跳到主要内容
腾讯题库 · Q05

原题 Q05 · 当前收录 4 / 49

学习状态 未开始

SSS 皮肤 Shader

Shader SSS · shader 对应课程:实时特效与质量分级

面试官问

PDF 第 11 页

如何在 Unity 中实现一个支持次表面散射(SSS)的皮肤 Shader?需考虑哪些参数与采样策略?(常问题,理清逻辑)

学习进度

0/9 已勾

只保存在这台浏览器;勾满 9 项即视为本题完成。

先把题目说成人话

普通不透明材质只在表面算明暗,皮肤因此容易像涂了颜色的塑料:脸颊阴影过硬,逆光耳廓没有温暖透光。可若把整张脸直接模糊,毛孔高光、眼睛、嘴唇和背景边缘又会一起糊掉。现实要解决的是让进入皮肤的那部分光在附近柔和出来,同时保住表面的清晰反光和非皮肤区域。

这种“光进入材质后从附近离开”的现象叫次表面散射(Subsurface Scattering,简称 SSS)。描述各颜色能在材质内走多远的配置叫扩散配置(Diffusion Profile),只在当前画面邻域近似这件事叫屏幕空间扩散(Screen-space Diffusion)。表示哪里更薄的输入叫厚度图(Thickness Map),背光穿过薄处的支路叫透射(Transmission)。

这是虚构教学故事,不是个人项目经历。

场景:先让问题变得看得见

近景角色处在逆光下。耳廓与鼻翼需要有薄处透光,脸颊上的漫反射需要比塑料更柔,但毛孔高光、眼睛和嘴唇不能一起被糊掉。

(右脑)画面:黑暗房间里,一盏暖灯从人的耳后亮起。薄薄的耳廓先透出红色,脸颊背光的一侧没有立刻掉进死黑,而是像暖意在皮肤下面走过一小段后慢慢散开。与此同时,眼睛、嘴唇的湿润亮点和皮肤表面的细小高光仍然清楚;柔和发生在皮肤里面,不是整张脸被涂糊了。

(左脑)对表:检查对象包括皮肤漫反射缓冲、材质 ID、线性深度、法线、厚度、散射半径与样本位置。最终颜色变柔是观察事实,“因此实现了 SSS”仍是假设;证据需来自分项 debug,证明镜面未参与、背景未串色、薄处透射来自厚度支路。半径必须注明毫米或 Unity 世界单位,像素核还依赖深度、FOV 与分辨率;透视换算不能套到正交相机。薄蜡类比只说明局部传播,类比不等于屏幕空间卷积就是完整体积光传输。

小明:先形成一个完整猜测

小明建议把最终人物颜色做一次大范围模糊。这样确实会变柔,却会把镜面高光、眼睛、嘴唇和背景边缘一起污染;这不是对皮肤漫反射的有边界扩散。

他的方案留下了一条有用证据:如果只模糊最终颜色,所有光照分量都会串色。正确实现需要先分离“允许扩散的皮肤漫反射”。

小红:把猜测放回现实检查

小红先把允许“走进皮肤”的光单独显示出来:只有皮肤漫反射是白色,眼睛、牙齿、头发和清晰镜面都保持黑色。这个材质 mask 只决定谁参加扩散,能保护眼睛和镜面,却不能单独阻止采样跨过人物轮廓;逐样本材质 ID 排除其他材质,再由深度、法线双边权重抑制漏到背景或另一块表面。它们能降低串色,不保证所有遮挡边界都完美。

她固定采样数,只改变以毫米或项目世界单位定义的散射半径,确认变化的是光在皮肤内摊开的物理范围。对透视相机和局部近似正对相机的小范围表面,可用 rpx≈rworldfy,px/zr_{px}\approx r_{world}f_{y,px}/z 换算像素核,其中 fy,px=H/[2tan⁡(FOVy/2)]f_{y,px}=H/[2\tan(FOV_y/2)],zz 是正的观察空间深度;rworldr_{world} 与 zz 必须同单位,Profile 若用毫米还要按 World Scale 换成 Unity 世界单位。正交相机的像素比例不随深度按 1/z1/z 变化。固定像素半径只能算艺术近似。随后固定世界半径再改采样数,观察离散采样何时出现带状或抖动。最后显示厚度图:耳廓比脸颊薄,因此背光透射更强。厚度图解释“哪里容易透”,不替代表面扩散。

我:用检查结果修正模型

