Three.js 蘑菇教程

📅 2026/7/7 10:59:00 👁️ 阅读次数 📝 编程学习
Three.js 蘑菇教程

蘑菇 ·Mushroom· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • 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循环中更新状态并 render(Cesium 为viewer.render或自动渲染)
  • 代码要点

    import * as THREE from "three";

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

    const DOM = document.getElementById('box')

    const scene = new THREE.Scene()

    const camera = new THREE.PerspectiveCamera(50, DOM.clientWidth / DOM.clientHeight, 0.1, 100000) camera.position.set(10, 10, 10) scene.add(camera);

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true }) renderer.setSize(DOM.clientWidth, DOM.clientHeight) renderer.setPixelRatio(window.devicePixelRatio * 2) renderer.setClearColor(0x000000) DOM.appendChild(renderer.domElement) new OrbitControls(camera, renderer.domElement)

    const uniforms = { Mouse: { type: 'v2', value: new THREE.Vector2(0, 0) }, Resolution: { type: 'v2', value: new THREE.Vector2(window.innerWidth, window.innerHeight) }, Time: { type: 'f', value: 1.0 } }

    DOM.addEventListener('mousemove', (event) => uniforms.Mouse.value = new THREE.Vector2( (event.offsetX / event.target.clientWidth) * 2 - 1, -(event.offsetY / event.target.clientHeight) * 2 + 1 )) const geometry = new THREE.BoxGeometry(10, 10, 10);

    var material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader:varying vec2 vUv; void main(){ gl_Position=projectionMatrixmodelViewMatrixvec4(position,1.); vUv=uv; }, fragmentShader:#ifdef GL_ES precision mediump float; #endif uniform vec2 Resolution; uniform vec3 Mouse; uniform float Time; varying vec2 vUv; mat2 rot2D(float angle){ float s=sin(angle); float c=cos(angle); return mat2(c,-s,s,c); } float sdCutHollowSphere(vec3 p,float r,float h,float t) { float w=sqrt(rr-hh); vec2 q=vec2(length(p.xz),p.y); return((hq.xq.y)?length(q-vec2(w,h)): abs(length(q)-r))-t; } vec4 sdstripe(vec3 p,vec3 color){ p.xz=abs(p.xz); float d1=sdCutHollowSphere(p-vec3(.0,-3.3,0.),.8,.01,.01); float d2=sdCutHollowSphere(p-vec3(.9,-3.3,.9),.5,.005,.01); float d=min(d1,d2); return vec4(d,color); } vec4 sdCutSphere(vec3 p,float r,float h,vec3 color) { float w=sqrt(rr-hh); vec2 q=vec2(length(p.xz),p.y); float s=max((h-r)q.xq.x+ww(h+r-2.q.y),hq.x-w*q.y); float d=(s<0.)?length(q)-r: (q.x pabababa); float cax=max(0.,x-((paba<.5)?ra:rb)); float cay=abs(paba-.5)-.5; float k=rba*rba+baba; float f=clamp((rba(x-ra)+pabababa)/k,0.,1.); float cbx=x-ra-f*rba; float cby=paba-f; float s=(cbx<0.&&cay<0.)?-1.:1.; return vec4(ssqrt(min(caxcax+caycaybaba, cbxcbx+cbycby*baba)),color); } float smin(float d1,float d2,float k){ float h=clamp(.5+.5*(d2-d1)/k,0.,1.); return mix(d2,d1,h)-kh(1.-h); } vec4 colorMin(vec4 a,vec4 b){ if(a.x 100.||d.x<.001){ break; } color=vec4(td.yzw.13,1.); } gl_FragColor=color; }, uniforms });

    material.side = THREE.DoubleSide

    var mesh = new THREE.Mesh(geometry, material); mesh.scale.set(1, -1, 1) scene.add(mesh);

    render() function render() { uniforms.Time.value += 0.005; renderer.render(scene, camera) requestAnimationFrame(render) }

    完整源码:GitHub

    小结

    • 本文提供蘑菇完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库