三维液体网格波动效果
代码语言:html
所属分类:三维
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <style> html, body { margin: 0; } canvas { display: block; } </style> </head> <body translate="no"> <canvas id="canvas"></canvas> <script type="text/javascript" src="http://repo.bfw.wiki/bfwrepo/js/three.109.js"></script> <script src='http://repo.bfw.wiki/bfwrepo/js/OrbitControls.js'></script> <script > function App() { const conf = { el: 'canvas', fov: 75, cameraZ: 100 }; let renderer, scene, camera, cameraCtrl; let width, height, cx, cy, wWidth, wHeight; let ripple; let gridWWidth, gridWHeight; let gridWidth, gridHeight; const mouse = new THREE.Vector2(); const mousePlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); const mousePosition = new THREE.Vector3(); const raycaster = new THREE.Raycaster(); let mouseOver = false; init(); function init() { // const gl = renderer.getContext(); // const floatTextures = gl.getExtension('OES_texture_float'); // if (!floatTextures) { // alert('no floating point texture support'); // return; // } renderer = new THREE.WebGLRenderer({ canvas: document.getElementById(conf.el), antialias: true }); camera = new THREE.PerspectiveCamera(conf.fov); camera.position.z = conf.cameraZ; updateSize(); window.addEventListener('resize', updateSize, false); // gridWHeight = wHeight - 20; // gridWWidth = gridWHeight; gridWHeight = wHeight; gridWWidth = wWidth; gridWidth = gridWWidth * width / wWidth; gridHeight = gridWHeight * height / wHeight; ripple = new RippleEffect(renderer, width, height); const getGridMP = function (e) { const v = new THREE.Vector3(); camera.getWorldDirection(v); v.normalize(); mouse.x = e.clientX / width * 2 - 1; mouse.y = -(e.clientY / height) * 2 + 1; raycaster.setFromCamera(mouse, camera); raycaster.ray.intersectPlane(mousePlane, mousePosition); return { x: 2 * mousePosition.x / gridWWidth, y: 2 * mousePosition.y / gridWHeight }; }; renderer.domElement.addEventListener('mousemove', e => { mouseOver = true; const gp = getGridMP(e); ripple.addDrop(gp.x, gp.y, 0.05, 0.1); }); renderer.domElement.addEventListener('mouseleave', e => {mouseOver = false;}); // renderer.domElement.addEventListener('mouseup', e => { // const gp = getGridMP(e); // ripple.addDrop(gp.x, gp.y, 0.2, -3.0); // }); initScene(); animate(); } function initScene() { scene = new THREE.Scene(); let pointLight1 = new THREE.PointLight(0xFFFF80); pointLight1.position.set(-wWidth / 2, wHeight / 2, 50); scene.add(pointLight1); let pointLight2 = new THREE.PointLight(0xde3578); pointLight2.position.set(wWidth / 2, wHeight / 2, 50); scene.add(pointLight2); let pointLight3 = new THREE.PointLight(0xFF4040); pointLight3.position.set(-wWidth / 2, -wHeight / 2, 50); scene.add(pointLight3); let pointLight4 = new THREE.PointLight(0x0247e5); pointLight4.position.set(wWidth / 2, -wHeight / 2, 50); scene.add(pointLight4); renderer.domElement.addEventListener('mouseup', e => { pointLight1.color = new THREE.Color(chroma.random().hex()); pointLight2.color = new THREE.Color(chroma.random().hex()); pointLight3.color = new THREE.Color(chroma.random().hex()); pointLight4.color = new THREE.Color(chroma.random().hex()); }); const material = new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.DoubleSide, metalness: 0.5, roughness: 0.5, onBeforeCompile: shader => { shader.uniforms.hmap = { value: ripple.hMap.texture }; shader.vertexShader = "uniform sampler2D hmap;\n" + shader.vertexShader; const token = '#include <begin_vertex>'; const customTransform = ` vec3 transformed = vec3(position); vec4 info = texture2D(hmap, uv); vNormal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a).xzy; transformed.z = 20. * info.r; `; shader.vertexShader = shader.vertexShader.replace(token, customTransform); } }); let nx = Math.round(gridWidth / 5),ny = Math.round(gridHeight / 40); let dx = gridWWidth / nx,dy = gridWHeight / ny; for (let j = 0; j <= ny; j++) { const geometry = new THREE.BufferGeometry(); const positions = [],uvs = []; const y = -gridWHeight / 2 + j * dy; for (let i = 0; i <= nx; i++) { positions.push(-gridWWidth / 2 + i * dx, y, 0); uvs.push(i / nx, j / ny); } geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)); geometry.computeBoundingSphere(); scene.add(new THREE.Line(geometry, material)); } nx = Math.round(gridWidth / 40);ny = Math.round(gridHeight / 5); dx = gridWWidth / nx;dy = gridWHeight / ny; for (let i = 0; i <= nx; i++) { const geometry = new THREE.BufferGeometry(); const positions = [],uvs = []; const x = -gridWWidth / 2 + i * dx; for (let j = 0; j <= ny; j++) { positions.push(x, -gridWHeight / 2 + j * dy, 0); uvs.push(i / nx, j / ny); } geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)); geometry.computeBoundingSphere(); scene.add(new THREE.Line(geometry, material)); } camera.position.set(0, -gridWHeight / 2, 40); camera.lookAt(new THREE.Vector3(0, -gridWHeight / 6, 0)); cameraCtrl = new THREE.OrbitControls(camera, renderer.domElement); cameraCtrl.enableDamping = true; cameraCtrl.dampingFactor = 0.1; cameraCtrl.rotateSpeed = 0.5; } function animate() { if (!mouseOver) { const time = Date.now() * 0.001; const x = Math.cos(time) * 0.2; const y = Math.sin(time) * 0.2; ripple.addDrop(x, y, 0.05, -0.04); } ripple.update(); renderer.render(scene, camera); requestAnimationFrame(animate); } function updateSize() { width = window.innerWidth;cx = width / 2; height = window.innerHeight;cy = height.........完整代码请登录后点击上方下载按钮下载查看
网友评论0