PreintegratedSkin预积分皮肤BxDF
2025-11-9
| 2025-11-12
Words 1004Read Time 3 min
type
status
date
slug
summary
tags
category
icon
password
SHADINGMODELID == SHADINGMODELID_PREINTEGRATED_SKIN

1.Gbuffer设计:

notion image
重点有个Curvature 曲率。
这玩意一开始设计是放在MaterialInputs.color_mask.y
然后到gbuffer阶段存到 gbuffer.Curvature

材质输入阶段

曲率图(如果没有 填充58灰度)
notion image
ao图:
notion image
notion image

平行光 光照计算

核心是 双 lobe GGX 模拟皮肤两层高光预积分 LUT 查表 —— 次表面散射的核心简化
先大致了解一下:

双 lobe 模拟皮肤两次高光

皮肤的反光分两层:表皮的油脂层(细腻高光)+ 真皮的粗糙反光,单 lobe GGX 无法模拟这种层次,所以用 “双 lobe”(两个不同粗糙度的 GGX 高光混合):
一般会设置两个粗糙度,大粗糙度和小粗糙度。然后通过某个系数进行混合。并且引入曲率影响。曲率大的地方(鼻尖、颧骨),高光更细腻(粗糙度降低),符合真实皮肤规律。
譬如:(函数来自ue)
notion image

预积分 LUT 查表 —— 次表面散射的核心简化

皮肤的次表面散射需要计算 “光线在皮肤内的多次散射”,实时计算太慢,所以 离线预计算成 LUT,实时查表:
notion image

2.1相关代码:

主函数架构(master 稳定版本):
notion image
主要就是用预积分皮肤LUT
future high主函数架构(非常不完善版本):
notion image
在lut上,还引入了 动态曲率lut,和预积分皮肤LUT分情况使用
代码如下:
知识点如下

2.2计算实现:

直接光漫反射(LUT):

这里如果是在捏脸界面,是需要再走一个ssss的pass的,增强效果
这里的主要效果是sss 此表面散射。这就很奇怪了,为什么把sss放在Lighting.Diffuse 而不是 Lighting.Transmission ?
notion image
Lighting.Transmission 更倾向于 透过去的光
而皮肤这里的通过 LUT 计算的 SSS 效果(BRDF * GBuffer.DiffuseColor)本质是 “次表面散射对漫反射颜色的修正”,而非 “直接透射”,因此归到 Diffuse 更合理
而耳朵的 “透光” 如果是 “光线直接穿过薄皮肤”(无太多散射),才会归到 Transmission。
代码中用 LUT 计算的RGBCurvature(曲率相关的散射颜色)本质是修正漫反射的 “颜色分布”(曲率大的地方红色更重),因此合并到 Diffuse 符合物理表现

某管线用的动态LUT

float2 UV = float2(saturate(Context.NoL_Fullrange * 0.5 + 0.5), GBuffer.Curvature);
//可见 UV的U是归一化的Nol,V是曲率 此管线使用的LUT即考虑了视线问题
half3 PreintegratedBRDF = t_preintegrated_skin_lut.SampleLevel(s_preintegrated_skin_lut, UV, 0).rgb;
Lighting.Diffuse = PreintegratedBRDF * GBuffer.DiffuseColor;
PreintegratedBRDF 可以算是 预计算综合散射系数。包含了基础漫反射分量,次表面散射分量,参数相关性(光照角度 皮肤曲率等)

直接光高光:

重点是D F G 中的D项。 可见重点就是:
1.两种粗糙度的混合
2.在不同的区域(低曲率区域比如脸颊 怎么混合 高曲率区域比如鼻子 这两粗糙度怎么混合)
notion image

低画质下的优化:

双粗糙度这个核心显然是不能去除的。但是可以去除曲率影响粗糙度
这个改动很简单,就不贴代码了。就是
再极低画质下,直接使用通用材质的高光就更常见了。

Sss单独作为 pass:

3.点聚光 光照计算

4.一种在材质输入阶段实现的 比较节省的方案

  • HLSL
  • 渲染
  • 图形学
  • NP相关 - Φ观测方位角差 和 理解SpecularGGX - 直接光高光整合
    Loading...