Three.js 下雪教程 下雪 ·Snow· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么自定义 ShaderMaterial / 修改内置 shader相机交互控制器点云 / 粒子 / 实例化渲染requestAnimationFrame 渲染循环效果说明本案例演示下雪效果基于 WebGL 实现「下雪」可视化效果附完整可运行源码核心用到 onBeforeCompile、OrbitControls、THREE.Points。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念ShaderMaterial完全自定义 GLSLonBeforeCompile可在内置材质 shader 中注入代码。关注uniforms与 rAF 更新。OrbitControls轨道旋转缩放开enableDamping时每帧需controls.update()。Points大量顶点用点精灵渲染InstancedMesh相同几何体批量绘制降低 draw call。实现步骤搭建 Scene / Camera / Renderer 与 OrbitControls定义材质/shader 与 uniformsrAF 中更新rAF 循环中 update 并 render代码要点import * as THREE from three;import { OrbitControls } from three/addons/controls/OrbitControls.js; let renderer, scene, camera, stats, controls;let mesh, uniforms, geometry; let snowMaterial; const particles 1000;init(); animate();function init() { camera new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );scene new THREE.Scene();snowMaterial new THREE.PointsMaterial({ size: 5, blending: THREE.AdditiveBlending, transparent: true, });geometry new THREE.BufferGeometry();let positions new Float32Array(particles * 3);for (let i 0; i particles * 3; i 3) { positions[i] Math.random() * 200 - 100; positions[i 1] Math.random() * 200 - 100; positions[i 2] Math.random() * 200 - 100; } geometry.setAttribute( position, new THREE.Float32BufferAttribute(positions, 3) );snowMaterial.onBeforeCompile (shader) { shader.uniforms.uColor { value: new THREE.Color(0xffffff), };shader.fragmentShader shader.fragmentShader.replace(#include,#include uniform vec3 uColor;);shader.fragmentShader shader.fragmentShader.replace(#include,#include float distanceLen distance(gl_PointCoord,vec2(0.5)); distanceLen 1.0 - distanceLen; distanceLen pow(distanceLen,10.0); vec4 color vec4(uColor,distanceLen); // if(color.a0.1) // discard; gl_FragColor color;); };mesh new THREE.Points(geometry, snowMaterial); scene.add(mesh);renderer new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight);controls new OrbitControls(camera, renderer.domElement);const container document.getElementById(box); container.appendChild(renderer.domElement);window.addEventListener(resize, onWindowResize); }function onWindowResize() { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight); }function animate() { requestAnimationFrame(animate);render(); controls.update(); }function update(time, position) { if (snowMaterial) { const positions mesh.geometry.getAttribute(position).array; for (let i 0; i positions.length; i 3) { positions[i 1] - 0.1; positions[i] - Math.sin(i) * 0.1; positions[i 2] - Math.sin(i) * 0.1; if (positions[i 1] -100) { positions[i 1] 100; } }mesh.geometry.getAttribute(position).needsUpdate true; } }function render() { const time Date.now() * 0.005; update(); // mesh.rotation.z 0.01 * time;renderer.render(scene, camera); }完整源码GitHub小结本文提供下雪完整 Three.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库