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

WebGLRenderer: Support "Linear Display P3" working color space and "Display P3" unlit rendering #26644

Merged
merged 21 commits into from
Sep 7, 2023

Conversation

donmccurdy
Copy link
Collaborator

@donmccurdy donmccurdy commented Aug 25, 2023

tl;dr — Adds support for wide gamut color spaces in unlit rendering workflows such as 2D games, photogrammetry, and image processing applications.


Extends THREE.ColorManagement and THREE.WebGLRenderer with support — only in "unlit" scenes, currently — for the wide-gamut Display P3 color space. To use this feature, the following steps are required:

  1. Assign ColorManagement.workingColorSpace = LinearDisplayP3ColorSpace
  2. Assign renderer.outputColorSpace = DisplayP3ColorSpace
  3. Assign texture.colorSpace = DisplayP3ColorSpace AND ensure each texture's ICC Profile (or other color space metadata) is correctly embedded

To see the difference in this example, you'll need use Chrome or Safari, and a display and operating system that support the Display P3 wide gamut color space. Most newer macOS devices will do fine, but your external monitor may not. The change covers only unlit rendering now, e.g. MeshBasicMaterial. More changes will be required to adjust the lit rendering pipeline for a wider gamut, and @WestLangley and I are still discussing those requirements.


The images attached are borrowed from https://webkit.org/blog-files/color-gamut/comparison.html. We will want to verify the licenses and attribution before merging this PR, or create our own examples.


Related

@github-actions
Copy link

github-actions bot commented Aug 25, 2023

📦 Bundle size

Full ESM build, minified and gzipped.

Filesize dev Filesize PR Diff
645.6 kB (160.2 kB) 647.6 kB (160.8 kB) +2.07 kB

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Filesize dev Filesize PR Diff
438.9 kB (106.3 kB) 440.9 kB (106.9 kB) +2.01 kB

examples/webgl_test_wide_gamut.html Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLBackground.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLPrograms.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLProgram.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLTextures.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLTextures.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLTextures.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLTextures.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLTextures.js Fixed Show fixed Hide fixed
src/renderers/webgl/WebGLUtils.js Fixed Show fixed Hide fixed
@donmccurdy
Copy link
Collaborator Author

donmccurdy commented Aug 30, 2023

To summarize a few things happening in this PR and its demo —

  1. When the browser supports Display P3 (In 2023: Chrome and Safari), and the developer knows their scene contains wide gamut content, we assign ColorManagement.workingColorSpace = LinearDisplayP3ColorSpace to enable wide gamut rendering.
  2. When the display supports Display P3 (In 2023: Most macOS, iOS, and Pixel devices) we assign renderer.outputColorSpace = DisplayP3ColorSpace to enable wide gamut output. This may change during a session, if displays are (dis)connected or windows are moved to another display.
  3. When a texture's .colorSpace property indicates that it uses primaries differing from those of the working color space (e.g. sRGB textures in a Linear Display P3 working color space) the renderer enables gl.UNPACK_COLORSPACE_CONVERSION_WEBGL to gamut map the texture to the working color space. This operation requires that the texture's ICC profile be correct; setting texture.colorSpace alone is not enough. WebGL cannot do this for compressed textures or data textures — they must already use the working primaries.
  4. When a texture's .colorSpace property indicates that it uses a supported transfer function (both sRGB and Display P3 use the "sRGB" transfer function) the renderer chooses an internal format such that WebGL will automatically apply the sRGB EOTF when sampling from the texture.
  5. After rendering, pixels are encoded to the output color space.

As a result of (3) and (4), color images are typically uploaded to WebGL in either sRGB or Display P3 (whichever is the non-linear analog to the linear working color space). When the GPU samples the textures, it decodes each sample by applying the sRGB EOTF, to obtain a sample in the working color space (Linear sRGB or Linear Display P3).

@donmccurdy
Copy link
Collaborator Author

I've simplified the demo, using just a three.js logo. Copyright assigned to the three.js authors, Creative Commons Attribution 3.0. This is ready to merge experimentally, when we are ready. We can then continue working on changes required for lit rendering.

Comment on lines 2398 to 2404
this.resetColorManagement = function () {

_gl.drawingBufferColorSpace = this._outputColorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb';
_gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb';

};

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this new method?
Could we inline the calls in set outputColorSpace( colorSpace )?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for it – or we don't need a public method, at least. I've inlined the calls in the setter. ✅

@mrdoob mrdoob added this to the r157 milestone Sep 7, 2023
@donmccurdy
Copy link
Collaborator Author

FYI, this demo has just broken in Safari on macOS Sonoma:

https://bugs.webkit.org/show_bug.cgi?id=262429

@elalish elalish mentioned this pull request Oct 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants