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 开源仓库
