2.3 阴影工序:从光到影子的一次投递


文档摘要

2.3 阴影工序:从光到影子的一次投递 本节摘要:阴影是布光工位手续最繁的工序:总闸、灯闸、投方、受方、阴影相机五处登记,缺一处影子就不出勤。本节把整条投递链拆开演示,讲清阴影相机的范围标定与分辨率模糊度的取舍,并以沙盘阴影调优收尾,为第 8 章性能质检备好参数。 影子不出勤的五处登记 开了 castShadow 影子却毫无动静,是布光工位申诉率最高的事故。多数教程只教你一行 castShadow 等于 true,于你以为手续办完了——其实 Three.js 的阴影是一条完整流水线:场景在渲染前,会先站到每盏开阴影的灯的视角,把"哪些地方被挡住"画进一张深度图;正式渲染时,材质再去查这张图,查到"此处被遮挡"就调暗。流水线上的每一站都要登记,少一站,深度图画不出来或者查不到,影子就旷工。

2.3 阴影工序:从光到影子的一次投递

本节摘要:阴影是布光工位手续最繁的工序:总闸、灯闸、投方、受方、阴影相机五处登记,缺一处影子就不出勤。本节把整条投递链拆开演示,讲清阴影相机的范围标定与分辨率模糊度的取舍,并以沙盘阴影调优收尾,为第 8 章性能质检备好参数。

影子不出勤的五处登记

开了 castShadow 影子却毫无动静,是布光工位申诉率最高的事故。多数教程只教你一行 castShadow 等于 true,于你以为手续办完了——其实 Three.js 的阴影是一条完整流水线:场景在渲染前,会先站到每盏开阴影的灯的视角,把"哪些地方被挡住"画进一张深度图;正式渲染时,材质再去查这张图,查到"此处被遮挡"就调暗。流水线上的每一站都要登记,少一站,深度图画不出来或者查不到,影子就旷工。

五处登记如下:渲染器总闸 shadowMap.enabled;灯的出件闸 castShadow;投方物件闸 castShadow(谁挡光);受方物件闸 receiveShadow(谁挨影子);阴影相机范围(灯光视角能"看见"多大的区域)。前三处是布尔值,一处三字;最后一处是本节的正戏——范围标错了,影子不是没有,而是缺角或糊成一片。

图:阴影投递链五道登记与深度图查询

图:阴影投递链五道登记与深度图查询

阴影相机:影子缺角的头号原因

方向光的阴影靠一台正交阴影相机"看"场景,它有左右上下近远六个边界,默认范围只有正负 5 个单位。沙盘货箱铺开十几米宽,超出边界的部分根本进不了深度图——表现就是影子只在中间一小块出现,边缘整段缺失。标定方法:把阴影相机的边界恰好框住"需要投影的区域",一寸不浪费;范围越大,同样的阴影贴图分辨率摊到每寸的精度越低,影子越糊。

// 阴影五道登记(方向光主光) stage.renderer.shadowMap.enabled = true; // 1 总闸 stage.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 软化边缘的滤波方式 const sun = new THREE.DirectionalLight(0xffffff, 1.4); sun.position.set(-6, 10, 4); sun.castShadow = true; // 2 灯闸 // 3 阴影相机标定:恰好框住货盘区域(约 12 单位宽深) sun.shadow.camera.left = -8; sun.shadow.camera.right = 8; sun.shadow.camera.top = 8; sun.shadow.camera.bottom = -8; sun.shadow.camera.near = 1; sun.shadow.camera.far = 30; sun.shadow.mapSize.set(2048, 2048); // 深度图分辨率,画质与帧率的跷跷板 sun.shadow.bias = -0.0005; // 消除表面自阴影条纹 stage.scene.add(sun); // 4 与 5:投方与受方逐件登记 group.traverse((obj) => { if (obj.isMesh) { obj.castShadow = true; obj.receiveShadow = true; } }); ground.receiveShadow = true; // 地面只收影,不必投

动手:给沙盘上影并调优

背景:评审会反馈沙盘"太飘"——货箱像浮在地贴上。加影子是最直接的救法,但设备清单里有低配笔记本,帧预算不允许全场景高精度阴影。

操作:按上文代码完成五道登记,然后做一轮分辨率标定。

结果:货箱右侧拖出与主光方向一致的软边影子,"浮空感"消失,场景重量立刻上来。把 mapSize 从默认 512 提到 2048 后,影子边缘干净无锯齿;控制台帧率在高配机上纹丝不动,低配机上掉了约两成。

解读:三笔账要算清。第一笔,分辨率账:2048 的深度图在 16 单位范围内约每 0.008 单位一格,影子边缘平滑;同样的 2048 若阴影相机开到 40 单位,精度跌四倍,边缘立刻出现台阶——所以范围标定和分辨率是一张账单的两行,一起调。第二笔,bias 账:影子表面出现莫尔条纹(物件自己身上有斑驳横纹),是深度比较的精度误差导致自遮挡,负向 bias 是止痛片,剂量过大影子会从根部"漂离"物体,微调到条纹消失即可。第三笔,滤波账:PCFSoftShadowMap 边缘柔和,适合室内柔光;追求硬朗的工业风用 PCFShadowMap,几乎白赚性能。

变式:低配设备兜底方案——检测帧率持续低于阈值时,把 mapSize 降回 1024 并改用普通 PCF 滤波,视觉几乎无损、帧率回血;更极端的方案是给移动端整段关闭阴影,用一张预烘焙的暗色渐变贴图垫在货箱脚下,成本为零。阴影的终极优化思路在 8.1 节还会展开:影子贵在"实时",能预烤的绝不现烤。

排错台:三种影子事故的会诊

事故一,"影子只出现一小块"。十有八九是阴影相机范围没标定——默认正负 5 个单位装不下沙盘,超界物件整段丢影;按上文六参数框准投影区即愈。事故二,"物件身上有斑驳横纹"。这是自阴影精度冲突(阴影痤疮),负向 bias 小剂量止痛;若调 bias 后影子根部与物体脱开一条缝,说明剂量过头,往回调,或改用 normalBias 沿法线方向偏移,对曲面物件更温和。事故三,"影子边缘闪烁抖动"。方向光位置没固定(比如挂在会移动的物件上)导致阴影相机每帧微动,或阴影贴图分辨率过低让边缘在两个像素间跳动;前者把光源独立出来,后者提分辨率或加滤波。三则事故合计覆盖了阴影工位九成的报障,下次影子旷工,先照单会诊再动手改参数。

还有一条给动态场景的忠告:物件大幅移动后影子突然消失,先查它是否跑出了阴影相机的远裁剪面——阴影相机也有 near 与 far,高空的飞行物件常死在这道边界上;把 far 抬到"最高物件加两倍"的高度即可。另外,半透明物件的影子表现要单独说明:透明材质默认也会投出实心影子,玻璃罩投黑影的违和感就来自这里,需要给这类物件单独关闭投影,或接受"影子是简化的"这一行业惯例。

本节要点回顾

  • 五道登记缺一旷工:总闸、灯闸、阴影相机、投方、受方,逐处检查再报障;
  • 阴影相机范围即精度:框准投影区一寸不浪费,范围与分辨率同账单联调;
  • bias 治条纹不过量:负值小剂量止痛,过量影子漂离物体根部;
  • PCFSoft 柔、PCF 硬:滤波方式按场景气质与性能预算选;
  • 两遍渲染是影子底价:开阴影即场景多画一遍,低配端要有降级预案。

布光工位收工。下一章换岗到上漆工位:影子给了体积,材质谱系和纹理贴图负责给这些货箱换上"实拍级"的表皮。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U