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 手动控制。

具体改动点:

  1. Backbuffer 格式变更

D3D11Swapchain.cpp:759-764, ContextGLES.cpp:92-97, AndroidDisplayManagerGLES.cpp:457-463 — 当 runtimeBackbufferNoSRGB == true 时,backbuffer 强制使用 R8G8B8A8_UNorm 而非 sRGB 格式。

  1. Camera::SetupRender 中移除了 per-camera 的 SetSRGBWrite

Camera.cpp:801-805: #if !DRAW_UI_SRGB bool linearLighting = GetActiveColorSpace() == kLinearColorSpace; device.SetSRGBWrite(linearLighting); #endif 原来每个 Camera setup 时都会设置 SetSRGBWrite,现在被移除了。

  1. 改为在 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。

  1. 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 的格式并没有被这套改动覆盖。

具体来说:

  1. RenderTexture 格式不匹配:backbuffer 被改成了 UNorm,但你的离屏 RT 很可能仍然是 sRGB 格式(Unity 在 Linear 空间下创建 RT 的默认行为)。
  2. SetSRGBWrite(true) + sRGB RT = 硬件自动做 Linear→sRGB 转换:在 Submit() 中全局设了 SetSRGBWrite(true),当渲染目标是 sRGB 格式的 RT 时,GPU 会自动做 Linear→sRGB 转换。
  3. UI 顶点色已经是 Gamma 空间:因为 VertexColorAlwaysGammaSpace = true,UI 的顶点色没有被转到 Linear。这些 Gamma 值经过 Shader 后输出,再被 GPU 做一次 Linear→sRGB 转换 → 双重 Gamma,颜色变暗。
  4. Alpha Blend 在 sRGB RT 上是在 Linear 空间做的:GPU 会先把 framebuffer 中的 sRGB 值转成 Linear,再做混合,再转回 sRGB。但因为源颜色已经被双重 Gamma 了,混合结果自然是错的。

如果你的离屏 RT 是 UNorm 格式,那问题可能不同:SetSRGBWrite(true) 在 UNorm RT 上是 no-op(D3D11 下),混合在 Gamma 空间进行,但 3D 内容输出的是 Linear 值(没有被转换),混合也会不正确。


建议排查方向

  1. 确认离屏 RT 的格式:检查你的 3D Camera 的 targetTexture 是 sRGB 还是 UNorm。这决定了问题的具体表现。
  2. 最直接的修复思路:在离屏渲染路径中,需要根据 RT 格式正确设置 SetSRGBWrite。当前的实现是在 Submit() 中一刀切,没有区分渲染目标是 backbuffer 还是离屏 RT。可以考虑: - 在 Camera::SetupRender 中恢复 per-camera 的 SetSRGBWrite 逻辑,但仅在渲染到非 backbuffer 目标时生效 - 或者让 SetOverrideSRGBWrite 在 C# 层根据当前 camera 的 target 动态调整
  3. 如果你能控制 RT 创建:尝试把离屏 RT 也改成 UNorm 格式(与 backbuffer 一致),看 alpha blend 是否恢复正常。这能快速验证是否是格式不匹配导致的。