目录
PBR 渲染(物理基础渲染)知识大纲
1. PBR 渲染概述
-
定义:PBR(Physically Based Rendering)是一种模拟现实世界物理现象的渲染技术,旨在通过物理规律更真实地再现光与物体表面之间的交互。
-
发展背景:从传统的光照模型到现代的基于物理的渲染方法,PBR旨在提高渲染的真实性和一致性。
-
目标:更准确地模拟材质与光源的交互,实现材质的统一表现,特别是不同光照环境下的表现一致性。
2. PBR 基础概念
-
能量守恒:表面反射的光不应超过入射光的强度,避免产生不物理的亮度。
-
微表面模型:模拟表面微观结构对光的散射影响,常用的模型包括:
-
Cook-Torrance 模型
-
Lambertian 反射
-
Fresnel 反射
-
-
BRDF(双向反射分布函数):描述表面如何反射光,PBR渲染通常使用复杂的BRDF模型来进行反射模拟。
3. PBR 渲染模型的组成
-
Albedo(基色):材质的基础颜色,不包含光照信息的表面颜色。
-
Metallic(金属度):材质是否为金属的属性,金属材质的反射特性与非金属材质有显著差异。
-
Roughness(粗糙度):表面微结构的光滑度,影响表面反射的锐利度和散射程度。
-
Normal Map(法线贴图):用于修改表面法线,以模拟更复杂的表面细节,如凹凸、皱纹等。
-
Ambient Occlusion(环境光遮蔽):模拟光线被周围几何形状阻挡时的阴影效果。
-
Specular(高光反射):描述反射表面如何表现光亮区域,主要影响金属或非金属材质的高光表现。
4. PBR 渲染流程
-
光源模型:理解点光源、方向光源、聚光灯等对场景的影响。
-
渲染路径:从表面交互到最终的图像输出,常见的渲染路径有:
-
前向渲染(Forward Rendering)
-
延迟渲染(Deferred Rendering)
-
-
光照计算:包括漫反射光照、镜面反射光照、折射、反射等。
-
表面反射模型:如何利用Cook-Torrance模型或其他近似模型计算表面反射。
5. PBR 在游戏引擎中的应用
-
Unity:
-
使用标准材质(Standard Shader)
-
PBR 渲染管线(URP, HDRP)
-
光照探针、反射探针与全局光照。
-
-
Unreal Engine:
-
使用PBR材质系统
-
强大的后期处理和材质编辑器(Material Editor)
-
-
PBR工作流程:材质创建、纹理生成、光照设置等步骤。
6. PBR 材质类型
-
金属与非金属材质:
-
金属表面反射近乎所有光线,具有镜面光泽。
-
非金属材质的反射较弱,并带有漫反射。
-
-
透明与不透明材质:
-
透明材质(如玻璃)与折射/透射模型。
-
通过折射率(IOR)调整透明材质的渲染效果。
-
-
层次化材质:模拟表面上多层材质的混合,如皮革、布料等。
7. PBR 技术实现
-
离线渲染与实时渲染的区别:PBR技术如何适应不同的渲染需求。
-
贴图格式:常用的PBR贴图格式,包括:
-
Albedo/Color Map
-
Roughness/Glossiness Map
-
Metallic Map
-
Normal Map
-
Ambient Occlusion Map
-
-
反射贴图:环境反射、反射探针的使用。
8. PBR 渲染中的高级技术
-
光谱反射率:使用实际的光谱数据来更精确地描述材质的反射。
-
表面微结构建模:对微表面模型进行更高阶的建模,以支持复杂的材质效果。
-
实时全局光照(RTGI):实时计算物体间的间接光照,以增加渲染的真实感。
-
辐射度与BRDF表面采样:采用更复杂的辐射度方程计算表面采样,提高光照计算的精度。
9. PBR 渲染中的优化
-
延迟渲染:优化多个光源渲染,适用于复杂场景。
-
纹理压缩与LOD(细节层次):减少内存占用和计算复杂度。
-
动态范围(HDR)渲染:支持更高的亮度范围,以更好地呈现高动态范围的光照效果。
PBR 基础概念:
PBR 基础概念
1. 能量守恒(Energy Conservation)
-
定义:能量守恒原则意味着物体表面反射的光线不能超过入射光线的总量。换句话说,任何表面材质的反射能量(即反射光)加上吸收能量和透射能量的总和不得大于入射光的能量。
-
重要性:能量守恒是 PBR 渲染中最重要的原则之一,它确保了材质的光照行为符合现实物理规律,避免了诸如反射光过亮等不自然的现象。在 PBR 模型中,常常会使用 Fresnel-Schlick 近似来计算反射部分,确保总反射光不会超出实际物理的限制。
2. 微表面模型(Microfacet Model)
-
定义:微表面模型是用来描述材质表面微小结构对光照的影响。这些微小的表面结构(通常视为微小的平面)在宏观上形成粗糙或光滑的效果。
-
工作原理:当光线照射到物体表面时,光会在这些微表面结构上反射。不同的表面结构(粗糙或平滑)会改变光的散射方式。微表面模型使用统计分布(如 Beckmann 分布、GGX 分布)来模拟这些表面结构的特性。
常见的微表面分布模型:
-
Beckmann 分布:适用于光滑至中等粗糙的表面。
-
GGX 分布:用于较为粗糙的表面,能更好地模拟实际粗糙表面的光散射特性。
3. BRDF(双向反射分布函数)
-
定义:BRDF 描述了光与表面交互时的反射行为,尤其是入射光和反射光方向之间的关系。BRDF 是一个函数,用来计算从表面某一点反射光的强度。
-
公式:BRDF 通常用一个函数表示,定义为入射辐照度(或入射光强度)和反射光强度之间的比值。
$
f r (L,V)= dE i (L,V)/ dL o (L,V)
$其中
$
mathbf{L}
$$
mathbf{V}
$分别是入射和观察方向,
$
dLo
$是反射光的辐射度,
$
dEi
$是入射光的辐照度。
-
BRDF 组成:PBR 中的 BRDF 由以下几个主要部分构成:
-
漫反射项(Diffuse Component):描述光线被表面散射的部分。常见的漫反射模型为 Lambertian。
-
镜面反射项(Specular Component):描述光线在表面微结构上的反射部分。
-
Fresnel 项:描述入射光与表面交互时,随着入射角的变化反射光的变化。
-
几何项(Geometric Attenuation):描述表面微结构的遮挡和阴影效应。
-
-
Cook-Torrance BRDF:现代 PBR 渲染中广泛使用的 BRDF 模型。它将反射光分为两个主要部分:
-
菲涅耳反射(Fresnel Reflectance):光在表面入射角度变化时的反射强度,通常通过 Fresnel-Schlick 近似 计算。
-
几何遮挡(Geometric Attenuation):描述表面微结构之间的遮挡现象,通常使用 Smith模型。
Cook-Torrance BRDF 的简化版本公式如下:
$$
fr=4(cos(θi)cos(θo))F(θi)G(θi,θo)D(α)
$$ -
4. Fresnel 反射(Fresnel Reflectance)
-
定义:Fresnel 反射描述的是当光线入射到表面时,由于入射角度的不同,反射光的强度发生变化的现象。入射光与表面之间的夹角越大,反射光的比例越高。
-
Fresnel-Schlick 近似:为了避免计算复杂度,PBR 中通常使用 Fresnel-Schlick 近似公式来简化计算:
$
F0=F(θ)≈F0+(1−F0)(1−cos(θ))5
$
5. 表面粗糙度与光泽度(Roughness vs. Glossiness)
-
粗糙度(Roughness):表面微结构的粗糙度决定了光的散射程度。在 PBR 中,粗糙度的数值通常从 0(光滑表面)到 1(非常粗糙表面)之间。粗糙表面会散射更多的光,使反射更模糊。
-
光泽度(Glossiness):光泽度通常是粗糙度的倒数,较高的光泽度表示表面更光滑,反射更集中。通常在材质定义中,粗糙度和光泽度相互对立,二者可通过互补映射。
6. PBR 渲染的光照模型
-
直接光照(Direct Lighting):指的是物体表面直接接受来自光源的照射。
-
间接光照(Indirect Lighting):指的是光线被其他物体反射后再照射到物体表面上。PBR 渲染中的间接光照(例如全局光照)通过更精确的光照模拟来提高真实感。
7. 反射率与金属度(Metalness)
-
金属度(Metalness):在 PBR 中,金属材质的反射行为与非金属材质不同。金属材质的反射光几乎完全来自其表面,而非金属材质则存在一定的漫反射。金属度控制了这一点,通常通过一个 0 到 1 的值来表示:
-
金属度为 1 时,材质是完全金属。
-
金属度为 0 时,材质是完全非金属。
-
-
反射率(Reflectance):金属表面的反射率通常较高,而非金属表面的反射率较低。反射率通常通过 F0 来表示,在 PBR 中,反射率值基于材质的金属度进行调整。
8. PBR 渲染工作流程
-
线性工作流(Linear Workflow):PBR 渲染通常在一个线性空间中进行,确保在计算颜色和光照时不发生色彩空间失真。
-
材质模型(Material Model):常见的材质类型包括:
-
金属材质:完全由金属材料构成,表面反射表现较强。
-
非金属材质:反射光和散射光有较大区别,通常有较为显著的漫反射部分。
-
透明材质:如玻璃或水,常常需要额外的折射和透光计算。
-
用代码实现 PBR 渲染过程:
如何用代码实现 PBR 渲染过程
在编写 PBR 渲染代码时,需要实现多个核心步骤,包括计算表面的反射率、粗糙度、法线方向以及与光源的交互。以下是实现这一过程的关键代码步骤:
1. 计算 Fresnel 反射(Fresnel-Schlick 近似)
Fresnel 方程用来描述光线入射到介质时,表面反射与透射的比例。PBR 中,Fresnel 反射是反射强度的重要因素,且依赖于入射角度。Schlick 近似是计算 Fresnel 反射的一种高效方法。
// Schlick approximation for Fresnel reflection
float FresnelSchlick(float cosTheta, float F0) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
-
cosTheta
是光线与法线之间的夹角的余弦值。 -
F0
是材料的基准反射率,通常在没有入射角度变化时(即垂直入射),这个值通常取 0.04(表示常见的非金属表面反射率)。
2. 计算 BRDF(双向反射分布函数)
BRDF 是用来描述表面反射光照的数学模型。在 PBR 渲染中,常用的 BRDF 模型是 Cook-Torrance 模型,它涉及到微表面粗糙度、视角和光源方向。
// Cook-Torrance BRDF model
float CookTorrance(float V, float H, float NdotV, float NdotL, float roughness) {
// Fresnel term
float F = FresnelSchlick(NdotV, 0.04); // 0.04 is the typical F0 for non-metals
// Geometric attenuation term (Schlick-GGX)
float G = (NdotV * (1.0 - roughness) + roughness) / (NdotV + roughness);
// Microfacet distribution term (GGX)
float D = (NdotH * (1.0 - roughness) + roughness) / (NdotH * NdotH + (1.0 - NdotH * NdotH) * roughness * roughness);
return (F * G * D) / (4.0 * NdotV * NdotL);
}
-
V
和L
分别是视线和光线方向的单位向量。 -
NdotV
、NdotL
和NdotH
分别表示法线与视线、光线、半程向量H
(光线与视线的中间向量)之间的点积。 -
roughness
控制表面的粗糙程度,决定光线如何散射。
3. 法线与半程向量的计算
为了计算 BRDF 中的反射强度,需要计算法线与视线和光线的夹角。
// 计算法线与视线的夹角
float NdotV = max(dot(normal, viewDirection), 0.0); // 正向法线与视线方向的点积
// 计算法线与光线的夹角
float NdotL = max(dot(normal, lightDirection), 0.0);
// 计算法线与半程向量的夹角
vec3 H = normalize(viewDirection + lightDirection);
float NdotH = max(dot(normal, H), 0.0);
-
normal
是表面的法线。 -
viewDirection
和lightDirection
是视线和光线的方向向量。 -
H
是视线与光线的半程向量,计算方式是对视线方向和光源方向进行归一化求和。
4. 计算 PBR 材质的反射和光照
PBR 渲染模型中,通常需要考虑 漫反射(Diffuse) 和 镜面反射(Specular) 部分。漫反射部分一般采用 Lambertian 模型,而镜面反射则使用 Cook-Torrance 模型。
// Lambertian diffuse reflectance (simplified)
vec3 LambertDiffuse(vec3 albedo) {
return albedo / PI;
}
// PBR 光照计算
vec3 PBRLighting(vec3 albedo, float roughness, float metallic, vec3 normal, vec3 viewDirection, vec3 lightDirection) {
// 漫反射部分
vec3 diffuse = LambertDiffuse(albedo);
// 镜面反射部分 (Cook-Torrance)
float NdotV = max(dot(normal, viewDirection), 0.0);
float NdotL = max(dot(normal, lightDirection), 0.0);
vec3 H = normalize(viewDirection + lightDirection);
float NdotH = max(dot(normal, H), 0.0);
// 计算 Fresnel、几何遮蔽、微表面分布函数
float F = FresnelSchlick(NdotV, 0.04); // 使用常见的非金属反射率
float G = (NdotV * (1.0 - roughness) + roughness) / (NdotV + roughness); // 简化的遮蔽项
float D = (NdotH * (1.0 - roughness) + roughness) / (NdotH * NdotH + (1.0 - NdotH * NdotH) * roughness * roughness); // GGX分布
vec3 specular = F * G * D / (4.0 * NdotV * NdotL);
// 结合漫反射和镜面反射
vec3 finalColor = diffuse + specular;
return finalColor;
}
-
漫反射:使用 Lambertian 模型计算材质的漫反射部分。
-
镜面反射:使用 Cook-Torrance BRDF 计算镜面反射部分。
-
Fresnel:根据视角计算 Fresnel 反射系数。
-
G(几何遮蔽):根据表面粗糙度计算几何遮蔽项。
-
D(微表面分布):使用 GGX 分布函数计算表面微观结构的反射分布。
-
5. 光照模型的实现
PBR 渲染的光照模型可以通过不同类型的光源(如点光源、聚光灯等)来实现。以下是一个简化的光照计算方式,适用于场景中的点光源:
vec3 PointLight(vec3 lightPosition, vec3 viewPosition, vec3 normal, vec3 albedo, float roughness, float metallic) {
// 计算光源方向
vec3 lightDirection = normalize(lightPosition - viewPosition);
// 使用PBR光照模型计算表面颜色
return PBRLighting(albedo, roughness, metallic, normal, viewPosition, lightDirection);
}
-
lightPosition
是光源的位置。 -
viewPosition
是观察者(相机)的位置。 -
normal
是表面的法线。 -
albedo
是材质的基础颜色(漫反射部分)。 -
roughness
和metallic
分别是材质的粗糙度和金属度。
6. 最终渲染
结合所有计算结果,最终渲染输出将包括来自多个光源的贡献,并根据每个光源的位置、强度和材质的属性来综合计算最终像素的颜色。
vec3 Render(vec3 viewPosition, vec3 normal, vec3 albedo, float roughness, float metallic, vec3 lightPosition) {
vec3 color = vec3(0.0);
// 对于每个光源,计算光照
color += PointLight(lightPosition, viewPosition, normal, albedo, roughness, metallic);
return color;
}
-
Render
函数通过多次调用PointLight
函数来处理不同光源的影响。 -
最终颜色通过所有光源的计算结果相加得到。
预计算与实时计算对性能的消耗:
预计算与实时计算对性能的消耗以及近似方式
在 PBR 渲染中,许多计算(如 Fresnel 反射、光照模型、环境光反射等)都可能对性能产生影响。根据计算是否需要在每帧渲染时实时进行,或者是否可以通过预计算进行优化,性能的消耗会有较大差异。以下详细讨论了预计算与实时计算的区别、性能消耗以及常见的近似方法。
1. 预计算与实时计算
(1) 预计算
预计算是指在运行时之前对某些计算结果进行存储或计算,以便在渲染过程中快速查找或使用。这种方式通常用于无法在实时渲染中轻易计算的复杂操作,如环境光反射、材质参数的复杂处理等。
-
优点:
-
减少每帧的计算量。
-
提高渲染性能,尤其是对于复杂的光照模型和材质属性。
-
可以通过存储查找表(LUTs)等方式来减少实时计算的开销。
-
-
缺点:
-
需要额外的存储空间来存储预计算结果。
-
可能需要额外的计算时间来生成预计算数据。
-
-
示例:
-
环境光反射:对于环境光反射(如 IBL,图像基础光照),通常会预先计算一个环境贴图或环境光源的反射信息,存储为一张立方体贴图或其他形式的纹理,在渲染时直接使用。
-
BRDF 查找表:通过预计算不同粗糙度和入射角度下的 BRDF 值,并将其存储在查找表中,避免了每帧实时计算复杂的 BRDF 模型。
-
(2) 实时计算
实时计算是指在每一帧渲染时,动态计算材质与光源之间的交互,如 Fresnel 反射、镜面反射、漫反射等。实时计算通常需要处理每个光照与表面材质的交互,计算量较大,但能够适应动态变化的环境。
-
优点:
-
灵活,可以处理复杂的光照条件和材质变化。
-
能够应对动态场景中的材质和光源变化。
-
-
缺点:
-
每帧计算量较大,对性能消耗较高。
-
在复杂场景下可能造成帧率下降,尤其是在移动设备或低性能平台上。
-
-
示例:
-
Fresnel-Schlick 近似:实时计算 Fresnel 反射,这个计算需要在每个光照交互时进行。
-
Cook-Torrance BRDF 计算:每帧实时计算材质的光反射和粗糙度。
-
2. 性能消耗
-
计算开销:PBR 渲染中的某些计算,特别是涉及到精确物理模拟的计算,可能非常耗费 GPU 资源。实时计算的复杂性会显著增加计算负担,尤其是在有多个光源和动态物体的情况下。常见的性能瓶颈包括:
-
光照计算:PBR 模型中,计算每个光源对场景的影响时需要考虑入射角度、反射率、粗糙度等,涉及大量浮点计算。
-
Fresnel 反射:虽然 Fresnel-Schlick 近似相对简单,但若光照场景较复杂时,依然会带来一定的计算开销。
-
环境光反射:IBL(Image-Based Lighting)需要对环境贴图进行采样,尤其是高质量的反射会增加计算量。
-
-
存储开销:预计算时,存储的开销主要来源于:
-
环境光贴图:立方体贴图、Irradiance Map 和 BRDF 查找表等预计算数据需要消耗大量显存。
-
多种粗糙度与反射率的材质数据:在 PBR 模型中,对于每种材质的不同属性(例如粗糙度、金属度、折射率等),可能需要进行多次存储。
-
3. 近似方法
由于 PBR 中许多计算过程比较复杂,为了在不显著牺牲视觉效果的情况下减少性能消耗,通常会使用一些近似方法。以下是常见的近似方式:
(1) Fresnel-Schlick 近似
-
问题:Fresnel 反射的精确计算是计算密集型的。
-
近似:Schlick 近似提供了一种高效计算 Fresnel 反射的方法,显著降低了计算复杂度。通过线性插值方法来计算 Fresnel 的反射比例,可以快速获得一个接近真实反射的效果。
// Fresnel-Schlick Approximation
float FresnelSchlick(float cosTheta, float F0) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
-
这种方法比完整的 Fresnel 公式要高效得多,并且效果足够接近真实的光照反射。
(2) BRDF 查找表(BRDF Lookup Table)
-
问题:Cook-Torrance BRDF 计算复杂且开销较大。
-
近似:通过预计算不同材质属性下的 BRDF 值,并存储在查找表中。每帧渲染时,直接从查找表中获取对应的 BRDF 值,而不是重新计算。
-
示例:针对不同的粗糙度和金属度,可以预计算多个 BRDF,并将其存储为 2D 或 3D 查找表,渲染时根据材质属性快速查找。
(3) 环境光反射预计算(IBL)
-
问题:实时采样环境贴图对性能有较大消耗。
-
近似:环境光反射通常使用球谐函数(Spherical Harmonics)来进行近似,以减少计算量。
-
另外,使用 环境光映射
(4) 低精度材质计算
-
问题:每个像素级的细节计算对于复杂材质会造成性能瓶颈。
-
近似:降低材质的计算精度。例如,使用简化的反射模型(例如 Lambertian 近似)代替复杂的 Cook-Torrance 模型,或者减少环境光贴图的分辨率。
-
实时计算:虽然灵活且精确,但由于涉及大量浮点计算,尤其是光照计算和反射计算,可能会显著影响性能。
-
预计算:适用于一些不常变化的场景元素,能够显著提高渲染性能,特别是在高质量图形渲染和大型场景中。
-
近似方法:采用有效的近似计算(如 Fresnel-Schlick 近似、BRDF 查找表等)可以大幅度降低计算开销,同时保持视觉效果的高度真实感。
通过适当的预计算与近似方法,能够在保证渲染效果的同时,显著提升渲染性能,尤其是在实时图形应用(如游戏或VR)中,选择合适的策略对于保证流畅的帧率至关重要。