在线性色彩空间使用 ImGui¶
ImGui 目前所有操作都是用非线性颜色做的,不支持线性色彩空间。1 考虑到透明混合的问题,不能直接对 ImGui 传入 Shader 的颜色去 Gamma 校正,否则 ImGui 显示的颜色和原来不一致,尤其是它的 Color Picker。
为了显示效果一致,只能让 ImGui 继续使用非线性颜色。
注意到 ImGui 只有一张 Texture,在不使用 Colorful Glyphs/Emojis 时,这张 Texture 的 RGB 全是 1,这意味着我们既可以把它当作线性颜色,也可以把它当作非线性颜色。我引擎的 Texture 在被 Shader 采样后得到的都是线性颜色,所以直接修改 ImGui 的 Pixel Shader,在 Texture 采样后加一个 Gamma 校正。这样,我引擎的 Texture 的颜色就成非线性颜色了,ImGui 的 Texture 颜色不变。
struct PS_INPUT
{
float4 pos : SV_POSITION;
float4 col : COLOR0;
float2 uv : TEXCOORD0;
};
SamplerState sampler0 : register(s0);
Texture2D texture0 : register(t0);
float LinearToSRGB1(float x)
{
return (x < 0.0031308) ? (12.92 * x) : (1.055 * pow(x, 1.0 / 2.4) - 0.055);
}
float3 LinearToSRGB3(float3 x)
{
return float3(LinearToSRGB1(x.r), LinearToSRGB1(x.g), LinearToSRGB1(x.b));
}
float4 main(PS_INPUT input) : SV_Target
{
float4 tex_col = texture0.Sample(sampler0, input.uv);
float4 out_col = input.col * float4(LinearToSRGB3(tex_col.rgb), tex_col.a);
return out_col;
}
等 ImGui 渲染完成后,再做一次去 Gamma 校正,同时 Blit 到 Back Buffer(sRGB RTV)。
void GameEditor::DrawImGuiRenderGraph(GfxDevice* device, int32_t renderTargetId)
{
auto builder = m_ImGuiRenderGraph->AddPass("DrawImGui");
GfxRenderTextureDesc desc = device->GetBackBuffer()->GetDesc();
desc.Format = m_ImGuiRtvFormat;
builder.CreateTransientTexture(renderTargetId, desc);
builder.SetRenderTargets(renderTargetId);
builder.ClearRenderTargets(ClearFlags::Color);
builder.SetRenderFunc([=](RenderGraphContext& context)
{
ImGui::Render();
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), context.GetD3D12GraphicsCommandList());
});
}
void GameEditor::BlitImGuiToBackBuffer(GfxDevice* device, int32_t srcTextureId, int32_t backBufferId)
{
auto builder = m_ImGuiRenderGraph->AddPass("BlitImGuiToBackBuffer");
builder.ImportTexture(backBufferId, device->GetBackBuffer());
builder.SetRenderTargets(backBufferId);
TextureHandle srcTexture = builder.ReadTexture(srcTextureId, ReadFlags::PixelShader);
builder.SetRenderFunc([=](RenderGraphContext& context)
{
m_BlitImGuiMaterial->SetTexture("_SrcTex", srcTexture.Get());
context.DrawMesh(GetFullScreenTriangleMesh(), m_BlitImGuiMaterial.get());
});
}
float4 c = _SrcTex.Sample(sampler_SrcTex, input.uv);
#ifdef MARCH_COLORSPACE_GAMMA
return c;
#else
return SRGBToLinear(c);
#endif
相关文章