javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > Three.js阴影贴图生成

Three.js阴影贴图生成与性能优化调优指南

作者:墨舟的AI笔记

在Three.js中灯光和阴影是构建真实感和氛围的重要元素,这篇文章主要介绍了Three.js阴影贴图生成与性能优化调优的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

Three.js 阴影贴图生成与性能优化调优

在 WebGL / Three.js 3D 渲染中,“光影”是赋予场景深度与真实感的灵魂。一个没有阴影的 3D 模型,无论材质纹理多么精致,看起来都像是悬浮在虚空中的纸片。

但阴影在图形学中是一门极其昂贵的计算。很多开发者开启阴影后(renderer.shadowMap.enabled = true),场景帧率从 60 FPS 瞬间骤降至 20 FPS,且物体边缘出现严重的锯齿走样(Shadow Acne / Aliasing)或者阴影悬空(Peter Panning)。

理解阴影贴图(Shadow Map)的底层双通行渲染管线与视锥体裁剪,是兼顾电影级光影美感与极致帧率的关键。

阴影贴图底层物理原理:深度贴图与双通行渲染

现代实时阴影的主流算法是阴影贴图(Shadow Mapping)。GPU 在绘制一帧画面时,实际上在背后执行了两次场景渲染(Two-pass Rendering):

sequenceDiagram
    autonumber
    participant GPU as GPU 渲染管线
    participant LightCam as 光源视角虚拟摄像机 (Light Camera)
    participant ShadowTex as 阴影深度贴图 (Depth Map FBO)
    participant MainCam as 主视角摄像机 (Main Camera)
    participant Screen as 屏幕画布 (Screen)

    GPU->>LightCam: 1. 第一通行:将摄像机放置在光源位置
    LightCam->>ShadowTex: 渲染场景,记录从光源到每个物体的最近深度值 Z_light
    Note over ShadowTex: 生成一张单通道深度纹理 (Depth FBO)
    
    GPU->>MainCam: 2. 第二通行:从真实用户摄像机视角正常渲染场景
    MainCam->>GPU: 在片元着色器中,将当前像素坐标变换到光源投影空间 (x_proj, y_proj, z_current)
    GPU->>ShadowTex: 采样阴影深度贴图: 比较 z_current 与 Z_light
    alt z_current > Z_light (该点被前方的物体遮挡)
        GPU-->>Screen: 处于阴影区:施加环境阴影暗色
    else z_current <= Z_light (直接受到光照)
        GPU-->>Screen: 处于受光区:计算完整高光与漫反射
    end

每次场景中多了一盏投射阴影的光源(DirectionalLight 或 SpotLight),整座 3D 场景的 Draw Call 就要翻倍一次!

阴影常见三大走样与调优实战

1. 阴影粉刺(Shadow Acne)与阴影悬空(Peter Panning)

2. 光源视锥体(Shadow Frustum)极致收敛

平行光(DirectionalLight)的阴影摄像机是一个正交相机(OrthographicCamera)。如果默认视锥体范围设置得过于庞大(如覆盖 1000x1000 空间),而你的主体模型只有 10x10,那么 2048x2048 的阴影贴图绝大部分像素都被浪费在了空地上,投射到模型上的阴影分辨率只有几个像素,导致严重的锯齿边缘。

必须将光源视锥体紧紧包裹在场景的有效活动包围盒内部:

export function optimizeDirectionalLightShadow(
  light: THREE.DirectionalLight,
  targetBoundingBox: THREE.Box3
) {
  light.castShadow = true;

  // 1. 适度贴图分辨率:移动端 1024x1024,桌面端 2048x2048
  light.shadow.mapSize.width = 1024;
  light.shadow.mapSize.height = 1024;

  // 2. 软阴影类型:采用 PCF 滤波或 VSM
  light.shadow.camera.near = 0.5;
  light.shadow.camera.far = 150;

  // 3. 紧致正交视锥体包围盒
  const size = new THREE.Vector3();
  targetBoundingBox.getSize(size);
  const maxDim = Math.max(size.x, size.z) * 0.6;

  light.shadow.camera.left = -maxDim;
  light.shadow.camera.right = maxDim;
  light.shadow.camera.top = maxDim;
  light.shadow.camera.bottom = -maxDim;

  light.shadow.camera.updateProjectionMatrix();

  // 4. 阴影算法选型:开启柔和百分比接近过滤 (PCFSoftShadowMap)
  light.shadow.radius = 2; // 软阴影羽化半径
}

生产环境性能降级与烘焙策略

在包含数百个网格的复杂大屏中,实时阴影的性能优化终极心法是:

  1. 严格限制投射源:场景中坚决只允许 1 盏核心主光源开启 castShadow = true,辅助光与补光坚决关闭阴影;
  2. 区分投射与接收:绝大多数地面与墙体只需 receiveShadow = true,绝不需要 castShadow = true;
  3. 静态场景光影烘焙(Baking):对于建筑、地形等永不移动的静态物体,在 Blender 中预先烘焙为环境光遮蔽(AO)贴图和光照贴图(Lightmap),在运行时以 0 额外 Draw Call 呈现出电影级的真实阴影。

掌握阴影视锥体的几何边界与渲染开销,才能在 3D 数字画卷中从容驾驭光影之美。

总结

到此这篇关于Three.js阴影贴图生成与性能优化调优指南的文章就介绍到这了,更多相关Three.js阴影贴图生成内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文