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: Add support for AgX Tone Mapping #27366

Merged
merged 20 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/webgl_tonemapping.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
Reinhard: THREE.ReinhardToneMapping,
Cineon: THREE.CineonToneMapping,
ACESFilmic: THREE.ACESFilmicToneMapping,
AgX: THREE.AgXToneMapping,
Custom: THREE.CustomToneMapping
};

Expand Down
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const ReinhardToneMapping = 2;
export const CineonToneMapping = 3;
export const ACESFilmicToneMapping = 4;
export const CustomToneMapping = 5;
export const AgXToneMapping = 6;
gkjohnson marked this conversation as resolved.
Show resolved Hide resolved
export const AttachedBindMode = 'attached';
export const DetachedBindMode = 'detached';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,78 @@ vec3 ACESFilmicToneMapping( vec3 color ) {

}

// AGX Tone Mapping implementation from
// https://iolite-engine.com/blog_posts/minimal_agx_implementation
// https://www.shadertoy.com/view/cd3XWr
// Mean error^2: 3.6705141e-06
vec3 agxDefaultContrastApprox( vec3 x ) {

vec3 x2 = x * x;
vec3 x4 = x2 * x2;

return + 15.5 * x4 * x2
- 40.14 * x4 * x
+ 31.96 * x4
- 6.868 * x2 * x
+ 0.4298 * x2
+ 0.1191 * x
- 0.00232;

}

vec3 agx( vec3 val ) {

const mat3 agx_mat = mat3(
0.842479062253094, 0.0423282422610123, 0.0423756549057051,
0.0784335999999992, 0.878468636469772, 0.0784336,
0.0792237451477643, 0.0791661274605434, 0.879142973793104
);

const float min_ev = -12.47393;
const float max_ev = 4.026069;

// Input transform (inset)
val = agx_mat * val;

// Log2 space encoding
val = clamp( log2( val ), min_ev, max_ev );
val = ( val - min_ev ) / ( max_ev - min_ev );

// Apply sigmoid function approximation
val = agxDefaultContrastApprox( val );

return val;

}

vec3 agxEotf( vec3 val ) {

const mat3 agx_mat_inv = mat3(
1.19687900512017, -0.0528968517574562, -0.0529716355144438,
-0.0980208811401368, 1.15190312990417, -0.0980434501171241,
-0.0990297440797205, -0.0989611768448433, 1.15107367264116
);

// Inverse input transform (outset)
val = agx_mat_inv * val;

// sRGB IEC 61966-2-1 2.2 Exponent Reference EOTF Display
// NOTE: We're linearizing the output here. Comment/adjust when
// *not* using a sRGB render target
val = pow( val, vec3( 2.2 ) );
gkjohnson marked this conversation as resolved.
Show resolved Hide resolved

return val;

}

vec3 AgXToneMapping( vec3 color ) {
gkjohnson marked this conversation as resolved.
Show resolved Hide resolved

color *= toneMappingExposure;
color = agx( color );
color = agxEotf( color );
return color;

}

vec3 CustomToneMapping( vec3 color ) { return color; }
`;
6 changes: 5 additions & 1 deletion src/renderers/webgl/WebGLProgram.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { WebGLUniforms } from './WebGLUniforms.js';
import { WebGLShader } from './WebGLShader.js';
import { ShaderChunk } from '../shaders/ShaderChunk.js';
import { NoToneMapping, AddOperation, MixOperation, MultiplyOperation, CubeRefractionMapping, CubeUVReflectionMapping, CubeReflectionMapping, PCFSoftShadowMap, PCFShadowMap, VSMShadowMap, ACESFilmicToneMapping, CineonToneMapping, CustomToneMapping, ReinhardToneMapping, LinearToneMapping, GLSL3, LinearSRGBColorSpace, SRGBColorSpace, LinearDisplayP3ColorSpace, DisplayP3ColorSpace, P3Primaries, Rec709Primaries } from '../../constants.js';
import { NoToneMapping, AddOperation, MixOperation, MultiplyOperation, CubeRefractionMapping, CubeUVReflectionMapping, CubeReflectionMapping, PCFSoftShadowMap, PCFShadowMap, VSMShadowMap, AgXToneMapping, ACESFilmicToneMapping, CineonToneMapping, CustomToneMapping, ReinhardToneMapping, LinearToneMapping, GLSL3, LinearSRGBColorSpace, SRGBColorSpace, LinearDisplayP3ColorSpace, DisplayP3ColorSpace, P3Primaries, Rec709Primaries } from '../../constants.js';
import { ColorManagement } from '../../math/ColorManagement.js';

// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
Expand Down Expand Up @@ -120,6 +120,10 @@ function getToneMappingFunction( functionName, toneMapping ) {
toneMappingName = 'ACESFilmic';
break;

case AgXToneMapping:
toneMappingName = 'AgX';
break;

case CustomToneMapping:
toneMappingName = 'Custom';
break;
Expand Down
1 change: 1 addition & 0 deletions test/unit/src/constants.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default QUnit.module( 'Constants', () => {
assert.equal( Constants.CineonToneMapping, 3, 'CineonToneMapping is equal to 3' );
assert.equal( Constants.ACESFilmicToneMapping, 4, 'ACESFilmicToneMapping is equal to 4' );
assert.equal( Constants.CustomToneMapping, 5, 'CustomToneMapping is equal to 5' );
assert.equal( Constants.AgXToneMapping, 6, 'AgXToneMapping is equal to 6' );

assert.equal( Constants.AttachedBindMode, 'attached', 'AttachedBindMode is equal to attached' );
assert.equal( Constants.DetachedBindMode, 'detached', 'DetachedBindMode is equal to detached' );
Expand Down