UI SRGB 1
DRAW UI SRGB 改动分析 这个宏改动的核心思路是:把 backbuffer 从 sRGB 格式改为 UNorm 格式,sRGB 转换不再由硬件自动完成,而是由引擎/Shader 手动控制。 具体改动点: 1. Backbuffer 格式变更 D3D11Swapchain.cpp:759 764, ContextGLES.cpp:92 97, AndroidDisplayManagerGL…
DRAW_UI_SRGB 改动分析
这个宏改动的核心思路是:把 backbuffer 从 sRGB 格式改为 UNorm 格式,sRGB 转换不再由硬件自动完成,而是由引擎/Shader 手动控制。
具体改动点:
- Backbuffer 格式变更
D3D11Swapchain.cpp:759-764, ContextGLES.cpp:92-97, AndroidDisplayManagerGLES.cpp:457-463 — 当 runtimeBackbufferNoSRGB == true 时,backbuffer 强制使用 R8G8B8A8_UNorm 而非 sRGB 格式。
- Camera::SetupRender 中移除了 per-camera 的 SetSRGBWrite
Camera.cpp:801-805: #if !DRAW_UI_SRGB bool linearLighting = GetActiveColorSpace() == kLinearColorSpace; device.SetSRGBWrite(linearLighting); #endif 原来每个 Camera setup 时都会设置 SetSRGBWrite,现在被移除了。
- 改为在 Submit() 中全局设置一次
ScriptableRenderContext.cpp:1605-1614: void ScriptableRenderContext::Submit() { #if DRAW_UI_SRGB ChangeSRGBWrite(); // device.SetSRGBWrite(m_OverrideSRGBWrite) #endif ExecuteScriptableRenderLoop(); #if DRAW_UI_SRGB RestoreSRGBWrite(); // 恢复旧值 #endif } m_OverrideSRGBWrite 默认值是 GetActiveColorSpace() == kLinearColorSpace,即 Linear 空间下为 true。
- Canvas 顶点色处理
Canvas.cpp:168-170 — m_VertexColorAlwaysGammaSpace 被设为 runtimeBackbufferNoSRGB,意味着 UI 顶点色保持 Gamma 空间,不做 Gamma→Linear 转换。
你的离屏渲染问题根因
你的场景:3D Camera → RenderTexture(离屏)→ Overlay UI Camera 渲染 3D Canvas。
核心问题在于:DRAW_UI_SRGB 的设计是针对 backbuffer(UNorm)的,但离屏 RenderTexture 的格式并没有被这套改动覆盖。
具体来说:
- RenderTexture 格式不匹配:backbuffer 被改成了 UNorm,但你的离屏 RT 很可能仍然是 sRGB 格式(Unity 在 Linear 空间下创建 RT 的默认行为)。
- SetSRGBWrite(true) + sRGB RT = 硬件自动做 Linear→sRGB 转换:在 Submit() 中全局设了 SetSRGBWrite(true),当渲染目标是 sRGB 格式的 RT 时,GPU 会自动做 Linear→sRGB 转换。
- UI 顶点色已经是 Gamma 空间:因为 VertexColorAlwaysGammaSpace = true,UI 的顶点色没有被转到 Linear。这些 Gamma 值经过 Shader 后输出,再被 GPU 做一次 Linear→sRGB 转换 → 双重 Gamma,颜色变暗。
- Alpha Blend 在 sRGB RT 上是在 Linear 空间做的:GPU 会先把 framebuffer 中的 sRGB 值转成 Linear,再做混合,再转回 sRGB。但因为源颜色已经被双重 Gamma 了,混合结果自然是错的。
如果你的离屏 RT 是 UNorm 格式,那问题可能不同:SetSRGBWrite(true) 在 UNorm RT 上是 no-op(D3D11 下),混合在 Gamma 空间进行,但 3D 内容输出的是 Linear 值(没有被转换),混合也会不正确。
建议排查方向
- 确认离屏 RT 的格式:检查你的 3D Camera 的 targetTexture 是 sRGB 还是 UNorm。这决定了问题的具体表现。
- 最直接的修复思路:在离屏渲染路径中,需要根据 RT 格式正确设置 SetSRGBWrite。当前的实现是在 Submit() 中一刀切,没有区分渲染目标是 backbuffer 还是离屏 RT。可以考虑: - 在 Camera::SetupRender 中恢复 per-camera 的 SetSRGBWrite 逻辑,但仅在渲染到非 backbuffer 目标时生效 - 或者让 SetOverrideSRGBWrite 在 C# 层根据当前 camera 的 target 动态调整
- 如果你能控制 RT 创建:尝试把离屏 RT 也改成 UNorm 格式(与 backbuffer 一致),看 alpha blend 是否恢复正常。这能快速验证是否是格式不匹配导致的。