Three.js 波浪效果教程
波浪效果 ·Water Effect· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么ShaderMaterial 自定义着色器实现核心视觉效果OrbitControls 相机轨道交互requestAnimationFrame渲染循环与resize自适应效果说明本案例演示波浪效果效果基于 WebGL 实现「波浪效果」可视化效果附完整可运行源码核心用到 ShaderMaterial、OrbitControls。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念Scene / Camera / WebGLRenderer构成最小渲染闭环大场景可开logarithmicDepthBuffer缓解 Z-fighting。ShaderMaterial通过uniforms 自定义 GLSL 控制逐像素/逐点效果透明粒子常配合depthTest: false。OrbitControls提供轨道旋转/缩放开启enableDamping后需在 animate 中controls.update()。实现步骤搭建 Scene、PerspectiveCamera、WebGLRenderer挂载 canvas 并处理resize定义 uniforms / onBeforeCompile 或 ShaderMaterial编写 GLSL 与材质参数创建 OrbitControls及 Raycaster 等交互控件若源码包含在requestAnimationFrame循环中更新状态并 renderCesium 为viewer.render或自动渲染代码要点import * as THREE from three;import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js import * as dat from dat.gui const gui new dat.GUI();const box document.getElementById(box);// 假设typeState已经被定义 const typeState { color: #0670c1, speed: 0.1, brightness: 1.5, flowSpeed: { x: 0.01, y: 0.01 }, };let vertexShader // Examples of variables passed from vertex to fragment shader varying vec2 vUv;void main(){ // To pass variables to the fragment shader, you assign them here in the // main function. Traditionally you name the varying with vAttributeName vUvuv; // This sets the position of the vertex in 3d space. The correct math is // provided below to take into account camera and object data. gl_PositionprojectionMatrixmodelViewMatrixvec4(position,1.); }; let fragmentShader #define TAU 6.28318530718 #define MAX_ITER 5uniform vec2 resolution; uniform vec3 backgroundColor; uniform vec3 color; uniform float speed; uniform vec2 flowSpeed; uniform float brightness; uniform float time;varying vec2 vUv;void main(){ vec2 uv(vUv.xy(timeflowSpeed))resolution; vec2 pmod(uv*TAU,TAU)-250.; vec2 ivec2(p); float c1.; float inten.005; for(int n0;n speed(1.-(3.5/float(n1))); ipvec2(cos(t-i.x)sin(ti.y),sin(t-i.y)cos(ti.x)); c1./length(vec2(p.x/(sin(i.xt)/inten),p.y/(cos(i.yt)/inten))); } c/float(MAX_ITER); c1.17-pow(c,brightness); vec3 rgbvec3(pow(abs(c),8.)); gl_FragColorvec4(rgb*colorbackgroundColor,length(rgb).1); };// 创建场景 const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 10000 ); camera.position.set(15, 15, 15);// 创建渲染器 const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(box.clientWidth, box.clientHeight); renderer.setClearColor(#201919); box.appendChild(renderer.domElement); // 添加环境光 const ambientLight new THREE.AmbientLight(0x0a0a0a0); scene.add(ambientLight);// 创建控制器 const controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true;// 创建平面几何体 const geometry new THREE.PlaneGeometry(10, 10);// 创建着色器材质 const material new THREE.ShaderMaterial({ uniforms: { resolution: { value: new THREE.Vector2(1, 1) }, backgroundColor: { value: new THREE.Color(#0670c1) }, color: { value: new THREE.Color(#fff) }, speed: { value: 0.1 }, flowSpeed: { value: new THREE.Vector2(0.01, 0.01) }, brightness: { value: 1.5 }, time: { value: 0.1 }, }, vertexShader: vertexShader, fragmentShader: fragmentShader, side: THREE.DoubleSide, transparent: true, depthWrite: false, depthTest: true, });// 创建网格 const mesh new THREE.Mesh(geometry, material); scene.add(mesh); // 设置网格的旋转注意Three.js中旋转的单位是弧度 mesh.rotation.x -Math.PI / 2; // 将x轴旋转-90度// 设置网格的位置这里设置y坐标为1 mesh.position.y 1;// 添加辅助网格 const gridHelper new THREE.GridHelper(10, 10); scene.add(gridHelper);// 渲染循环 function animate() { requestAnimationFrame(animate); controls.update(); // 更新时间 material.uniforms.time.value 0.1;renderer.render(scene, camera); } animate();// 创建颜色控制器 const colorController gui .addColor(typeState, color) .onChange((value) { console.log(颜色值改变为: ${value});material.uniforms.backgroundColor.value new THREE.Color(value); }) .name(颜色);// 创建速度控制器设置最小值、最大值和步长 const speedController gui .add(typeState, speed, 0.1, 1, 0.1) .onChange((value) { console.log(速度值改变为: ${value}); material.uniforms.speed.value value; }) .name(速度);// 创建亮度控制器设置最小值、最大值和步长 const brightnessController gui .add(typeState, brightness, 0.1, 2, 0.1) .onChange((value) { console.log(亮度值改变为: ${value}); material.uniforms.brightness.value value; }) .name(亮度);// 创建流动速度控制器dat.GUI不支持倒置的控制器因此需要手动处理 const flowSpeedFolder gui.addFolder(流动速度); const flowSpeedXController flowSpeedFolder .add(typeState.flowSpeed, x, 0.01, 0.6, 0.02) .onChange((value) { console.log(流动速度X值改变为: ${value}); material.uniforms.flowSpeed.value.x value; }); const flowSpeedYController flowSpeedFolder .add(typeState.flowSpeed, y, 0.01, 0.6, 0.02) .onChange((value) { console.log(流动速度Y值改变为: ${value}); material.uniforms.flowSpeed.value.y value; }); // 手动处理倒置逻辑 flowSpeedXController.__min 0.6; flowSpeedXController.__max 0.01; flowSpeedYController.__min 0.6; flowSpeedYController.__max 0.01;完整源码GitHub小结本文提供波浪效果完整 Three.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库