WebGLRenderer: Add 'AgXPunchyToneMapping'#27618
WebGLRenderer: Add 'AgXPunchyToneMapping'#27618donmccurdy wants to merge 3 commits intomrdoob:devfrom
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
| // on Blender's implementation using rec 2020 primaries | ||
| // https://github.com/google/filament/pull/7236 | ||
| // Inputs and outputs are encoded as Linear-sRGB. | ||
| vec3 agxLook( vec3 color, uint look ) { |
There was a problem hiding this comment.
This function appears to be missing chunks of code... Was that done on purpose?
(I am not referring to the "golden" chunk.)
| vec3 offset = vec3( 0.0 ); | ||
| vec3 slope = vec3( 1.0 ); | ||
| vec3 power = vec3( 1.0 ); | ||
| float sat = 1.0; | ||
|
|
||
| if ( look == AGX_LOOK_PUNCHY ) { | ||
|
|
||
| slope = vec3( 1.0 ); | ||
| power = vec3( 1.35, 1.35, 1.35 ); | ||
| sat = 1.4; | ||
|
|
||
| } |
There was a problem hiding this comment.
This can be simplified -- or are you leaving this for future look options?
There was a problem hiding this comment.
I was leaving space for future looks, but I don't particularly feel that we need to ship the "Golden" look out of the box, and I'm not sure if the contrast-oriented looks are implemented in the same way. So, I'd be happy to simplify this if you prefer!
|
|
||
| } | ||
|
|
||
| const vec3 lw = vec3( 0.2126, 0.7152, 0.0722 ); |
There was a problem hiding this comment.
I know this was copied from elsewhere, but these are not the correct luminance coefficients for BT.2020 primaries. I guess this can be addressed in a separate PR.
There was a problem hiding this comment.
I don't mind taking the time on this PR. I believe we're working in a log space at this point, between the inset and outset matrices. My mental model, illustrated as (hopefully-intelligible?) pseudocode:
outdated
LINEAR_SRGB {
# (1) apply shading
LINEAR_REC2020 {
AGX_LOG {
# (2) apply sigmoid and look
}
}
SRGB {
# (3) output to drawing buffer
}
}
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
There was a problem hiding this comment.
Who knows, but I would like to think the color space remains Rec.2020.
There was a problem hiding this comment.
Hm... I hadn't yet noticed that these are BT.709 coefficients. Indeed, I don't understand why we'd be using BT.709 coefficients here, rather than BT.2020 coefficients (adapted to the log encoding or not).
These can be found in the iodite "minimal agx" blog post, on which Godot's and Filament's implementations are also based. I'm not comfortable enough reading Blender's implementation, or Troy's original, to know how OpenColorIO implements this step.
There was a problem hiding this comment.
I believe these would be the luminance coefficients for Rec.2020.
0.2626983 0.6780088 0.0592929
Common sense tells me these would be the appropriate coefficients.
There was a problem hiding this comment.
@WestLangley I received a response to my question about the luminance coefficients on the Minimal AgX blog past, and did some further reading. The coefficients come from ASC CDL v1.2, which is a standardized representation of color grading looks. I haven't managed to find the actual text of ASC CDL v1.2, but the luminance coefficients are constant and based on Rec. 709 regardless of the working color space. This is not AgX-specific.
While very possibly more correct, the practical benefits of matching the coefficients to the working color space here are unclear to me. I do believe the log space encoding means we are not strictly dealing with Rec. 2020 here, either. The benefit of using Rec. 709 coefficients is the ability to import looks from other tools. I'm inclined to leave a comment about ASC-CDL v1.2 but to keep the coefficients of Rec. 709.
|
Could we, instead of shipping a specific AgX look, make the parameters adjustable, as they are intended to be according to Troy? Neither the "punchy" nor the "default" look satisfy all applications, and AgX is designed so that there are only a few, artist-adjustable, parameters exposed to control the look (offset, slope, power, saturation). Instead of adding more enums for various looks I think exposing the parameters and then having e.g. the presets from Blender, or the "punchy" and "golden" examples, as available constants to feed into those parameters would be much more effective and more in line to how AgX is intended to be used. |
|
@hybridherbst The ASC CDL v1.2 definition of color grading transforms with [offset, slope, power, saturation] is new to me. Personally I don't know how to use those parameters (except saturation) other than copy/pasting them from existing code. Have you used these parameters before, and do you feel they are artist-friendly? It's encouraging that the CDL parameters are not AgX-specific. If we could support the same color grading API across multiple compatible tone mappers, that would be great. Perhaps one of... // (a)
renderer.setToneMappingCDL( slope, offset, power, saturation );
// (b)
renderer.setColorGradingCDL( slope, offset, power, saturation );... and then we don't need to include "looks". |
|
That said ... a color grading API will often include more parameters than just these. See Filament's ColorGrading API for example. Such an API would involve either loading a LUT, or generating a LUT at runtime. I'm not sure we want to put all of this API surface into WebGLRenderer. Maybe a compromise would be to include just the CDL parameters on WebGLRenderer, along with exposure. And then if we need a more advanced API, that can be added to the node system, or a post-processing pass to be applied before THREE.OutputPass. |
I think it's okay if more advanced/specific features are only exclusively supported in |
|
I just think introducing AgX examples purely meant for learning, such as "Punchy" or "Golden", as tonemapper options in three.js doesn't make much sense – they're not "presets set in stone", they are provided for understanding. Slope, offset, power, saturation are similar to the high-level parameters that are available in grading tools (Premiere, Davinci etc) – personally I find them intuitive. I would very much welcome having that control for AgX outside of postprocessing passes, because these are not viable on mobile/VR. I think more complex LUT tonemapping methods can either be implemented via CustomTonemapping or as pass. |
|
Ok, let's try it — I believe it will be straightforward to support these custom looks (based on CDL parameters) in both AgX and ACES Filmic. Both tonemappers are designed to go through a log space where a custom look may be applied. Our other tonemappers do not have that design feature, to my understanding. We could apply the color grading before tonemapping, but the results will be different. Or perhaps we only enable the CDL parameters for tonemappers designed to support looks. It may take some experimenting to decide. |
|
(... 1.5 years later 😅 ...) Well, if I'm honest with myself, introducing a color grading API is not such a small amount of work. Not so much technical complexity and lines of code as it is API design. I think there's a clear path to add new TSL nodes for color grading operators with WebGPURenderer, but the path a minimum-viable grading API in WebGLRenderer is less clear (see #28544). I'm unsure if I have time/energy to push either forward on a free-time capacity right now. In the meantime... AgX at base contrast is not really intended to be used "as-is" for finished projects, in my opinion, it's a low-contrast starting point for color grading, comparable to shooting flat when filming. That's arguably true for tone mapping in general, but AgX is especially deliberate about it, and I suspect users don't adopt AgX in three.js as much because of this. But I do think AgX makes great choices and compares favorably to any other modern tone mapper, not to mention the Blender interop use case, so I'd really like to have at least as useable an option for it as our other tone mappers. It's also probably our most practical path to tone mapping support for output color spaces other than sRGB. I'd like to propose we do one of two things:
I might prefer (a), but interested in others' thoughts? Then at least WebGLRenderer has an AgX option that's ready to serve the same roles as ACES Filmic, and we can just focus on WebGPURenderer for custom color grading nodes in the future, if/when we're ready to tackle that. 1 Probably using "punchy" preset initially. Could be named AgXPunchyToneMapping as in this PR, or we could name it something else and reserve the possibility of customizing it later, as we've already done with ACES Filmic |
|
Personally I would love if the controls that AgX has (offset, slope, power, sat) would be exposed, and then there can be presets for that (Default, "Like ACES", Punchy), ... I believe that is the intended use of AgX – tunable parameters for controlled, artistic image formation. For reference, here's the values – including the tuned ones that Needle Engine uses for AgX tonemapping: // Default
vec3 offset = vec3(0.0);
vec3 slope = vec3(1.0);
vec3 power = vec3(1.0);
float sat = 1.0;
// Golden
slope = vec3(1.0, 0.9, 0.5);
power = vec3(0.8);
sat = 0.8;
// Punchy
slope = vec3(1.0);
power = vec3(1.35, 1.35, 1.35);
sat = 1.4;
// Needle
slope = vec3(1.05);
power = vec3(1.10, 1.10, 1.10);
sat = 1.15; |
|
I'd certainly also be happy with exposing a CDL! #28544 had just been open for a while, and it seemed like maybe I was the only one interested. I don't think there's just one canonical way to configure AgX looks — Blender uses OCIO for the looks, DaVinci Resolve has its own options. If we had suitable grading APIs we could use them instead, but we don't currently. A CDL (slope, offset, power, saturation) is a minimum viable "look" configuration and is (importantly!) safe to use pre-tone mapping. If we expose a CDL it would make sense to support that with ACES Filmic, too. |
|
To be honest I hadn't seen that one! Maybe reopen it? :) |
|
The WebXR implementation for https://threejs.org/examples/webgpu_xr_cubes |
|
That's awesome to hear, I'll take a look! Thanks for pushing it through! |



Related issue:
Description
Adds THREE.AgXPunchyToneMapping, as found in Blender and Filament. A more contrasty and saturated look, intended for sRGB displays. Intended to provide easier workflows to/from Blender, while retaining a more similar look to what users are currently getting from ACES Filmic.
Comparisons
From left to right: linear • agx • agx-punchy • aces-filmic.
Caution
In the screenshots below, the third column ("agx-punchy") is out of date based on comments in #27618 (comment). I'll update the screenshots soon, and would expect a boost in saturation for the entire column.