`ShaderMaterial` output Color Space behavior on main scene vs render target
See original GitHub issueI’ve hit a confusing case where ShaderMaterial is behaving differently depending on if it was rendered in the main canvas or in a render target. The issue seems to be related to how color space is managed inside Threejs. I’ve consulted the Color Management’s section in the docs but couldn’t find information about how to handle output colors in a ShaderMaterial.
Here’s a link to reproduce the issue
https://jsfiddle.net/yelouafi/36h8eusp/57/
In the example we render 4 cubes, for that we prepare an input color that’s converted to linear space
-
The 2 on top are rendered into the main scene:
- Top left is using a
MeshBasicMaterial
- Top right is using a
ShaderMaterial
- Top left is using a
-
The 2 on the bottom are rendered inside a render target, the render target’s texture is then mapped on to a mesh
- Bottom left is using a
MeshBasicMaterial
- Bottom right is using a
ShaderMaterial
- Bottom left is using a
The basic material renders the same color in both situations, but the ShaderMaterial’s behavior is a little confusing. It seems to render different colors depending on where is was rendered (main scene or render target). Below is a screenshot of the result: Seems top one is rendering the wrong color
if you uncomment the line 74 // outputColor = LinearTosRGB(outputColor);
in the material’s fragment shader the color is rendered correct on both the main scene and the render target.
Also seems render target’s encoding
param doesn’t seem to have any impact on the outcome.
So my question are
-
how to handle color output in the ShaderMaterial’s fragment shader? should we always encode to sRGB or take into account the output encoding of the destination (a canvas or a render target)
-
In the case we’re rendering into a render target, should we take into account the render target’s encoding in the fragment shader: for example, if the render target’s enconding is linear, should the fragement shader output a linear color in this case?
-
One last question regarding the color supplied to
renderer.setClearColor
, the docs seems to suggest that all input colors should be converted to linear but in the case ofsetClearColor
it seems the color needs to be sRGB, is this correct?
Issue Analytics
- State:
- Created a year ago
- Reactions:3
- Comments:5
Top GitHub Comments
I suggest you do not directly use
LinearTosRGB()
but include theencodings_fragment
shader chunk at the end of your fragment shader. When usingShaderMaterial
, the renderer can inject the “correct”linearToOutputTexel()
implementation. This should work for both rendering to screen or RTT.I do feel like something is missing that could justify a GitHub issue thread being kept open here. The color management docs do not cover postprocessing, but should, and I’ve been hesitant to write that part up because the implementation in this repository seems to be out of date compared to alternatives like pmndrs/postprocessing. I’m not sure which implementation to recommend or document at this point, I’ve been using pmndrs.