三维立体波纹效果
代码语言: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 type="text/javascript" src="http://repo.bfw.wiki/bfwrepo/js/OrbitControls.min.js"></script> <script> function App() { const conf = { el: 'canvas', fov: 75, cameraZ: 100, background: 0xffffff }; let renderer, scene, camera, cameraCtrl; let width, height, cx, cy, wWidth, wHeight; const { randFloat: rnd, randFloatSpread: rndFS } = THREE.Math; let ripple; let gridWWidth, gridWHeight, 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() { renderer = new THREE.WebGLRenderer({ canvas: document.getElementById(conf.el), antialias: true }); // if (!renderer.extensions.get('OES_texture_float')) { // alert('no floating point texture support'); // return; // } camera = new THREE.PerspectiveCamera(conf.fov); camera.position.z = conf.cameraZ; updateSize(); window.addEventListener('resize', updateSize, false); gridWWidth = wWidth; gridWHeight = wHeight; gridWidth = gridWWidth * width / wWidth; gridHeight = gridWHeight * height / wHeight; ripple = new RippleEffect(renderer, gridWidth, gridHeight, 1 / 5); 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('mouseleave', e => {mouseOver = false;}); renderer.domElement.addEventListener('mousemove', e => { mouseOver = true; const gp = getGridMP(e); ripple.addDrop(gp.x, gp.y, 0.05, 0.1); }); renderer.domElement.addEventListener('mouseup', e => { const gp = getGridMP(e); ripple.addDrop(gp.x, gp.y, 0.1, -1.5); }); initScene(); animate(); } function initScene() { scene = new THREE.Scene(); if (conf.background) scene.background = new THREE.Color(conf.background); const material = new THREE.MeshBasicMaterial({ color: 0x0, side: THREE.DoubleSide, 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); transformed.z = 20. * info.r; `; shader.vertexShader = shader.vertexShader.replace(token, customTransform); } }); const pSize = 1; let nx = Math.round(gridWidth / 5),ny = Math.round(gridHeight / 50); let dy = gridWHeight / ny; for (let j = 0; j <= ny; j++) { const geometry = new THREE.PlaneBufferGeometry(gridWWidth, pSize, nx, 1); geometry.translate(0, -gridWHeight / 2 + j * dy, 0); const uvH = pSize / gridWHeight; const uvY = j / ny; const uvs = geometry.attributes.uv.array; for (let i = 0; i < uvs.length; i += 2) { uvs[i + 1] = uvs[i + 1] == 0 ? uvY - uvH : uvY + uvH; } scene.add(new THREE.Mesh(geometry, material)); } nx = Math.round(gridWidth / 50);ny = Math.round(gridHeight / 5); let dx = gridWWidth / nx; for (let i = 0; i <= nx; i++) { const geometry = new THREE.PlaneBufferGeometry(pSize, gridWHeight, 1, ny); geometry.translate(-gridWWidth / 2 + i * dx, 0, 0); const uvW = pSize / gridWWidth; const uvX = i / nx; const uvs = geometry.attributes.uv.array; for (let i = 0; i < uvs.length; i += 2) { uvs[i] = uvs[i] == 0 ? uvX - uvW : uvX + uvW; } scene.add(new THREE.Mesh(geometry, material)); } camera.position.set(0, -gridWHeight / 1.6, 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.4; const y = Math.sin(time) * 0.4; ripple.addDrop(x, y, 0.05, -0.05); } ripple.update(); renderer.render(scene, camera); requestAnimationFrame(animate); } function updateSize() { width = window.innerWidth;cx = width / 2; height = window.innerHeight;cy = height / 2; renderer.setSize(width, height); camera.aspect = width / height; camera.updateProjectionMatrix(); const wsize = getRendere.........完整代码请登录后点击上方下载按钮下载查看
网友评论1