ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.44k stars 10.13k forks source link

Used color space (sRGB vs Linear) #1724

Open matt77hias opened 6 years ago

matt77hias commented 6 years ago

Based on the vertex structure used,

struct ImDrawVert 
{
    ImVec2  pos;
    ImVec2  uv;
    ImU32   col;
};

I assume that col represents a color in sRGB color space (i.e. not in linear color space)?

Since these vertex structures aren't modified and sent straight to the actual vertex buffer, and since the D3D11 vertex layout is the following:

D3D11_INPUT_ELEMENT_DESC local_layout[] = {
            { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT,   0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
            { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,   0, (size_t)(&((ImDrawVert*)0)->uv),  D3D11_INPUT_PER_VERTEX_DATA, 0 },
            { "COLOR",    0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
        };

I assume that the color attribute of a vertex is still expressed in sRGB color space?

Based on the exemplar D3D11 pixel shader used,

static const char* pixelShader =
            "struct PS_INPUT\
            {\
            float4 pos : SV_POSITION;\
            float4 col : COLOR0;\
            float2 uv  : TEXCOORD0;\
            };\
            sampler sampler0;\
            Texture2D texture0;\
            \
            float4 main(PS_INPUT input) : SV_Target\
            {\
            float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
            return out_col; \
            }";

I assume all intermediate calculations occur in sRGB color space and sRGB colors are written to a non-sRGB RTV?

If all of the above questions are answered with "yes" and I want to work in a linear color space instead, is it just necessary (and efficient) to:

ocornut commented 6 years ago

I don't have your answers right now, and perhaps surprisingly I am not the best person to answer. Looking at it from a casual distance, the subtleties and wording involved in srgb/linear space discussions are still mostly confusing to me (even though a few kind people have made an effort to explain things and I've got several e-mail/articles to re-read). Linking this post to #578 for now.

matt77hias commented 6 years ago

Ok thanks, I will take a look.

As a side note, the two problems that I am facing are:

screenshot-2018-04-05-12-16-19

matt77hias commented 6 years ago

I changed the HLSL vertex shader to:

static const char* vertexShader =
            "cbuffer vertexBuffer : register(b0) \
            {\
            float4x4 ProjectionMatrix; \
            };\
            struct VS_INPUT\
            {\
            float2 pos : POSITION;\
            float4 col : COLOR0;\
            float2 uv  : TEXCOORD0;\
            };\
            \
            struct PS_INPUT\
            {\
            float4 pos : SV_POSITION;\
            float4 col : COLOR0;\
            float2 uv  : TEXCOORD0;\
            };\
            \
            PS_INPUT main(VS_INPUT input)\
            {\
            PS_INPUT output;\
            output.pos     = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
       output.col.xyz = pow(abs(input.col.xyz), 2.2f);\
            output.col.w   = input.col.w;\
            output.uv       = input.uv;\
            return output;\
            }";

and my dithering problem is solved (you cannot see the quantization banding anymore):

screenshot-2018-04-08-13-52-45 screenshot-2018-04-08-13-56-12

DiligentGraphics commented 4 years ago

It appears that the right solution here is to use SRGB texture view e.g. here: https://github.com/ocornut/imgui/blob/master/examples/imgui_impl_dx11.cpp#L314 The hardware will do sRGB -> linear conversion under the hood and filtering will also be correct.

matt77hias commented 4 years ago

@DiligentGraphics this would not solve the whole problem as the vertex colors are not part of a texture. Furthermore, (I need to double-check) ImGui uses one font texture that is black and white-ish (i.e. linear black/white = sRGB black/white). Of course if the latter would have some colors in between, an sRGB will be the better fit.

Other related ImGui issue with more detailed info: https://github.com/ocornut/imgui/issues/578#issuecomment-379467586