three打造日出草坪小草摆动三维效果
代码语言:html
所属分类:三维
代码描述:three打造日出草坪小草摆动三维效果,可以360拖动
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <style> body { background-color: #fff; margin: 0; overflow: hidden; } .label { position: absolute; top: 0; left: 0; padding: 5px 15px; color: #fff; font-size: 13px; background-color: rgba(0, 0, 0, .15); } .instructions { position: absolute; bottom: 0%; left: 0; padding: 5px 15px; color: #fff; font-size: 13px; background-color: rgba(0, 0, 0, .15); } canvas { display: block; } </style> </head> <body translate="no"> <canvas id="canvas"></canvas> <div class="label"> Logo </div> <div class="instructions"> WASD/ARROW KEYS TO MOVE, MOUSE TO LOOK </div> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/three.109.js"></script> <script src="//repo.bfw.wiki/bfwrepo/js/OrbitControls.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/Stats-16.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/dat.gui-min.js"></script> <script> var canvas = document.getElementById("canvas"); const mobile = (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i) ); //Variables for blade mesh var joints = 4; var bladeWidth = 0.12; var bladeHeight = 1; //Patch side length var width = 120; //Number of vertices on ground plane side var resolution = 32; //Distance between two ground plane vertices var delta = width/resolution; //Radius of the sphere onto which the ground plane is bended var radius = 120; //User movement speed var speed = 1.5; //The global coordinates //The geometry never leaves a box of width*width around (0, 0) //But we track where in space the camera would be globally var pos = new THREE.Vector2(0, 0); //Number of blades var instances = 40000; if (mobile) { instances = 7000; width = 50; } //Sun //Height over horizon in range [0, PI/2.0] var elevation = 0.3; //Rotation around Y axis in range [0, 2*PI] var azimuth = 2.0; //Lighting variables for grass var ambientStrength = 0.6; var translucencyStrength = 1.4; var specularStrength = 0.5; var diffuseStrength = 2.2; var shininess = 256; var sunColour = new THREE.Vector3(1.0, 1.0, 1.0); var specularColour = new THREE.Vector3(1.0, 1.0, 1.0); //Camera rotate var rotate = false; //Initialise three.js. There are two scenes which are drawn after one another with clear() called manually at the start of each frame //Grass scene var scene = new THREE.Scene(); //Sky scene var backgroundScene = new THREE.Scene(); var renderer = new THREE.WebGLRenderer({ antialias: true, canvas: canvas }); renderer.outputEncoding = THREE.sRGBEncoding; renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); //Camera const FOV = 45; var camera = new THREE.PerspectiveCamera(FOV, window.innerWidth / window.innerHeight, 1, 20000); camera.position.set(-70, 0, -50); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); backgroundScene.add(camera); //Light for ground plane var ambientLight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(ambientLight); //OrbitControls.js for camera manipulation controls = new THREE.OrbitControls(camera, renderer.domElement); controls.autoRotate = rotate; controls.autoRotateSpeed = 1.0; controls.maxDistance = 65.0; if (mobile) { controls.maxDistance = 25.0; } controls.minDistance = 5.0; //Disable keys to stop arrow keys from moving the camera controls.enableKeys = false; controls.update(); const stats = new Stats(); stats.showPanel(0); stats.domElement.style.position = 'absolute'; stats.domElement.style.right = '0px'; stats.domElement.style.bottom = '0px'; document.body.appendChild(stats.domElement); //************* GUI *************** var gui = new dat.GUI(); gui.add(this, 'radius').min(85).max(1000).step(5); gui.add(this, 'speed').min(0.5).max(10).step(0.01); gui.add(this, 'elevation').min(0.0).max(Math.PI/2.0).step(0.01).listen().onChange(function(value) { updateSunPosition(); }); gui.add(this, 'azimuth').min(0.0).max(Math.PI*2.0).step(0.01).listen().onChange(function(value) { updateSunPosition(); }); gui.close(); window.addEventListener('resize', onWindowResize, false); function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); backgroundMaterial.uniforms.resolution.value = new THREE.Vector2(canvas.width, canvas.height); } //************** Sky ************** //https://discourse.threejs.org/t/how-do-i-use-my-own-custom-shader-as-a-scene-background/13598/2 const backgroundMaterial = new THREE.ShaderMaterial({ uniforms: { sunDirection: { type: 'vec3', value: new THREE.Vector3(Math.sin(azimuth), Math.sin(elevation), -Math.cos(azimuth))}, resolution: { type: 'vec2', value: new THREE.Vector2(canvas.width, canvas.height)} }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4( position, 1.0 ); } `, fragmentShader: ` varying vec2 vUv; uniform vec2 resolution; uniform vec3 sunDirection; const vec3 skyColour = 0.5 * vec3(0.09, 0.33, 0.81); //Darken sky when looking up vec3 getSkyColour(vec3 rayDir){ return mix(skyColour, 0.2*skyColour, rayDir.y); } //https://iquilezles.org/www/articles/fog/fog.htm vec3 applyFog(vec3 rgb, vec3 rayOri, vec3 rayDir, vec3 sunDir){ //Make horizon more hazy float dist = 4000.0; if(abs(rayDir.y) < 0.0001){rayDir.y = 0.0001;} //Rate of fade float b = 0.2; float fogAmount = pow(1.0-rayDir.y, 4.0);//1.0 * exp(-rayOri.y*b) * (1.0-exp(-dist*rayDir.y*b))/rayDir.y; float sunAmount = max( dot( rayDir, sunDir ), 0.0 ); vec3 fogColor = mix( vec3(0.5,0.6,0.7), vec3(1.0), pow(sunAmount, 16.0) ); return mix(rgb, fogColor, clamp(fogAmount, 0.0, 1.0)); } vec3 ACESFilm(vec3 x){ float a = 2.51; float b = 0.03; float c = 2.43; float d = 0.59; float e = 0.14; return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0); } vec3 rayDirection(float fieldOfView, vec2 fragCoord) { vec2 xy = fragCoord - resolution.xy / 2.0; float z = (0.5 * resolution.y) / tan(radians(fieldOfView) / 2.0); return normalize(vec3(xy, -z)); } //https://www.geertarien.com/blog/2017/07/30/breakdown-of-the-lookAt-function-in-OpenGL/ mat3 lookAt(vec3 camera, vec3 at, vec3 up){ vec3 zaxis = normalize(at-camera); vec3 xaxis = normalize(cross(zaxis, up)); vec3 yaxis = cross(xaxis, zaxis); return mat3(xaxis, yaxis, -zaxis); } float getGlow(float dist, float radius, float intensity){ dist = max(dist, 1e-6); return pow(radius/dist, intensity); } void main() { vec3 target = vec3(0.0, 0.0, 0.0); vec3 up = vec3(0.0, 1.0, 0.0); vec3 rayDir = rayDirection(45.0, gl_FragCoord.xy); //Get the view matrix from the camera orientation mat3 viewMatrix_ = lookAt(cameraPosition, target, up); //Transform the ray to point in the correct direction rayDir = viewMatrix_ * rayDir; vec3 sunDir = normalize(sunDirection); vec3 col = getSkyColour(rayDir); float mu = dot(sunDir, rayDir); //Draw sun col += getGlow(1.0-mu, 0.000015, 0.9); col += applyFog(col, vec3(0,1000,0), rayDir, sunDir); gl_FragColor = vec4(col, 1.0 ); } ` }); backgroundMaterial.depthWrite = false; var backgroundGeometry = new THREE.PlaneBufferGeometry(2, 2, 1, 1); var background = new THREE.Mesh(backgroundGeometry, backgroundMaterial); backgroundScene.add(background); renderer.autoClear = false; //************** Ground ************** //Ground material is a modification of the existing THREE.MeshPhongMaterial rather than one from scratch var groundBaseGeometry = new THREE.PlaneBufferGeometry(width, width, resolution, resolution); groundBaseGeometry.lookAt(new THREE.Vector3(0, 1, 0)); groundBaseGeometry.verticesNeedUpdate = true; var groundGeometry = new THREE.PlaneBufferGeometry(width, width, resolution, resolution); groundGeometry.addAttribute('basePosition', groundBaseGeometry.getAttribute("position")); groundGeometry.lookAt(new THREE.Vector3(0, 1, 0)); groundGeometry.verticesNeedUpdate = true; var groundMaterial = new THREE.MeshPhongMaterial({ color: 0x000300 }); var groundVertexPrefix = ` attribute vec3 basePosition; uniform float delta; uniform float posX; uniform float posZ; uniform float radius; uniform float width; float placeOnSphere(vec3 v){ float theta = acos(v.z/radius); float phi = acos(v.x/(radius * sin(theta))); float sV = radius * sin(theta) * sin(phi); //If undefined, set to default value if(sV != sV){ sV = v.y; } return sV; } vec3 norm; vec3 pos; //Get the position of the ground from the [x,z] coordinates, the sphere and the noise height field vec3 getPosition(vec3 pos, float epsX, float epsZ){ vec3 temp; temp.x = pos.x + epsX; temp.z = pos.z + epsZ; temp.y = max(0.0, placeOnSphere(temp)) - radius; //temp.y += getYPosition(vec2(basePosition.x+epsX+delta*floor(posX), basePosition.z+epsZ+delta*floor(posZ))); return temp; } //Find the normal at pos as the cross product of the central-differences in x and z directions vec3 getNormal(vec3 pos){ float eps = 1e-1; vec3 tempP = getPosition(pos, eps, 0.0); vec3 tempN = getPosition(pos, -eps, 0.0); vec3 slopeX = tempP - tempN; tempP = getPosition(pos, 0.0, eps); tempN = getPosition(pos, 0.0, -eps); vec3 slopeZ = tempP - tempN; vec3 norm = normalize(cross(slopeZ, slopeX)); return norm; } `; var groundShader; groundMaterial.onBeforeCompile = function (shader) { shader.uniforms.delta = { value: delta }; shader.uniforms.posX = { value: pos.x }; shader.uniforms.posZ = { value: pos.z }; shader.uniforms.radius = { value: radius }; shader.uniforms.width = { value: width }; shader.vertexShader = groundVertexPrefix + shader.vertexShader; shader.vertexShader = shader.vertexShader.replace( '#include <beginnormal_vertex>', `//https://dev.to/maurobringolf/a-neat-trick-to-compute-modulo-of-negative-numbers-111e pos.x = basePosition.x - mod(mod((delta*posX),delta) + delta, delta); pos.z = basePosition.z - mod(mod((delta*posZ),delta) + delta, delta); pos.y = max(0.0, placeOnSphere(pos)) - radius; //pos.y += 10.0*getYPosition(vec2(basePosition.x+delta*floor(posX), basePosition.z+delta*floor(posZ))); vec3 objectNormal = getNormal(pos); #ifdef USE_TANGENT vec3 objectTangent = vec3( tangent.xyz ); #endif` ); shader.vertexShader = shader.vertexShader.replace( '#include <begin_vertex>', `vec3 transformed = vec3(pos);` ); groundShader = shader; }; var ground = new THREE.Mesh(groundGeometry, groundMaterial); ground.geometry.computeVertexNormals(); scene.add(ground); //************** Grass ************** var grassVertexSource = ` precision mediump float; attribute vec3 position; attribute vec3 normal; attribute vec3 offset; attribute vec2 uv; attribute vec2 halfRootAngle; attribute float scale; attribute float index; uniform float time; uniform float delta; uniform float posX; uniform float posZ; uniform float radius; uniform float width; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; varying vec2 vUv; varying vec3 vNormal; varying vec3 vPosition; varying float frc; varying float idx; //https://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/ vec3 rotateVectorByQuaternion(vec3 v, vec4 q){ return 2.0 * cross(q.xyz, v * q.w + cross(q.xyz, v)) + v; } float placeOnSphere(vec3 v){ float theta = acos(v.z/radius); float phi = acos(v.x/(radius * sin(theta))); float sV = radius * sin(theta) * sin(phi); //If undefined, set to default value if(sV != sV){ sV = v.y; } return sV; } void main() { //Vertex height in blade geometry frc = position.y / float(` + bladeHeight + `); //Scale vertices vec3 vPosition = position; vPosition.y *= scale; //Invert scaling for normals vNormal = normal; vNormal.y /= scale; //Rotate blade around Y axis vec4 direction = vec4(0.0, halfRootAngle.x, 0.0, halfRootAngle.y); vPosition = rotateVectorByQuaternion(vPosition, direction); vNormal = rotateVectorByQuaternion(vNormal, direction); //UV for texture vUv = uv; vec3 pos; vec3 globalPos; vec3 tile; globalPos.x = offset.x-posX*delta; globalPos.z = offset.z-posZ*delta; tile.x = floor((globalPos.x + 0.5 * width) / width); tile.z = floor((globalPos.z + 0.5 * width) / width); pos.x = globalPos.x - tile.x * width; pos.z = globalPos.z - tile.z * width; pos.y = max(0.0, placeOnSphere(pos)) - radius; //pos.y += 10.0*getYPosition(pos.xz); //Wind is sine waves in time float noise = sin(0.1 * pos.x + time); float halfAngle = noise *.........完整代码请登录后点击上方下载按钮下载查看
网友评论0