WebGPU 体积树冠光线步进实验

原作者及原始链接
- 原作者:aengel(实验室地址:https://lab.aengel.io/ )
- 原始链接:https://lab.aengel.io/webgpu-raymarching-canopy
- 展示页面:https://mesh3d.gallery/experiment/magical-canopy

项目概述
Magical Canopy 是一个完全基于 Three.js TSL(Three.js Shading Language) 在 WebGPU 环境下实现体积树冠光线步进(volumetric tree canopy raymarching)的实验性 Web3D 作品。层层叠叠的树叶在风中轻轻摇曳,配合柔和阴影(soft shadows)与雾气(fog)效果,营造出梦幻的森林氛围。整个场景会响应鼠标指针的移动,产生动态变化的辉光(glow),使观者仿佛置身于魔法树冠之下。

核心技术解析
该实验的核心亮点在于完全摒弃传统几何体建模,转而使用光线步进(raymarching) 技术在片元着色器(或计算着色器)中逐像素地计算体积密度,从而渲染出具有空间层次感的树冠。所有着色逻辑均通过 Three.js TSL 节点化语言编写,而非直接手写 GLSL/WGSL,这大幅提高了代码的可读性与可维护性,同时能够无缝切换到不同的图形后端(WebGPU 或 WebGL2)。

3 个核心优化要点
1. 利用 TSL 节点化着色器构建,提升开发效率与跨后端兼容性
优化点:使用 Three.js TSL 替代手写 GLSL/WGSL,将复杂的光线步进逻辑抽象为可复用的节点图。这不仅避免了手动管理不同着色语言(WGSL 与 GLSL 语法差异)的负担,还允许在 WebGPU 与 WebGL 之间灵活切换渲染后端,确保更广泛的设备覆盖。
2. 以 raymarching 体积渲染替代几何体,大幅降低顶点压力
优化点:传统树冠若使用大量叶片网格(mesh)将带来高昂的顶点着色与光栅化开销。本实验通过体积光线步进直接在屏幕空间累加密度场,仅需一个全屏四边形(或少量代理几何体),就可以生成具有丰富内部结构的树冠效果。这样把计算压力从顶点处理转移到片元着色,更适合现代 GPU 的并行架构,同时有效控制 Draw Call 数量。
3. 软阴影与雾效的深度融合,以低成本增强视觉层次与交互反馈
优化点:软阴影并非通过多次采样高成本阴影贴图实现,而是在光线步进过程中基于体积密度累计遮挡信息,天然产生柔和过渡。雾气与辉光则作为后处理或步进终结条件的一部分,与指针交互参数联动,仅需在每一帧更新少量 uniform 变量即可实现场景对用户的动态响应,无需额外的几何体或纹理开销。

GLSL / WebGL 专业术语检查
以下是本项目中涉及的关键术语及其标准中文译名:
| 英文术语 | 中文译名 | 说明 |
|---|---|---|
| WebGPU | 网页图形处理单元 | 新一代 Web 图形/计算 API,由浏览器暴露现代 GPU 能力 |
| Three.js TSL | Three.js 着色语言 | Three.js 提供的节点化着色器编写方式,可编译为 WGSL 或 GLSL |
| Raymarching | 光线步进 / 射线推进 | 一种体绘制技术,逐步推进射线并采样距离场或密度场 |
| Volumetric | 体积的 / 容积的 | 描述具有内部空间分布效果的渲染方式 |
| Soft shadows | 软阴影 | 边缘柔和的阴影,通常由区域光源或多次采样产生 |
| Fog | 雾效 | 模拟大气散射,使远处物体逐渐融入背景色 |
| Glow | 辉光 / 泛光 | 高亮区域向周围扩散的视觉效果,常作为后处理 |
| Pointer | 指针 / 鼠标指针 | 用户输入设备,用于驱动交互式参数变化 |
注意:本项目基于 WebGPU 与 WGSL(WebGPU Shading Language),并非直接使用 GLSL。但 TSL 提供了抽象层,使得同样的着色逻辑可以在 WebGL(GLSL)后端运行。因此在术语理解上,光线步进、软阴影等概念与 GLSL 环境完全通用。

核心代码示意(基于 TSL 的重建)
由于原始展示页面未附带完整着色器源码,以下是根据项目描述重建的 Three.js TSL 光线步进核心逻辑示意,用于说明其结构:
// 示意:TSL 体积树冠光线步进核心(非原始代码)
import {
uniform,
vec3,
vec4,
mix,
step,
smoothstep,
sin,
time,
positionWorld,
cameraPosition,
normalize,
length,
float,
Fn,
} from "three/tsl";
export const canopyMaterial = new THREE.MeshBasicNodeMaterial();
const canopyDensity = Fn(([p]) => {
// 多层叶片密度函数:使用噪声与正弦波模拟风动
const wind = sin(p.y * 3.0 + time.mul(0.5)).mul(0.1);
const layers = sin(p.y * 5.0 + p.x * 2.0 + wind)
.add(1.0)
.mul(0.5);
const density = layers.mul(smoothstep(0.2, 0.0, length(p.xz)));
return density;
});
const rayMarch = Fn(() => {
const ro = cameraPosition;
const rd = normalize(positionWorld.sub(ro));
let t = float(0.0);
let accumDensity = float(0.0);
let light = float(0.0);
// 步进循环(示意简化)
for (let i = 0; i < 64; i++) {
const pos = ro.add(rd.mul(t));
const dens = canopyDensity(pos);
accumDensity = accumDensity.add(dens);
// 软阴影:沿光源方向二次采样密度
// light = light.add( ... );
t = t.add(0.05);
}
// 雾效与辉光混合
const baseColor = vec3(0.1, 0.5, 0.2);
const fogColor = vec3(0.7, 0.8, 0.9);
const finalColor = mix(baseColor, fogColor, accumDensity.oneMinus());
return vec4(finalColor, 1.0);
});
canopyMaterial.colorNode = rayMarch();
以上代码仅为技术结构示意,并非原始实验源码,但体现了 TSL 中体积步进、密度累积、软阴影与雾效融合的典型写法。
结语
Magical Canopy 是 WebGPU + Three.js TSL 在体积渲染方向上的优秀示范。它通过光线步进技术摆脱了传统树冠建模的几何负担,并借助 TSL 的高层抽象实现了跨 GPU 后端的优雅着色器开发流程。对于希望探索现代 Web3D 体积渲染与着色器优化的开发者而言,该项目提供了极具参考价值的实践思路。
版权声明:本文为技术深度解读,原始项目内容、截图与录屏版权归原作者 aengel 所有。
