Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Used color space (sRGB vs Linear) #1724

Open
matt77hias opened this issue Apr 5, 2018 · 5 comments
Open

Used color space (sRGB vs Linear) #1724

matt77hias opened this issue Apr 5, 2018 · 5 comments

Comments

@matt77hias
Copy link
Contributor

matt77hias commented Apr 5, 2018

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:

  • transform ImDrawVert to a custom format instead of using ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; directly;

  • change the vertex input layout to a DXGI_FORMAT_R32G32B32A32_FLOAT?

@ocornut
Copy link
Owner

ocornut commented Apr 6, 2018

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
Copy link
Contributor Author

Ok thanks, I will take a look.

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

  • The alpha blending of the ImGui components with my scene is wrong, since the blending should occur in linear space, since a*c1^g + (1-a)*c2^g != (a*c1 + (1-a)*c2)^g (i.e. my linear scene content should be alpha blended with linear ImGui content).
  • Dithering to eliminate quantization errors should be postponed till the very end of the frame, and thus after blending. In the image below, I applied dithering to my scene which successfully removes floating point circular regions due to the finite color depth. It is, however, possible to still see such regions where ImGui components are alpha blended with my scene. Due to the blending the quantization range becomes smaller (<< 1/255) and should be taken into account while dithering or the dithering must just be postponed to the very end.

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

@matt77hias
Copy link
Contributor Author

matt77hias commented Apr 8, 2018

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

@ocornut ocornut changed the title Used color space Used color space (sRGB vs Linear) Jul 8, 2018
@DiligentGraphics
Copy link
Contributor

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
Copy link
Contributor Author

matt77hias commented Jan 18, 2020

@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: #578 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants