Appearance
光照与材质
Blinn-Phong 和 Phong 区别是什么?
一句话理解
Phong 和 Blinn-Phong 都是经典光照模型,主要区别在镜面高光怎么算:Phong 比较“反射方向 R 和视线方向 V”;Blinn-Phong 比较“半程向量 H 和法线 N”。
Phong 怎么算
Phong 的镜面高光思路是:
先根据光照方向 L 和法线 N 算出反射方向 R;
再看观察方向 V 和反射方向 R 是否接近。
公式可以记成:
Specular = max(dot(R, V), 0)^shininess如果 R 和 V 越接近,说明你眼睛刚好在反射光方向上,高光越亮。
Blinn-Phong 怎么算
Blinn-Phong 不直接算反射方向,而是算半程向量 H:
H = normalize(L + V)然后比较 H 和法线 N 是否接近:
Specular = max(dot(N, H), 0)^shininess半程向量可以理解为:光照方向和视线方向中间的那个方向。 如果这个中间方向刚好接近表面法线,就说明这个点应该有高光。
核心区别
Phong:用 R dot V。 Blinn-Phong:用 N dot H。
Phong 更符合“镜面反射方向”的直觉。 Blinn-Phong 计算更方便,早期硬件上通常更快,而且在很多角度下高光更稳定。
高光效果一样吗?
不完全一样。
同样的 shininess 指数下,Phong 和 Blinn-Phong 的高光宽度通常不一样。 一般 Blinn-Phong 如果想得到接近 Phong 的高光,需要把指数调大一些。
所以不能简单认为:
Phong shininess = Blinn shininess它们参数不是严格等价的。
它们和 PBR 的关系
Phong 和 Blinn-Phong 都是经验模型。 它们能做出“看起来像高光”的效果,但不是严格基于物理的光照模型。
现代游戏里,如果追求真实感,更多会用 PBR,比如基于:
粗糙度;
金属度;
法线分布函数;
菲涅尔;
几何遮蔽。
但 Phong / Blinn-Phong 在教学、低成本风格化渲染、简单材质里仍然很好用。
面试高分说法
NOTE
Phong 和 Blinn-Phong 的漫反射部分通常都可以用 Lambert,主要区别在镜面高光。Phong 先算反射向量 R,再用 dot(R, V) 判断观察方向是否接近反射方向;Blinn-Phong 算的是光照方向和观察方向的半程向量 H,再用 dot(N, H) 判断半程向量是否接近法线。Blinn-Phong 通常计算更方便,也更稳定,但同样的高光指数下两者高光范围不同,参数不能直接等价。两者都属于传统经验光照模型,不是严格 PBR。
漫反射和高光分别是什么?
一句话理解
漫反射决定“物体本身被照亮后的颜色和明暗”;高光决定“表面反光形成的亮斑”。简单说:漫反射看光照到表面多少,高光看反射光有没有进入眼睛。
漫反射是什么?
漫反射 Diffuse 可以理解为:光打到粗糙表面后,被往很多方向散开。
比如墙、纸、布、粉笔,它们没有特别明显的亮斑,但是会根据光照角度变亮或变暗。
常见 Lambert 漫反射公式:
Diffuse = Albedo * max(dot(N, L), 0)这里:
Albedo 是物体本色;
N 是表面法线;
L 是指向光源的方向;
dot(N, L) 表示表面有多“正对”光源。
如果表面正对光源,dot(N, L) 大,物体更亮。 如果表面背对光源,dot(N, L) 小甚至小于 0,就很暗。
高光是什么?
高光 Specular 可以理解为:光照到比较光滑的表面后,沿着接近镜面反射的方向反出去,刚好被眼睛或相机看到,就形成亮斑。
比如金属、塑料、玻璃、湿地面,通常会有明显高光。
Phong 高光常见公式:
Specular = pow(max(dot(R, V), 0), shininess)这里:
R 是反射方向;
V 是观察方向;
shininess 控制高光集中程度。
shininess 越大,高光越小越锐利; shininess 越小,高光越大越柔和。
Blinn-Phong 里常用半程向量:
H = normalize(L + V)然后:
Specular = pow(max(dot(N, H), 0), shininess)它们最大的区别
漫反射主要和光照方向、表面法线、物体本色有关。 高光除了和光照方向、法线有关,还强烈依赖观察方向。
所以相机移动时:
漫反射通常不会明显跟着跑;
高光会在物体表面移动。
这就是你在游戏里转动相机时,金属、塑料、水面上的亮斑会动的原因。
美术上怎么理解
漫反射像是在回答:这个物体是什么颜色?被照得有多亮?
高光像是在回答:这个物体表面有多光滑?反光强不强?有没有油亮、金属、湿润的感觉?
面试高分说法
NOTE
漫反射是光照射到粗糙表面后向各个方向散射形成的亮度,常用 Lambert 模型,用 dot(N, L) 表示表面朝向光源的程度,它主要决定物体的基础明暗和颜色。高光是光在较光滑表面上发生方向性反射形成的亮斑,Phong 模型用 dot(R, V),Blinn-Phong 用 dot(N, H) 来计算,它和观察方向强相关,能表现材质的光滑程度、金属感和反光感。
环境光有什么作用?
一句话理解
环境光 Ambient Light 的作用是:给场景一个基础亮度和基础颜色,模拟现实中天空、墙面、地面反弹来的间接光,避免没有被直接光照到的地方变成一片死黑。
为什么需要环境光?
如果只算直接光,比如方向光、点光源、聚光灯,那么背光面可能非常黑。
现实里不会这样极端,因为光会在环境中反弹:
阳光照到地面,地面会反射一部分光;
天空本身会提供蓝色的散射光;
墙面会把自己的颜色轻微反射到附近物体上。
环境光就是用一个低成本方式近似这种“到处都有一点点的间接光”。
传统光照里怎么理解
一个简单光照模型可以写成:
最终颜色 = 环境光 + 漫反射 + 高光其中:
漫反射负责物体被主光照亮的明暗;
高光负责表面反光亮斑;
环境光负责暗部基础亮度。
如果没有环境光,背光面可能接近黑色。 如果有环境光,暗部还能保留一些颜色和形体。
环境光主要作用
第一,防止暗部死黑。 角色背面、墙角、阴影区域不会完全丢细节。
第二,模拟间接光。 它不是真正计算光线反弹,而是用便宜的方式近似。
第三,统一画面氛围。 偏蓝的环境光会有夜晚、天空感;偏暖的环境光会有夕阳、室内灯光感。
第四,辅助材质表现。 没有环境光时,很多材质在暗部看不出颜色;有环境光后,物体本色更容易被看到。
环境光不能替代什么?
环境光不能替代主光源。 因为它通常没有明确方向,所以不能产生清晰的投影,也不能塑造强烈的立体感。
如果环境光太强,会出现一个问题:画面变平。 阴影被冲淡,角色和场景的体积感下降,画面像“糊了一层亮灰”。
现代渲染里环境光更高级
在传统模型里,环境光可能只是一个固定颜色:
Ambient = AmbientColor * Albedo但在现代 PBR 里,环境光经常会变成更真实的间接光方案,比如:
IBL,基于环境贴图的光照;
GI,全局光照;
Light Probe,给动态物体采样周围间接光;
Reflection Probe,提供环境反射;
Ambient Occlusion,压暗缝隙和接触区域,避免环境光把所有角落照得一样亮。
面试高分说法
TIP
环境光的作用是近似间接光照,给没有被直接光源照到的区域提供基础亮度,避免暗部完全死黑,同时还能统一场景色调。它通常没有明确方向,所以不能产生清晰阴影,也不能替代方向光、点光源等直接光。环境光过弱会丢暗部细节,过强会让画面变平、缺少体积感。现代渲染中,环境光往往不只是一个常量颜色,而会结合 IBL、GI、Light Probe、Reflection Probe 和 AO 来获得更自然的间接照明效果。
Gamma 空间和 Linear 空间区别是什么?
一句话理解
Gamma 空间更像“给人眼和显示器看的颜色编码”;Linear 空间更像“真实光强数值”。 渲染里更推荐:贴图按 Gamma/sRGB 存储,光照计算转到 Linear,最后输出到屏幕前再转回 Gamma/sRGB。
Gamma 空间是什么?
人眼对暗部变化更敏感,对亮部变化相对没那么敏感。 所以很多图片格式和显示系统会用非线性方式存颜色,也就是 Gamma/sRGB 编码。
大概可以理解成:
屏幕颜色 = 线性光强 ^ (1 / 2.2)反过来:
线性光强 = 屏幕颜色 ^ 2.2所以在 Gamma/sRGB 里,数值 0.5 并不代表真实光强的一半。 它大概只对应 0.214 左右的线性光强。
Linear 空间是什么?
Linear 空间里的颜色值和真实光强成线性关系。
也就是说:
0.2 + 0.2 = 0.4这在物理意义上是合理的。 光照、阴影、混合、插值、PBR 这些计算,本质都应该基于真实光强,所以应该在线性空间里算。
为什么 Gamma 空间直接算光会有问题?
因为 Gamma 值不是线性光强。
比如两个颜色做混合,如果你直接在 Gamma 空间平均,得到的亮度不是物理正确的平均光强。 所以会出现画面偏灰、偏亮、过渡不自然、光照不真实的问题。
尤其这些操作很容易受影响:
灯光叠加;
透明混合;
颜色插值;
阴影衰减;
PBR 光照;
后处理中的亮度计算。
Unity 里怎么理解
Unity 里项目可以选择 Gamma 或 Linear Color Space。
Gamma 模式: 兼容性好,旧项目常见,低端设备历史上更友好。
Linear 模式: 光照更真实,PBR 材质更准确,现代项目更推荐。
在 Linear 工作流里,Unity 通常会做这件事:
读取 sRGB 颜色贴图时,把它解码到 Linear;
在线性空间里做光照计算;
最后输出到屏幕时,再编码回 sRGB/Gamma。
贴图设置很重要
颜色贴图,比如 Albedo、BaseMap,通常应该勾选 sRGB。 因为它们是给人看的颜色数据。
但数据贴图通常不应该勾选 sRGB,比如:
法线贴图;
金属度贴图;
粗糙度贴图;
AO 贴图;
Mask 贴图;
高度图。
因为这些不是颜色,而是数值数据。 如果错误地做 Gamma 转换,数值就变了,效果会不对。
面试高分说法
IMPORTANT
Gamma 空间是为了适配人眼感知和显示设备的非线性颜色编码,sRGB 贴图通常就是 Gamma 编码;Linear 空间表示真实线性光强,更适合做光照、混合、插值和 PBR 计算。正确流程一般是:颜色贴图从 sRGB 解码到 Linear,在线性空间里进行光照计算,最后输出到屏幕前再编码回 sRGB。Unity 中颜色贴图通常开启 sRGB,而法线、金属度、粗糙度、AO、Mask 等数据贴图不应该当颜色做 sRGB 转换。Gamma 模式兼容性好,但 Linear 模式的光照更符合物理规律。
HDR 是什么?
一句话理解
HDR 是 High Dynamic Range,高动态范围。渲染里它表示:颜色亮度可以超过普通 0 到 1 的范围,先保留强光信息,再通过曝光、Bloom、Tone Mapping 映射到屏幕上。
LDR 是什么
LDR 是低动态范围,颜色通常限制在 0 到 1。
比如:
0 表示黑色;
1 表示最亮白色。
如果一个光照结果算出来是 3.0,LDR 会直接把它截断成 1.0。 这样 1.5、3.0、10.0 最后都可能变成一样的白色,亮部细节就没了。
HDR 是什么
HDR 允许渲染中间结果超过 1.0。
比如:
太阳附近亮度可以是 10.0;
火焰可以是 5.0;
普通墙面可能是 0.6。
这样渲染管线能知道:“这里不是普通白,而是真的很亮。”
这对后处理非常重要。
为什么 HDR 经常和 Bloom 一起出现
Bloom 泛光通常会提取特别亮的区域,让它向周围扩散,形成发光效果。
如果是 LDR:
亮度超过 1.0 的信息已经被截断;
后处理不知道哪里是 1.2,哪里是 10.0;
Bloom 效果容易不自然。
如果是 HDR:
强光信息还在;
Bloom 可以只提取真正超过阈值的亮部;
火焰、太阳、魔法特效、霓虹灯会更有发光感。
Tone Mapping 是什么
屏幕最终还是有显示范围的。 哪怕渲染中有 10.0 的亮度,也不能直接原样显示。
所以需要 Tone Mapping,把 HDR 的大亮度范围压缩回屏幕能显示的范围。
你可以把它理解成相机曝光:
太亮的地方压下来;
暗部尽量保留;
让画面看起来既有层次,又不会整片过曝。
HDR 的代价
HDR 不是免费的。
它通常需要更高精度的 RenderTexture,比如浮点格式。 这会增加:
显存占用;
内存带宽;
后处理成本;
移动端发热和耗电风险。
所以移动端项目不能无脑开 HDR,要看画面收益和性能预算。
Unity 里怎么理解
Unity 中开启 Camera HDR 或管线 HDR 后,场景会先渲染到 HDR 缓冲里。 然后经过 Bloom、Color Grading、Tone Mapping 等后处理,最后输出到屏幕。
注意: HDR 渲染不等于玩家一定使用 HDR 显示器。 即使是普通 SDR 屏幕,HDR 渲染也可以通过 Tone Mapping 和 Bloom 让画面更自然。
面试高分说法
TIP
HDR 是高动态范围渲染,它允许渲染过程中的颜色亮度超过 0 到 1,从而保留强光区域的真实亮度差异。LDR 会把超过 1 的值截断,导致亮部细节丢失;HDR 会先把这些超亮信息保留下来,用于 Bloom、曝光、Color Grading 等后处理,最后通过 Tone Mapping 压缩到屏幕可显示范围。HDR 能提升亮部层次和发光效果,但会增加 RenderTexture 精度、显存和带宽成本,移动端要谨慎开启。
Tone Mapping 是什么?
一句话理解
Tone Mapping 是把 HDR 渲染出来的高亮度范围,压缩映射到屏幕能显示的范围。它不是简单把超过 1 的颜色砍掉,而是用一条曲线把暗部、中间调、亮部重新分配,让画面既不过曝,又保留层次。
为什么需要 Tone Mapping
HDR 渲染里,颜色亮度可能超过 1。
比如:
太阳:10.0
火焰:5.0
金属高光:2.0
普通墙面:0.6
但普通屏幕最终显示范围有限。 如果直接 clamp 到 0 到 1,那么 2.0、5.0、10.0 都会变成 1.0,结果就是亮部一片白,细节全没了。
Tone Mapping 的作用就是: 把这些超亮值压下来,但尽量保留谁更亮、谁更暗的关系。
它大概做了什么
渲染流程可以理解成:
HDR 场景颜色 -> 曝光调整 -> Tone Mapping 曲线 -> Gamma/sRGB 输出 -> 屏幕其中 Tone Mapping 负责从“大范围亮度”变成“屏幕可显示亮度”。
它像相机或胶片的响应曲线:
暗部不要太死黑;
中间调保持自然;
高光不要直接炸白;
整体画面要有可看的对比度。
常见 Tone Mapping 类型
Reinhard: 简单、柔和,经典公式类似:
color = color / (color + 1)它会自然把很大的值压到 1 以下。
Filmic: 模拟胶片响应,亮部压缩比较自然,常用于电影感画面。
ACES: 现在游戏引擎里很常见,亮部和色彩表现更有电影感。Unity、Unreal 里都经常看到 ACES 风格的 Tone Mapping。
Neutral: 更偏中性,不想让画面有太强电影调色感时可以用。
Tone Mapping 和 Bloom 区别
Bloom 是泛光。 它负责让特别亮的区域向周围扩散,形成发光效果。
Tone Mapping 是亮度映射。 它负责把 HDR 的大亮度范围压到屏幕可显示范围。
两者经常一起出现,但不是一回事。
通常流程是:
先在 HDR 中找到高亮区域做 Bloom;
再把原画面加上 Bloom;
最后做 Tone Mapping 输出。
Unity 里怎么理解
在 Unity 的 URP/HDRP 或 Post Processing 中,Tonemapping 常见选项有 None、Neutral、ACES。
None:不做明显映射,亮部可能更容易硬。
Neutral:比较中性,适合不想大幅改变颜色风格的项目。
ACES:电影感更强,亮部压缩和色彩观感更好,但可能改变整体色彩倾向。
面试高分说法
NOTE
Tone Mapping 是 HDR 渲染到显示设备之间的一步映射过程。因为 HDR 场景颜色可以超过 0 到 1,而屏幕显示范围有限,如果直接截断会导致高光细节丢失,所以 Tone Mapping 会用一条非线性曲线把大范围亮度压缩到可显示范围,同时尽量保留暗部、中间调和亮部层次。它常和曝光、Bloom、Color Grading 一起使用。Bloom 是泛光效果,Tone Mapping 是亮度范围映射,两者不要混为一谈。
IBL 是什么?
一句话理解
IBL 是 Image Based Lighting,基于图像的光照。它的核心是:用一张环境贴图记录周围世界的光照信息,然后用这张图来给物体提供间接光和环境反射。
IBL 不是单纯的天空盒
天空盒只是“看起来像背景”。 IBL 是把环境贴图真的拿来参与光照计算。
比如一个金属球放在蓝天黄土地的环境里,它表面会反射蓝天和地面的颜色。 这不是普通方向光能做出来的,需要环境信息。
IBL 主要做两件事
第一,提供间接漫反射。
粗糙表面会接收来自周围很多方向的光。 比如墙面、角色衣服、地面,它们不会像镜子一样清晰反射环境,但会被环境颜色影响。
常见做法是用 Irradiance Map,也就是把环境贴图卷积成低频的漫反射环境光。
第二,提供间接高光反射。
光滑表面会反射周围环境。 越光滑,反射越清晰;越粗糙,反射越模糊。
常见做法是用 Prefiltered Environment Map。 不同粗糙度对应不同 mip 级别,粗糙度越高,采样越模糊的 mip。
PBR 里 IBL 为什么重要
PBR 材质不只需要直接光,还需要环境间接光。
最终大概可以理解成:
最终光照 = 直接光 + IBL 漫反射 + IBL 高光反射如果没有 IBL:
金属会很黑;
暗部缺少环境颜色;
光滑物体没有真实反射;
材质很难融入场景。
有了 IBL 后,物体会更像“真的放在这个环境里”。
为什么 IBL 要预计算
理论上,一个点受到环境光影响时,要从半球很多方向采样环境贴图。 如果每个像素实时采样很多方向,太贵。
所以通常提前准备几张东西:
Irradiance Map:给漫反射用,模糊、低频。
Prefiltered Environment Map:给高光反射用,不同 mip 表示不同粗糙度。
BRDF LUT:把视角、粗糙度等部分计算预存成查找表。
这样运行时就能用少量贴图采样得到比较真实的环境光。
Unity 里怎么对应
Unity 里常见相关概念:
Skybox:环境来源之一。
Reflection Probe:采样环境反射,给金属、光滑表面使用。
Light Probe:给动态物体提供间接光信息。
Ambient Lighting:基础环境光设置。
URP/HDRP 的 PBR Shader:会结合这些数据计算环境漫反射和环境高光。
IBL 的代价
IBL 效果好,但不是免费。
环境贴图会占显存;
预过滤 mip 会增加贴图数据;
Reflection Probe 如果实时刷新,会有渲染成本;
多个探针混合也会增加复杂度。
移动端项目里,通常会控制反射探针数量、分辨率和刷新频率。
面试高分说法
IMPORTANT
IBL 是基于图像的光照,它使用环境贴图或探针记录周围环境的亮度和颜色,用来模拟间接光照和环境反射。PBR 中 IBL 通常分为两部分:漫反射部分使用卷积后的 Irradiance Map,高光反射部分使用预过滤的环境贴图和 BRDF LUT。它能让物体受到环境色影响,也能让金属、玻璃、水面等光滑材质反射周围世界。相比普通环境光,IBL 包含方向、颜色和亮度变化,效果更真实,但会增加贴图内存、探针更新和采样成本。
BRDF 是什么?
一句话理解
BRDF 是 Bidirectional Reflectance Distribution Function,双向反射分布函数。它描述的是:一束光从某个方向照到材质表面后,有多少光会被反射到观察方向。
BRDF 解决什么问题
同样一束光照到不同材质上,表现完全不同。
粉笔、布料:光会向很多方向散开,主要表现为漫反射。 金属、玻璃、湿地面:光会更集中地反射,产生明显高光。 粗糙塑料:既有漫反射,也有比较宽的高光。
BRDF 就是用数学函数描述这些“材质如何反射光”的规则。
可以简单记成:
BRDF = f(N, L, V, Material)其中:
N 是表面法线;
L 是光照方向;
V 是观察方向;
Material 是材质参数,比如粗糙度、金属度、基础颜色。
它和最终颜色的关系
BRDF 本身不是最终颜色。 它是渲染方程中的一部分。
最终光照大概可以理解成:
出射光 = 入射光 * BRDF * NdotL也就是说:
光有多强;
光从哪个方向来;
表面朝不朝向光;
材质怎么反射光;
这些一起决定最后你看到的颜色。
漫反射 BRDF
最经典的是 Lambert 漫反射。
它认为光打到粗糙表面后,会比较均匀地向各个方向散开。
常见形式:
DiffuseBRDF = Albedo / PI这里 Albedo 是物体基础颜色。 除以 PI 是为了能量守恒,让反射出去的总能量不会凭空变多。
镜面反射 BRDF
镜面反射描述高光和反射。
传统模型里可能用 Phong 或 Blinn-Phong。 现代 PBR 里更常用 Cook-Torrance 微表面模型。
它的大概形式是:
SpecularBRDF = D * F * G / (4 * NdotL * NdotV)这三个字母很重要:
D:Normal Distribution Function,法线分布函数。 描述微小表面朝向是否集中。粗糙度越低,微表面越整齐,高光越小越亮。
F:Fresnel,菲涅尔项。 描述不同观察角度下反射强度变化。视线越接近掠射角,反射越强。
G:Geometry,几何遮蔽项。 描述微表面之间互相遮挡、互相阴影的情况。
粗糙度怎么影响 BRDF
粗糙度低: 微表面排列更整齐,反射方向更集中,高光小而亮。
粗糙度高: 微表面方向更乱,反射被分散,高光大而暗。
所以粗糙度不是简单让物体“变暗”,而是改变反射能量的分布方式。
金属度怎么影响 BRDF
非金属: 通常有明显漫反射,镜面反射颜色偏白。
金属: 漫反射很弱甚至没有,反射颜色会被金属本身颜色染色。
这就是为什么金、铜这类金属的反光会带颜色,而普通塑料的高光更接近白色。
面试高分说法
NOTE
BRDF 是双向反射分布函数,用来描述材质表面如何把某个入射方向的光反射到某个观察方向。它是 PBR 光照计算的核心,输入通常包括法线、光照方向、观察方向和材质参数。传统模型里有 Lambert、Phong、Blinn-Phong;现代 PBR 常用 Cook-Torrance 微表面 BRDF,把镜面反射拆成 D、F、G 三项:法线分布、菲涅尔和几何遮蔽。一个合理的 BRDF 应该满足能量守恒,不能让反射光能量超过入射光。
Metallic/Roughness 工作流是什么?
一句话理解
Metallic/Roughness 是 PBR 常用材质工作流:用 Metallic 决定材质像不像金属,用 Roughness 决定表面反射是清晰还是模糊。
Metallic 是什么
Metallic 金属度一般是 0 到 1。
0 表示非金属,比如木头、布料、石头、塑料。 1 表示金属,比如铁、金、铜、铝。
非金属通常有明显漫反射,物体本色主要来自 BaseColor。 金属几乎没有漫反射,主要靠镜面反射表现,而且反射颜色会被 BaseColor 染色。
所以同样一张 BaseColor,在非金属和金属里含义不完全一样:
非金属:BaseColor 更像表面本色。 金属:BaseColor 更像反射颜色。
Roughness 是什么
Roughness 粗糙度一般也是 0 到 1。
0 表示非常光滑,反射清晰,高光小而亮。 1 表示非常粗糙,反射模糊,高光大而暗。
它的底层含义是:微表面法线分布有多乱。
表面越光滑,微表面越整齐,反射方向越集中。 表面越粗糙,微表面越杂乱,反射方向越分散。
所以粗糙度不是简单地让材质“变暗”,而是改变反射能量的分布。
工作流里常见贴图
BaseColor:基础颜色。 Metallic:金属度。 Roughness:粗糙度。 Normal:法线贴图,改变表面细节方向。 AO:环境遮蔽,压暗缝隙和接触区域。 Emission:自发光。
这些输入进入 PBR BRDF 后,再结合直接光和 IBL,得到最终材质表现。
Unity 里的重点坑
Unity 很多管线里更常说 Smoothness,而不是 Roughness。
它们是反过来的:
Smoothness = 1 - Roughness所以:
粗糙度高,Smoothness 低。 粗糙度低,Smoothness 高。
如果美术给的是 Roughness 贴图,但 Shader 需要 Smoothness,就要反相处理。 这个在 Unity 项目里很常见。
贴图通道也要注意
很多项目会把贴图合并到不同通道里,比如:
Metallic 放 R 通道;
AO 放 G 通道;
Roughness 或 Smoothness 放 A 通道。
具体怎么放没有绝对统一标准,要看项目和 Shader 约定。
还有一点很重要: Metallic、Roughness、AO、Mask 这类是数据贴图,不是颜色贴图,通常不要按 sRGB 做颜色转换。
面试高分说法
IMPORTANT
Metallic/Roughness 是 PBR 中常见的材质描述方式。Metallic 决定材质是非金属还是金属:非金属主要有漫反射,镜面高光通常偏白;金属几乎没有漫反射,主要靠镜面反射表现,并且反射颜色会被 BaseColor 染色。Roughness 决定微表面法线分布的分散程度,粗糙度越低,高光越锐利、反射越清晰;粗糙度越高,高光越宽、反射越模糊。Unity 里常用 Smoothness,它和 Roughness 是反向关系,也就是 Smoothness = 1 - Roughness。
法线贴图为什么通常偏蓝?
一句话理解
法线贴图通常偏蓝,是因为最常见的切线空间法线贴图里,平坦表面的默认法线大约是 (0, 0, 1),编码成 RGB 后就是 (0.5, 0.5, 1.0),也就是接近 (128, 128, 255),蓝色通道最大。
法线贴图不是普通颜色图
法线贴图里的 RGB 不是在表达“这个地方是什么颜色”,而是在表达“这个像素的表面朝向”。
也就是说:
R 通道通常表示 X 方向;
G 通道通常表示 Y 方向;
B 通道通常表示 Z 方向。
它是一张数据贴图,不是颜色贴图。
为什么会偏蓝
法线方向本来是一个三维向量,范围通常是 -1 到 1。
但贴图颜色通道一般是 0 到 1,所以需要编码:
RGB = Normal * 0.5 + 0.5对于一个平坦表面,它在切线空间里的默认法线通常是:
Normal = (0, 0, 1)代入公式:
R = 0 * 0.5 + 0.5 = 0.5
G = 0 * 0.5 + 0.5 = 0.5
B = 1 * 0.5 + 0.5 = 1.0所以得到:
RGB = (0.5, 0.5, 1.0)换成 8 位颜色就是:
(128, 128, 255)这就是一种偏蓝紫色的颜色。
为什么蓝色通道通常最大
因为大多数表面的小凹凸不会让法线完全倒向侧面。 它们只是稍微往左、右、上、下偏一点,但整体仍然朝着表面外侧,也就是切线空间的 +Z。
所以:
红色 R 表示左右偏移,通常在 0.5 附近波动;
绿色 G 表示上下偏移,通常在 0.5 附近波动;
蓝色 B 表示朝外程度,通常接近 1。
于是整张法线贴图看起来就偏蓝。
是不是所有法线贴图都偏蓝?
不是。
偏蓝的一般是切线空间法线贴图,也就是游戏里最常见的那种。 如果是对象空间法线贴图或世界空间法线贴图,颜色可能会更花,不一定整体偏蓝。
Unity 里的注意点
Unity 里法线贴图要标记为 Normal Map。 引擎会按法线数据去解码,而不是按普通颜色图处理。
还有一个常见坑: DirectX 和 OpenGL 对绿色通道方向的约定可能不同。 所以有些法线贴图导入后,凹凸方向反了,就需要翻转 G 通道。
面试高分说法
IMPORTANT
法线贴图通常偏蓝,是因为游戏里最常用的是切线空间法线贴图。平坦表面的默认法线方向是 (0,0,1),而贴图 RGB 只能存 0 到 1,所以会把法线从 [-1,1] 编码到 [0,1],公式是 RGB = Normal * 0.5 + 0.5。这样 (0,0,1) 会变成 (0.5,0.5,1),也就是约等于 (128,128,255),蓝色通道最大。R 和 G 表示切线平面内的偏移,B 表示朝外方向,所以大多数切线空间法线贴图看起来都是蓝紫色。