Three.js 管道表面运动教程
管道表面运动 ·Flow Tube· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么自定义 ShaderMaterial / 修改内置 shader相机交互控制器requestAnimationFrame 渲染循环Clock 帧间隔计时效果说明本案例演示管道表面运动效果基于 WebGL 实现「管道表面运动」可视化效果附完整可运行源码核心用到 onBeforeCompile、OrbitControls、CatmullRomCurve3。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念ShaderMaterial完全自定义 GLSLonBeforeCompile可在内置材质 shader 中注入代码。关注uniforms与 rAF 更新。OrbitControls轨道旋转缩放开enableDamping时每帧需controls.update()。实现步骤搭建 Scene / Camera / Renderer 与 OrbitControls定义材质/shader 与 uniformsrAF 中更新rAF 循环中 update 并 render代码要点import * as THREE from three;import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; const box document.getElementById(box);const scene new THREE.Scene();const camera new THREE.PerspectiveCamera( 75, box.clientWidth / box.clientHeight, 0.1, 1000 );camera.position.set(30, 10, 10)const renderer new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true, });renderer.setSize(box.clientWidth, box.clientHeight); box.appendChild(renderer.domElement);new OrbitControls(camera, renderer.domElement);window.onresize () { renderer.setSize(box.clientWidth, box.clientHeight);camera.aspect box.clientWidth / box.clientHeight; camera.updateProjectionMatrix(); };animate();function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); }scene.add(new THREE.AmbientLight(0xffffff, 1)); scene.add(new THREE.DirectionalLight(0xffffff, 0.25));function create_pipe() { const cps Array.from({ length: 6 }).fill(0).map((_, idx, arr) { let init -(arr.length - 1) return new THREE.Vector3( init idx * 2, Math.random() 0.5 ? -1 : 1, -init - idx * 2 ) }) const curve new THREE.CatmullRomCurve3(cps) let g new THREE.TubeGeometry(curve, 100, 0.5, 32) const m new THREE.MeshLambertMaterial({ color: 0xface8d, side: THREE.DoubleSide,}) let length curve.getLength() let uniforms { totalLength: { value: length }, pipeFittingAt: { value: 2 }, pipeFittingWidth: { value: 2 }, pipeFittingColor: { value: new THREE.Color(0xff2200) } };m.onBeforeCompile shader { shader.uniforms.totalLength uniforms.totalLength; shader.uniforms.pipeFittingAt uniforms.pipeFittingAt; shader.uniforms.pipeFittingWidth uniforms.pipeFittingWidth; shader.uniforms.pipeFittingColor uniforms.pipeFittingColor; shader.fragmentShader #define S(a, b, c) smoothstep(a, b, c) uniform float totalLength; uniform float pipeFittingAt; uniform float pipeFittingWidth; uniform vec3 pipeFittingColor; ${shader.fragmentShader}.replace(#include,#include float normAt pipeFittingAt / totalLength; float normWidth pipeFittingWidth / totalLength; float hWidth normWidth * 0.5; float fw fwidth(vUv.x); float f S(hWidth fw, hWidth, abs(vUv.x - normAt)); diffuseColor.rgb mix(diffuseColor.rgb, pipeFittingColor, f); // diffuseColor.rgb mix(diffuseColor.rgb, vec3(1, 1, 0), S(fw, 0., abs(vUv.x - normAt)));) } m.defines { USE_UV: } let o new THREE.Mesh(g, m); scene.add(o); let clock new THREE.Clock() function animation() { uniforms.pipeFittingAt.value clock.getDelta() * 5 if (uniforms.pipeFittingAt.value - 1 uniforms.totalLength.value) { uniforms.pipeFittingAt.value 0 } requestAnimationFrame(animation) } animation() }create_pipe()完整源码GitHub小结本文提供管道表面运动完整 Three.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库