-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
WebGLRenderer: Consider .outputEncoding for background, clear color, and fog #23937
WebGLRenderer: Consider .outputEncoding for background, clear color, and fog #23937
Conversation
Can this be made with #18322? Then renderer can have list of all post-processing effects and apply the encoding after applying them... |
Depends on answers to #23614 (comment), I'm not sure. 🤔 |
/cc @drcmda this is a possible solution to the confusion with background and clear color we've discussed in Discord. It does not yet account for post-processing, still some open questions there. |
I'd like to provide some information on how this is handled in postprocessing. sRGB EncodingThe main problem is that WebGL doesn't support hardware sRGB encoding for the back buffer / canvas. Therefore, all materials in With this setup, fullscreen passes can either render linear output or sRGB output based on the
I'd argue that the user shouldn't have to use or worry about an additional fullscreen pass just to peform the sRGB conversion since this can easily be done at the end of any pass. However, if you're using several isolated fullscreen passes, then you'd have to include the sRGB encoding shader chunk in all of the fullscreen materials that are used in the respective passes because they could all potentially render to the canvas, which doesn't support hardware encoding. Background, Fog & Clear ColorMy current approach for the background, fog and clear color is to manually convert them to linear via convertSRGBToLinear. This is something users currently have to be aware of since |
Is this only true for devices that both (1) do not support WebGL 2.0, and (2) do not support @gkjohnson and @Mugen87 you've mentioned that you don't find the current model particularly confusing, so perhaps you can help me clear up one thing I'm confused by. I understand that the post-processing typically uses Linear-sRGB until the final pass, and Within three.js the requirement of adding GammaCorrectionShader is not ideal, but it's mostly fine, and (if we keep it) the name should be changed somewhere in the roadmap of #23614. I'd prefer if the need for that pass could be removed like @vanruesc describes, and handled with |
Does this actually is a two separate problems - one being when encoding should be applied (e.g. by renderer after getting the output from the linear-color-space post-processing effects and before passing the output to the display-color-space effects, as I proposed) and other one being how encoding should be applied (e.g. by |
@donmccurdy Hardware sRGB encoding is only available for render targets. The canvas doesn't support it. Related info: https://www.khronos.org/webgl/public-mailing-list/public_webgl/1707/msg00015.php, relevant portion: "there's presently no way to do [sRGB canvas] in WebGL, and adding a way may turn out to be more complex than assumed, so what you've got to do is re-encode the linear value manually to sRGB for output." |
That's correct;
This is true in theory. You can store linear colors in render targets, but you'll need at least 12 bits per channel or |
The three.js postprocessing stack has not been rethought for years afaict. There are definitely ways to address this from a user-facing perspective. One thing to keep in mind, as @vanruesc mentioned, automatic hardware support for interpreting textures as linear / sRGB is only supported for render targets. When we're talking about the canvas it's still a bit of a wild west and requires the user to explicit perform the conversion which is why the gamma shader is required in the first place. This is why I think changing In terms of making post processing less confusing then the post processing stack could implicitly add the Gamma conversion as a last step only if the renderer canvas color space was set to sRGB. |
This topic was also discussed here some time ago: #23019 |
A few questions in #23936 (comment).
I see, thanks — I knew that UnsignedByteType Linear-sRGB was very lossy but didn't know the device support situation vs. HalfFloatType. Unfortunately, this approach won't work with tone mapping, correct? We'd need to preserve open-domain [0,∞] values until the tone mapping step, so (for that purpose) 8 bits isn't enough in sRGB or Linear-sRGB. 😕
I think this is what has confused me then. All three names ( |
Right, Uint8 sRGB buffers are a compromise; colors are clamped to |
OK, I think what this PR would need to do, in order to support post-processing with render targets ("rt" below), would be:
Note that WebGLRenderer cannot know whether a GammaCorrectionShader is included somewhere in the post-processing chain, while it does know the render target encoding. Fortunately the choice of background color space does not depend on either. tl;dr — if rendering to a render target, set background color to working color space (Linear-sRGB) because we know whatever color space transform is at the end of the post-processing chain will affect the background color. If rendering to canvas, set background color in |
@donmccurdy That looks correct to me. |
This comment was marked as off-topic.
This comment was marked as off-topic.
Does anyone have performance tests or information about the performance implications of using |
Your shaders can be exactly the same either way. Converting to/from sRGB is performed automatically (by WebGL) when reading/writing a render target. |
#24362 may be a good example showing a color space problem originally caused by the issue this PR wants to resolve. Fog color is not affected by But the fog color rendered to Mirror ( Please refer to #24362 (comment) for the details. I hope all the colors will be under |
- Applies only when ColorManagement.legacyMode = false
83d2135
to
cf97ad7
Compare
…nd and clear color.
This PR is now ready for review. I've updated it to include fog color as well, because matching the background color to the fog color is otherwise difficult. The PR has no effect when |
Currently, at least three Color properties (renderer clear color, scene.background color, and scene.fog color) are exempt from the WebGLRenderer specified output color space. These exceptions create confusion — to make the ground plane match the background or fog color, for example, you need to specify the same color in two color spaces, for reasons that are mostly based on how WebGLRenderer applies the output color space conversion. However, if the user provides post-processing that handles color space conversion, the color space used for background and fog colors must change.
This PR is an idea for how to clear up that inconsistency, applied only when
ColorManagement.legacyMode = false
. In this case — as with THREE.Color setters — hexadecimal and CSS-string inputs are understood to be sRGB, and converted automatically to Linear-sRGB. Then internally, WebGLRenderer (which now knows it is dealing with something in the working color space, Linear-sRGB) can make the conversion appropriate for the output color space.With this change, all of these colors will match:
NOTE: The statement above assumes no post-processing, and renderer output to sRGB. One thing I'm not sure about is howrenderer.outputEncoding
andrenderTarget.encoding
are (or ideally should be?) respected in a post-processing chain. This relates to @WestLangley's comments #23614 (comment) and #18942 (comment).