Three.js 波涛海浪教程
波涛海浪 ·move Sea· ▶ 在线运行案例案例合集三维可视化功能案例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;// refer https://codepen.io/aderaaij/pen/XWpMONO const vertexShader #includeuniform float uTime;uniform float uBigWavesElevation; uniform vec2 uBigWavesFrequency; uniform float uBigWaveSpeed;uniform float uSmallWavesElevation; uniform float uSmallWavesFrequency; uniform float uSmallWavesSpeed; uniform float uSmallWavesIterations;varying float vElevation;// Classic Perlin 3D Noise // by Stefan Gustavson // vec4 permute(vec4 x){return mod(((x34.0)1.0)x, 289.0);} vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} vec3 fade(vec3 t) {return ttt(t(t*6.0-15.0)10.0);}float cnoise(vec3 P){ vec3 Pi0 floor(P); // Integer part for indexing vec3 Pi1 Pi0 vec3(1.0); // Integer part 1 Pi0 mod(Pi0, 289.0); Pi1 mod(Pi1, 289.0); vec3 Pf0 fract(P); // Fractional part for interpolation vec3 Pf1 Pf0 - vec3(1.0); // Fractional part - 1.0 vec4 ix vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec4 iy vec4(Pi0.yy, Pi1.yy); vec4 iz0 Pi0.zzzz; vec4 iz1 Pi1.zzzz;vec4 ixy permute(permute(ix) iy); vec4 ixy0 permute(ixy iz0); vec4 ixy1 permute(ixy iz1);vec4 gx0 ixy0 / 7.0; vec4 gy0 fract(floor(gx0) / 7.0) - 0.5; gx0 fract(gx0); vec4 gz0 vec4(0.5) - abs(gx0) - abs(gy0); vec4 sz0 step(gz0, vec4(0.0)); gx0 - sz0 * (step(0.0, gx0) - 0.5); gy0 - sz0 * (step(0.0, gy0) - 0.5);vec4 gx1 ixy1 / 7.0; vec4 gy1 fract(floor(gx1) / 7.0) - 0.5; gx1 fract(gx1); vec4 gz1 vec4(0.5) - abs(gx1) - abs(gy1); vec4 sz1 step(gz1, vec4(0.0)); gx1 - sz1 * (step(0.0, gx1) - 0.5); gy1 - sz1 * (step(0.0, gy1) - 0.5);vec3 g000 vec3(gx0.x,gy0.x,gz0.x); vec3 g100 vec3(gx0.y,gy0.y,gz0.y); vec3 g010 vec3(gx0.z,gy0.z,gz0.z); vec3 g110 vec3(gx0.w,gy0.w,gz0.w); vec3 g001 vec3(gx1.x,gy1.x,gz1.x); vec3 g101 vec3(gx1.y,gy1.y,gz1.y); vec3 g011 vec3(gx1.z,gy1.z,gz1.z); vec3 g111 vec3(gx1.w,gy1.w,gz1.w);vec4 norm0 taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); g000 * norm0.x; g010 * norm0.y; g100 * norm0.z; g110 * norm0.w; vec4 norm1 taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); g001 * norm1.x; g011 * norm1.y; g101 * norm1.z; g111 * norm1.w;float n000 dot(g000, Pf0); float n100 dot(g100, vec3(Pf1.x, Pf0.yz)); float n010 dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); float n110 dot(g110, vec3(Pf1.xy, Pf0.z)); float n001 dot(g001, vec3(Pf0.xy, Pf1.z)); float n101 dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); float n011 dot(g011, vec3(Pf0.x, Pf1.yz)); float n111 dot(g111, Pf1);vec3 fade_xyz fade(Pf0); vec4 n_z mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); vec2 n_yz mix(n_z.xy, n_z.zw, fade_xyz.y); float n_xyz mix(n_yz.x, n_yz.y, fade_xyz.x); return 2.2 * n_xyz; }void main() { #include #include #include vec4 modelPosition modelMatrix * vec4(position, 1.0); float elevation sin(modelPosition.xuBigWavesFrequency.x uTimeuBigWaveSpeed)sin(modelPosition.zuBigWavesFrequency.y uTime * uBigWaveSpeed)uBigWavesElevation;for(float i 1.0; i 10.0; i) { elevation - abs( cnoise( vec3(modelPosition.xzuSmallWavesFrequencyi, uTime * uSmallWavesSpeed) )uSmallWavesElevation / i); if(i uSmallWavesIterations ) { break; } } modelPosition.y elevation; vec4 viewPosition viewMatrix * modelPosition; vec4 projectedPosition projectionMatrix * viewPosition; gl_Position projectedPosition;vElevation elevation; }const fragmentShader #include precision mediump float; uniform vec3 uDepthColor; uniform vec3 uSurfaceColor;uniform float uColorOffset; uniform float uColorMultiplier;varying float vElevation;void main() { float mixStrength (vElevation uColorOffset) * uColorMultiplier; vec3 color mix(uDepthColor, uSurfaceColor, mixStrength); gl_FragColor vec4(color, 1.0); #include }const gui new dat.GUI({ closed: false, width: 340 }); const bigWavesFolder gui.addFolder(Large Waves); const smallWavesFolder gui.addFolder(Small Waves); const colorFolder gui.addFolder(Colors); const debugObject { waveDepthColor: #b5e4e4, waveSurfaceColor: #4d9aaa, fogNear: 1, fogFar: 8, fogColor: #8e99a2 };const scene new THREE.Scene(); scene.fog new THREE.Fog( debugObject.fogColor, debugObject.fogNear, debugObject.fogFar ); scene.background new THREE.Color(debugObject.fogColor); const waterGeometry new THREE.PlaneGeometry(12, 12, 512, 512); const waterMaterial new THREE.ShaderMaterial({ vertexShader, fragmentShader, transparent: true, fog: true, uniforms: { uTime: { value: 0 }, uMouse: { value: new THREE.Vector2() }, uBigWavesElevation: { value: 0.2 }, uBigWavesFrequency: { value: new THREE.Vector2(4, 2) }, uBigWaveSpeed: { value: 0.75 }, uSmallWavesElevation: { value: 0.15 }, uSmallWavesFrequency: { value: 3 }, uSmallWavesSpeed: { value: 0.2 }, uSmallWavesIterations: { value: 4 }, uDepthColor: { value: new THREE.Color(debugObject.waveDepthColor) }, uSurfaceColor: { value: new THREE.Color(debugObject.waveSurfaceColor) }, uColorOffset: { value: 0.08 }, uColorMultiplier: { value: 5 }, ...THREE.UniformsLib[fog] } });const water new THREE.Mesh(waterGeometry, waterMaterial); water.rotation.x -Math.PI * 0.5; scene.add(water);const sizes { width: window.innerWidth, height: window.innerHeight };window.addEventListener(resize, () { sizes.width window.innerWidth; sizes.height window.innerHeight; camera.aspect sizes.width / sizes.height; camera.updateProjectionMatrix() renderer.setSize(sizes.width, sizes.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); });const camera new THREE.PerspectiveCamera( 75, sizes.width / sizes.height, 0.1, 100 ); camera.position.set(1, 1, 1); scene.add(camera);const renderer new THREE.WebGLRenderer(); renderer.setSize(sizes.width, sizes.height); renderer.outputColorSpace THREE.SRGBColorSpace; document.body.appendChild(renderer.domElement);const controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true;bigWavesFolder .add(waterMaterial.uniforms.uBigWavesElevation, value) .min(0) .max(1) .step(0.001) .name(Elevation); bigWavesFolder .add(waterMaterial.uniforms.uBigWavesFrequency.value, x) .min(0) .max(10) .step(0.001) .name(Frequency X); bigWavesFolder .add(waterMaterial.uniforms.uBigWavesFrequency.value, y) .min(0) .max(10) .step(0.001) .name(Frequency Y); bigWavesFolder .add(waterMaterial.uniforms.uBigWaveSpeed, value) .min(0.25) .max(5) .step(0.001) .name(Speed);// Small Waves smallWavesFolder .add(waterMaterial.uniforms.uSmallWavesElevation, value) .min(0.0) .max(0.3) .step(0.001) .name(Elevation); smallWavesFolder .add(waterMaterial.uniforms.uSmallWavesFrequency, value) .min(0) .max(30) .step(0.001) .name(Frequency); smallWavesFolder .add(waterMaterial.uniforms.uSmallWavesSpeed, value) .min(0.0) .max(1) .step(0.001) .name(Speed); smallWavesFolder .add(waterMaterial.uniforms.uSmallWavesIterations, value) .min(0) .max(10) .step(1) .name(Iterations);// Colors colorFolder .add(waterMaterial.uniforms.uColorOffset, value) .min(0) .max(0.15) .step(0.0001) .name(Color Offset); colorFolder .add(waterMaterial.uniforms.uColorMultiplier, value) .min(0.0) .max(10.0) .step(0.001) .name(Color multiplier); colorFolder .addColor(debugObject, waveDepthColor) .name(Wave depth color) .onChange(() { waterMaterial.uniforms.uDepthColor.value.set(debugObject.waveDepthColor); }); colorFolder .addColor(debugObject, waveSurfaceColor) .name(Wave surface color) .onChange(() { waterMaterial.uniforms.uSurfaceColor.value.set( debugObject.waveSurfaceColor ); }); colorFolder .addColor(debugObject, fogColor) .name(Fog Color) .onChange(() { waterMaterial.uniforms.fogColor.value.set(debugObject.fogColor); scene.background.set(debugObject.fogColor); scene.fog new THREE.Fog( debugObject.fogColor, debugObject.fogNear, debugObject.fogFar ); });/**Animate*/ const clock new THREE.Clock();const tick () { const elapsedTime clock.getElapsedTime(); controls.update(); waterMaterial.uniforms.uTime.value elapsedTime; renderer.render(scene, camera); window.requestAnimationFrame(tick); };tick();完整源码GitHub小结本文提供波涛海浪完整 Three.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库