Three.js 下雨效果教程

发布时间:2026/6/30 16:14:43

Three.js 下雨效果教程 下雨效果 ·Rain Roof· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么onBeforeCompile 注入 GLSL 改造内置材质OrbitControls 相机轨道交互BufferGeometry 自定义顶点/索引数据监听窗口resize同步更新 camera 与 renderer效果说明本案例演示下雨效果效果基于 WebGL 实现「下雨效果」可视化效果附完整可运行源码核心用到 onBeforeCompile、OrbitControls、BufferGeometry。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念Scene / Camera / WebGLRenderer构成最小渲染闭环大场景可开logarithmicDepthBuffer缓解 Z-fighting。onBeforeCompile在 Three 拼好内置 shader 后替换#include片段适合在 PBR 材质上叠加大屏特效。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/addons/controls/OrbitControls.js;class DepthData extends THREE.WebGLRenderTarget{ constructor(size, camParams){ super(size, size); this.texture.minFilter THREE.NearestFilter; this.texture.magFilter THREE.NearestFilter; this.stencilBuffer false; this.depthTexture new THREE.DepthTexture(); this.depthTexture.format THREE.DepthFormat; this.depthTexture.type THREE.UnsignedIntType; let hw camParams.width * 0.5; let hh camParams.height * 0.5; let d camParams.depth; this.depthCam new THREE.OrthographicCamera(-hw, hw, hh, -hh, 0, d); this.depthCam.layers.set(1); this.depthCam.position.set(0, d, 0); this.depthCam.lookAt(0, 0, 0); } update(){ renderer.setRenderTarget(this); renderer.render(scene, this.depthCam); renderer.setRenderTarget(null); } }class Rain extends THREE.Line{ constructor(size, amount){ let v new THREE.Vector3(); let gBase new THREE.BufferGeometry().setFromPoints([new THREE.Vector2(0, 0), new THREE.Vector2(0, 1)]) let g new THREE.InstancedBufferGeometry().copy(gBase) g.setAttribute(instPos, new THREE.InstancedBufferAttribute( new Float32Array( Array.from({length: amount}, () { v.random().subScalar(0.5); v.y 0.5; v.multiply(size); return [...v]; }).flat() ), 3 )) g.instanceCount amount; let m new THREE.LineBasicMaterial({ color: 0x4488ff, transparent: true, onBeforeCompile: shader { shader.uniforms.depthData gu.depthData; shader.uniforms.time gu.time; shader.vertexShader uniform float time; attribute vec3 instPos; varying float colorTransition; varying vec3 vPos; ${shader.vertexShader}.replace(#include,#include float t time; vec3 iPos instPos; iPos.y mod(20. - instPos.y - t * 5., 20.); transformed.y * 0.5; transformed iPos; vPos transformed; colorTransition position.y;); //console.log(shader.vertexShader); shader.fragmentShader uniform sampler2D depthData; varying float colorTransition; varying vec3 vPos; ${shader.fragmentShader}.replace(vec4 diffuseColor vec4( diffuse, opacity );,vec2 depthUV (vPos.xz 10.) / 20.; depthUV.y 1. - depthUV.y; float depthVal 1. - texture(depthData, depthUV).r; float actualDepth depthVal * 20.; if(vPos.y actualDepth) discard; float trns 1. - colorTransition; float distVal smoothstep(3., 0., vPos.y - actualDepth); vec3 col mix(diffuse, vec3(0.9), distVal); // the closer, the whiter vec4 diffuseColor vec4( mix(col, col 0.1, pow(trns, 16.)), (opacity(0.25 0.75distVal)) * trns );); //console.log(shader.fragmentShader); } }) super(g, m); this.frustumCulled false; } }let scene new THREE.Scene(); let camera new THREE.PerspectiveCamera(30, innerWidth / innerHeight, 1, 1000); camera.position.set(3, 5, 13).setLength(50); let renderer new THREE.WebGLRenderer({antialias: true}); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement);window.addEventListener(resize, event { camera.aspect innerWidth / innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth, innerHeight); })let camShift new THREE.Vector3(0, 7, 0); camera.position.add(camShift); let controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true; controls.target.copy(camShift);let light new THREE.DirectionalLight(0xffffff, Math.PI); light.position.setScalar(1); scene.add(light, new THREE.AmbientLight(0xffffff, Math.PI * 0.5));let maxHeight 20; let depthData new DepthData(1024, {width: 20, height: 20, depth: maxHeight});let gu { time: {value: 0}, depthData: {value: depthData.depthTexture} }let lawn new THREE.Mesh( new THREE.PlaneGeometry(20, 20).rotateX(-Math.PI * 0.5), new THREE.MeshLambertMaterial({ map: new THREE.TextureLoader().load(FILE_HOST images/texture/g1.png), //map: gu.depthData.value }) ) lawn.layers.enable(1); scene.add(lawn);let tent new THREE.Mesh( new THREE.PlaneGeometry(10, 10).rotateX(-Math.PI * 0.65).translate(0, 10, 0), new THREE.MeshLambertMaterial({ map: new THREE.TextureLoader().load(FILE_HOST images/texture/g1.png), }) ) tent.layers.enable(1); tent.position.set(-2, 2, 0); tent.rotation.y Math.PI * 0.25; scene.add(tent);let rain new Rain(new THREE.Vector3(20, 20, 20), 50000); scene.add(rain);let clock new THREE.Clock(); let t 0;renderer.setAnimationLoop(() { let dt clock.getDelta(); t dt; gu.time.value t; controls.update(); tent.position.x Math.sin(t0.2)7; depthData.update(); renderer.render(scene, camera); })完整源码GitHub小结本文提供下雨效果完整 Three.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库

相关新闻