画面机制确定后,再按项目锁定的 Unity 版本、渲染管线与目标平台选实现:HDRP 可先核对内置 Diffusion Profile、Subsurface Scattering 与 Transmission;URP 或自定义 SRP 若没有同等内置路径,就要明确采用自建屏幕空间扩散,还是只保留包裹光和厚度透射等艺术近似。管线名称不能替代版本文档、实际中间缓冲和目标 Player 的验证。

我根据平台划分档位:

  • 高质量:HDRP Diffusion Profile,或半分辨率屏幕空间扩散;使用预计算、成对合并的卷积核并结合深度/法线权重,避免跨轮廓漏色。
  • 中质量:更小的扩散半径与样本数,保留厚度驱动的背光透射。
  • 低质量:关闭屏幕空间扩散,用 wrap diffuse、预积分皮肤查找表和一条受厚度控制的透射近似;它保留“暗部不死、薄处透光”的艺术目标,但不再声称是完整 SSS。

需要共同控制的参数包括:皮肤 Base Color、每通道散射颜色/半径、厚度、透射强度、法线、粗糙度、光源方向,以及分辨率、样本数和 temporal 策略。最终取舍要在目标构建中同时检查轮廓漏色、运动拖影、面部细节和 GPU 成本。

(右脑)画面修正:小明把整张人物画面一起模糊,脸确实柔了,眼睛、嘴唇、亮点和背景边缘也一起化开。小红把允许在皮肤里散开的光单独留下,耳朵的薄处另看透光,清晰的表面亮点则保持在外面。这样回看最初那张脸,柔和与清楚终于能同时存在;较便宜的方案可以保留这种观感,但不能因此自称完成了同样的光传输。

(左脑)严格对表:实现顺序为:标记皮肤像素;输出不含镜面的线性漫反射;把物理半径按 World Scale 和相机参数换成采样核;逐样本以材质 ID 排除异物,并用线性深度与法线权重抑制跨面;按 RGB Profile 做横纵扩散;计算厚度驱动的透射;最后与未模糊镜面合成。验收条件是半径单位明确、改变半径与改变样本数产生可区分证据、轮廓和异材质不明显漏色、运动时历史结果不拖尾,并在目标 Player 记录 GPU 时间。

老师解惑

屏幕空间近似的实现顺序通常是:

  1. 用材质 ID 或 stencil 只标记皮肤。
  2. 把皮肤的漫反射光照写入中间缓冲,镜面保持独立。
  3. 用若干可分离高斯之和,或 Jimenez 式单个可分离近似,逼近 Diffusion Profile;不同 RGB 通道使用不同扩散宽度。
  4. 逐样本用材质 ID 排除其他材质,并用深度、法线双边权重抑制跨轮廓串色。
  5. 将扩散后的漫反射与未模糊的镜面项(包括镜面 IBL)及其他材质重新合成;漫反射环境光应在扩散前进入漫反射缓冲,否则要明确这是性能近似。
  • Diffusion Profile:描述光在材质内部各颜色通道能扩散多远;距离需要明确使用毫米、世界单位还是固定像素近似。
  • 屏幕空间扩散:只对已经渲染到屏幕的皮肤漫反射做卷积;屏幕外信息、遮挡关系和轮廓需要额外处理。
  • 厚度与透射:厚度图帮助估计背光穿过多少材料,最适合耳、鼻翼、手指等薄处。
  • 可分离卷积:对可分离核或其近似,把二维采样拆成横向与纵向两次一维采样,降低样本数量;深度/法线权重用于抑制跨物体串色。
  • wrap lighting:便宜的艺术化近似,只改变暗部漫反射形状,不等同于真实光在皮肤内传播。

工具分工

  • HDRP Diffusion Profile / Material Inspector:在 HDRP 中配置散射距离、颜色与透射。
  • Unity Frame Debugger:确认皮肤标记、漫反射缓冲、扩散和合成 Pass 的顺序。
  • Unity Profiler(GPU Usage):在目标构建上比较分辨率、样本数和档位成本。
  • RenderDoc:检查扩散缓冲是否跨轮廓污染,以及镜面是否被错误模糊。

记忆钩子

只扩散皮肤漫反射,镜面留清楚;半径决定走多远,样本决定算多细,厚度决定哪里能透。

这是教学场景,不是目标项目的真实捕获或个人经历。

下一步:验证这条因果

把截面厚度、扩散 profile、材质边界和采样预算逐项对上画面。

教学边界:它只验证这一条画面因果,不替代完整答案、项目经历或目标设备数据。

进入教学 Lab:「光不是撞到皮肤就立刻弹回来」