Shader光照原理:RGB相乘的物理推导与实践
开场上周在调试一个角色皮肤的渲染效果时,美术反馈"红色光源打在大理石地板上,地板泛着奇怪的橙色"。我盯着屏幕上怪异的色块,脑子里的第一反应是:Unity 不是把光的颜色和物体颜色直接乘起来就行了吗?翻出 shader 代码,漫反射那行赫然写着diffuse = lightColor * albedo * NdotL,逻辑上没问题,数学上也是对的,可实际渲染结果就是不对劲。折腾了一下午才搞清楚:项目在线性空间(Linear)下工作,而那张贴图在导入时没有勾选 sRGB,采样出来的值没有经过解码,直接参与了乘法——相乘本身没错,乘的空间错了,某些波段的能量被悄悄放大或缩小。这类问题在 PBR 流程里几乎每次都会遇到,根源都是同一个:大多数教程只教你"这行乘法这么写",却很少有人系统地讲过——光的颜色凭什么能和物体颜色直接相乘?这行代码对应的真实物理过程是什么?它的适用边界在哪?这篇文章就按物理到工程的顺序把这件事从头梳理一遍:先讲 RGB 相乘的物理依据(为什么乘法是对的),再讲它的近似边界(什么时候乘法会撒谎),然后是线性空间这个最大的工程坑,最后落到 albedo 制作规范和性能实践。一、物理推导:RGB 相乘凭什么成立1.1 真实物理:光谱 × 反射率真实世界里没有"RGB 颜色"这种东西。一束光的本体是光谱功率分布(Spectral Power Distribution)——每个波长上携带多少能量,是一条连续曲线 L(λ)。物体表面的颜色也不是 RGB,而是光谱反射率曲线