Unity环境贴图强度换算贴图曝光度的坑
Unity环境贴图强度换算贴图曝光度的坑
00 现象
目标效果是:
1
原 EXR + Unity Skybox/Cubemap Exposure = 1.17
希望把这个曝光效果直接烘进 EXR, 然后在 Unity 中使用:
1
处理后的 EXR + Unity Skybox/Cubemap Exposure = 1.0
一开始尝试了两种方式:
1
Blender Exposure = 1.17
结果明显曝光过度。
随后按普通曝光档位换算:
1
Blender Exposure = log2(1.17) ≈ 0.226
或者直接把 EXR 线性乘以:
1
RGB × 1.17
结果二者一致, 但都比 Unity 中 Exposure = 1.17 的效果偏暗。
01 根因
Unity 内置 Skybox/Cubemap Shader 中, _Exposure 属性是这样声明的:
1
[Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
片元阶段则是:
1
2
3
4
5
half4 tex = texCUBE(_Tex, i.texcoord);
half3 c = DecodeHDR(tex, _Tex_HDR);
c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
c *= _Exposure;
return half4(c, 1);
关键点是 [Gamma] _Exposure。
在 Linear Color Space 项目中, Inspector 上填写的 _Exposure 值不是简单原样传入 Shader 计算, 而会经过 Gamma-to-Linear 转换。
因此 Inspector 中的:
1
Exposure = 1.17
在 Shader 内部实际参与乘法的线性倍率更接近:
1
GammaToLinear(1.17) ≈ pow(1.17, 2.2) ≈ 1.41
所以 Exposure = 1.17 并不等价于 EXR 像素值乘以 1.17, 而更接近 EXR 像素值乘以 1.41。
02 正确换算
如果要把 Unity Skybox/Cubemap 材质上的 _Exposure 烘进 EXR, 应该先把 Inspector 中的 Exposure 转成线性倍率:
1
linearMultiplier = GammaToLinearSpace(unityInspectorExposure)
近似公式:
1
linearMultiplier ≈ pow(unityInspectorExposure, 2.2)
然后如果在 Blender 中使用 Exposure 节点, 还需要把线性倍率转换为 EV 曝光值:
1
blenderExposure = log2(linearMultiplier)
合并后:
1
blenderExposure = log2(GammaToLinearSpace(unityInspectorExposure))
近似为:
1
blenderExposure ≈ log2(pow(unityInspectorExposure, 2.2))
也就是:
1
blenderExposure ≈ 2.2 * log2(unityInspectorExposure)
03 本次案例
Unity 中目标值:
1
Skybox/Cubemap Exposure = 1.17
换算为线性倍率:
1
linearMultiplier ≈ pow(1.17, 2.2) ≈ 1.41
换算为 Blender Exposure:
1
blenderExposure = log2(1.41) ≈ 0.496
最终验证:
1
原 EXR + Unity Exposure = 1.17
与:
1
EXR 在 Blender 中 Exposure = 0.496 后导出 + Unity Exposure = 1.0
视觉结果一致。
04 常见错误换算
错误 1:
1
Blender Exposure = 1.17
原因: Blender Exposure 是 EV 档位, 1.17 代表约 2^1.17 ≈ 2.25 倍, 会明显过曝。
错误 2:
1
Blender Exposure = log2(1.17) ≈ 0.226
原因: 这只等价于 EXR 线性乘以 1.17, 但 Unity Shader 中 [Gamma] _Exposure 实际让 1.17 转成了约 1.41 的线性倍率, 所以结果偏暗。
05 结论
对于 Unity 内置 Skybox/Cubemap Shader:
1
[Gamma] _Exposure
意味着 Inspector 中的 Exposure 值在 Linear Color Space 下需要先做 Gamma-to-Linear 转换。
因此, 要把 Unity Skybox Exposure 烘进 EXR, 不要直接使用 Inspector 数值, 也不要只做 log2(inspectorExposure)。
应使用:
1
2
linearMultiplier = GammaToLinearSpace(unityInspectorExposure)
blenderExposure = log2(linearMultiplier)
本例中:
1
2
3
Unity Exposure 1.17
≈ EXR 线性乘以 1.41
≈ Blender Exposure 0.496
06 工程细节
Blender节点图如下:
设置好之后, 使用Render->Render Image进行出图
