SSS 皮肤渲染原理与实现
生成日期:2026-04-01 | 分类:角色渲染
一、为什么皮肤需要特殊处理
皮肤是一种半透明材质,光线进入皮肤后不会直接反射出去,而是会在内部发生多次散射,最终从另一个位置离开。这种现象叫做 次表面散射(Subsurface Scattering, SSS)。
单纯使用 PBR 的 Diffuse + Specular 模型无法真实还原皮肤质感,因为:
- 皮肤的高光不是完美的 Fresnel 镜面反射
- 光线会在皮肤内部扩散,导致光线从迎光面传递到背光面(俗称”透光”)
- 不同波长的光在皮肤内的散射程度不同(红光散射最强,蓝光最弱)
二、光在皮肤中的行为
2.1 皮肤的层次结构
皮肤大致可以分为三层:
2.2 散射 vs 吸收
光子在皮肤内的行为可以用 漫射方程(Diffusion Equation) 描述:
∂L(r,ω)/∂s = -μa·L(r,ω) + μs·∫f_p(ω,ω')·L(r,ω')dω'
其中:
- μa:吸收系数(Absorption)
- μs:散射系数(Scattering)
- fp:相位函数(Phase Function)
三、简化模型:Wrap Lighting
最简单直观的 SSS 近似方法是 Wrap Lighting,也叫做光线包裹:
// GLSL 示例 float wrap = 0.5; float wrapDiffuse = max(0.0, (dot(N, L) + wrap) / (1.0 + wrap));
四、经典 SSS 公式推导
4.1 扩散近似(Diffusion Approximation)
Jensen 等人在 2001 年提出的 Diffusion Approximation 是次表面散射的经典理论基础。
将散射相函数简化为 Reduced Scattering Coefficient:
σs' = (1 - g) · σs 各向异性因子 g: g = 0 → 完全各向同性散射 g > 0 → 前向散射(皮肤: g ≈ 0.8) g < 0 → 后向散射
总衰减系数:σt = σa + σs
漫射系数(Diffusion Coefficient):D = 1 / (3σt') 其中 σt' = σa + σs'
4.2 单次散射 vs 多次散射
单次散射近似(Single Scattering):
Lss = (σs/σt) · e^(-σtr) / 4πr · Fss(θ)
多次散射近似(Multiple Scattering):
Ltd = (1/4π) · e^(-σtr·r) / r² · (N·L) · R(θ)
4.3 穿透深度与波长的关系
皮肤对不同波长的光具有不同的散射/吸收特性:
| 波长范围 | 主要效应 | 约化散射系数 σs' |
|---|---|---|
| 400-500nm (蓝光) | 强吸收、弱散射 | ~1.0 mm⁻¹ |
| 500-600nm (绿光) | 中等吸收 | ~0.8 mm⁻¹ |
| 600-700nm (红光) | 弱吸收、强散射 | ~0.5 mm⁻¹ |
| 700-900nm (近红外) | 最弱吸收、最强散射 | ~0.3 mm⁻¹ |
红光散射系数小 → 穿透深度更深 → 皮肤呈现红润感
五、UE5 中的 SSS 实现
5.1 Unreal Engine 的 SSS 渲染管线
UE 使用了 Separate Wrap SH 技术,结合 Screen Space Subsurface Scattering (SSSS)
SSSS Pipeline: 1. Scene Render → GBuffer 2. Extract Subsurface Color from BaseColor 3. Blur along screen-space normals 4. Recompose with scene color
5.2 代码示例:创建 SSS 材质实例
// UE C++ 创建次表面材质
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialExpressionSubsurface.h"
#include "Materials/MaterialExpressionVectorParameter.h"
void CreateSSSMaterial(UMaterial* Material)
{
UMaterialExpressionVectorParameter* BaseColor = NewObject<UMaterialExpressionVectorParameter>(Material);
BaseColor->ParameterName = TEXT("BaseColor");
BaseColor->DefaultValue = FLinearColor(0.8f, 0.55f, 0.45f);
UMaterialExpressionVectorParameter* SubsurfaceColor = NewObject<UMaterialExpressionVectorParameter>(Material);
SubsurfaceColor->ParameterName = TEXT("SubsurfaceColor");
SubsurfaceColor->DefaultValue = FLinearColor(1.0f, 0.2f, 0.15f);
UMaterialExpressionScalarParameter* Roughness = NewObject<UMaterialExpressionScalarParameter>(Material);
Roughness->ParameterName = TEXT("Roughness");
Roughness->DefaultValue = 0.45f;
Material->bUseSubsurface = true;
Material->SubsurfaceColor.Expression = SubsurfaceColor;
}
5.3 自定义 SSS 着色器(HLSL)
// Burley 散射模型实现
float3 SSS_Scatter(float3 LightDirection, float3 ViewDirection,
float3 Normal, FSSSSettings Settings)
{
float WrapDot = dot(Normal, LightDirection) + 0.5f;
float WrappedDiffuse = saturate(WrapDot / 1.5f);
float3 TransmittedLight = exp(-Settings.ScatterRadius * (1.0f - LightDirection));
float VoN = saturate(dot(ViewDirection, Normal));
float3 F_SS = Settings.ScatterColor * (1.0f - exp(2.0f * VoN - 2.0f));
float3 SSS = F_SS * WrappedDiffuse * TransmittedLight * Settings.TransmissionIntensity;
float RoughnessSq = Settings.Roughness * Settings.Roughness;
float SpecPower = 2.0f / (RoughnessSq * RoughnessSq) - 2.0f;
float Specular = pow(saturate(dot(Normal, normalize(LightDirection + ViewDirection))), SpecPower);
return SSS + Specular;
}
5.4 散射参数配置
// UE5 - 控制次表面散射参数 Profile->Settings.bEnableBurley = true; Profile->Settings.ScatterRadius = 1.0f; // 单位: cm Profile->Settings.FalloffColor = FVector3f(0.3f, 0.15f, 0.10f); Profile->Settings.SubsurfaceColor = FLinearColor(1.0f, 0.1f, 0.08f); Profile->Settings.bUseTransmission = true; Profile->Settings.TransmissionIntensity = 1.2f;
六、实用调参指南
6.1 皮肤色调参考
| 皮肤类型 | BaseColor | SubsurfaceColor | ScatterRadius |
|---|---|---|---|
| 白皙皮肤 | (0.76, 0.54, 0.42) | (1.0, 0.18, 0.12) | 1.5cm |
| 亚洲皮肤 | (0.68, 0.50, 0.38) | (1.0, 0.25, 0.10) | 1.2cm |
| 深色皮肤 | (0.35, 0.22, 0.15) | (0.4, 0.10, 0.05) | 0.8cm |
6.2 常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 皮肤看起来像塑料 | 缺少法线细节 | 增加高频法线(毛孔) |
| 透光时颜色不对 | Subsurface Color 偏蓝 | 调成暖红色调 |
| 散射范围太大 | ScatterRadius 过大 | 减小到 0.5-1.5cm |
| 边缘有黑边 | Wrap 过度 | 减少 Wrap 值 |
七、参考文献
- Jensen, Henrik Wann, et al. "A practical model for subsurface light transport." SIGGRAPH 2001
- Burley, Brent. "Physically-based shading at Disney." SIGGRAPH 2012 Course
- d'Eon, Eugene, and Steve Marschner. "Advanced techniques for realistic human skin." SIGGRAPH 2011 Course
- Donner, Craig, and Henrik Wann Jensen. "Light diffusion in multi-layered translucent materials." ACM Transactions on Graphics, 2005
本文档版本:1.0 | 生成日期:2026-04-01