SSS皮肤渲染原理与实现 – 角色渲染技术详解

SSS 皮肤渲染原理与实现

生成日期:2026-04-01 | 分类:角色渲染

一、为什么皮肤需要特殊处理

皮肤是一种半透明材质,光线进入皮肤后不会直接反射出去,而是会在内部发生多次散射,最终从另一个位置离开。这种现象叫做 次表面散射(Subsurface Scattering, SSS)

单纯使用 PBR 的 Diffuse + Specular 模型无法真实还原皮肤质感,因为:

  • 皮肤的高光不是完美的 Fresnel 镜面反射
  • 光线会在皮肤内部扩散,导致光线从迎光面传递到背光面(俗称”透光”)
  • 不同波长的光在皮肤内的散射程度不同(红光散射最强,蓝光最弱)

二、光在皮肤中的行为

2.1 皮肤的层次结构

皮肤大致可以分为三层:

图1: 皮肤层次结构与光线散射示意
图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));
图2: Wrap Lighting vs 标准 Lambert 对比
图2: Wrap Lighting vs 标准 Lambert 对比

四、经典 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
图3: UE5 皮肤材质节点连接示意
图3: UE5 皮肤材质节点连接示意

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

配图索引

图4: 次表面散射公式体系总览
图4: 次表面散射公式体系总览

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部