From b15f9a89fde2ae1a5a70d44139675c4597c93c28 Mon Sep 17 00:00:00 2001 From: "Raoul v. R" Date: Sun, 24 Dec 2023 01:42:04 +0100 Subject: [PATCH] Add support for AgX tone mapping Closes #555 --- src/effects/ToneMappingEffect.js | 11 +++++++++-- src/effects/glsl/tone-mapping.frag | 9 ++++++--- src/enums/ToneMappingMode.js | 10 ++++++---- src/utils/BackCompat.js | 23 ++++++++++++++++++++++- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/effects/ToneMappingEffect.js b/src/effects/ToneMappingEffect.js index 75e9948dd..17ec4c6f3 100644 --- a/src/effects/ToneMappingEffect.js +++ b/src/effects/ToneMappingEffect.js @@ -1,6 +1,7 @@ import { LinearMipmapLinearFilter, Uniform, WebGLRenderTarget } from "three"; import { AdaptiveLuminancePass, LuminancePass } from "../passes/index.js"; import { BlendFunction, ToneMappingMode } from "../enums/index.js"; +import { validateToneMappingMode } from "../utils/index.js"; import { Effect } from "./Effect.js"; import fragmentShader from "./glsl/tone-mapping.frag"; @@ -25,7 +26,7 @@ export class ToneMappingEffect extends Effect { * @param {Object} [options] - The options. * @param {BlendFunction} [options.blendFunction=BlendFunction.SRC] - The blend function of this effect. * @param {Boolean} [options.adaptive=false] - Deprecated. Use mode instead. - * @param {ToneMappingMode} [options.mode=ToneMappingMode.ACES_FILMIC] - The tone mapping mode. + * @param {ToneMappingMode} [options.mode=ToneMappingMode.AGX] - The tone mapping mode. * @param {Number} [options.resolution=256] - The resolution of the luminance texture. Must be a power of two. * @param {Number} [options.maxLuminance=4.0] - Deprecated. Same as whitePoint. * @param {Number} [options.whitePoint=4.0] - The white point. @@ -38,7 +39,7 @@ export class ToneMappingEffect extends Effect { constructor({ blendFunction = BlendFunction.SRC, adaptive = false, - mode = adaptive ? ToneMappingMode.REINHARD2_ADAPTIVE : ToneMappingMode.ACES_FILMIC, + mode = adaptive ? ToneMappingMode.REINHARD2_ADAPTIVE : ToneMappingMode.AGX, resolution = 256, maxLuminance = 4.0, whitePoint = maxLuminance, @@ -123,6 +124,8 @@ export class ToneMappingEffect extends Effect { this.defines.clear(); this.defines.set("TONE_MAPPING_MODE", value.toFixed(0)); + value = validateToneMappingMode(value); + // Use one of the built-in tone mapping operators. switch(value) { @@ -138,6 +141,10 @@ export class ToneMappingEffect extends Effect { this.defines.set("toneMapping(texel)", "ACESFilmicToneMapping(texel)"); break; + case ToneMappingMode.AGX: + this.defines.set("toneMapping(texel)", "AgXToneMapping(texel)"); + break; + default: this.defines.set("toneMapping(texel)", "texel"); break; diff --git a/src/effects/glsl/tone-mapping.frag b/src/effects/glsl/tone-mapping.frag index 8bcdb1962..040a3dd71 100644 --- a/src/effects/glsl/tone-mapping.frag +++ b/src/effects/glsl/tone-mapping.frag @@ -10,6 +10,8 @@ uniform float whitePoint; #if TONE_MAPPING_MODE == 1 || TONE_MAPPING_MODE == 2 + // Reinhard 2 + uniform float middleGrey; #if TONE_MAPPING_MODE == 2 @@ -48,9 +50,10 @@ uniform float whitePoint; } -#elif TONE_MAPPING_MODE == 5 +#elif TONE_MAPPING_MODE == 3 + + // Uncharted 2: http://filmicworlds.com/blog/filmic-tonemapping-operators - // http://filmicworlds.com/blog/filmic-tonemapping-operators #define A 0.15 #define B 0.50 #define C 0.10 @@ -79,7 +82,7 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) outputColor = vec4(Reinhard2ToneMapping(inputColor.rgb), inputColor.a); - #elif TONE_MAPPING_MODE == 5 + #elif TONE_MAPPING_MODE == 3 outputColor = vec4(Uncharted2ToneMapping(inputColor.rgb), inputColor.a); diff --git a/src/enums/ToneMappingMode.js b/src/enums/ToneMappingMode.js index 52d3726dc..88bf56ef7 100644 --- a/src/enums/ToneMappingMode.js +++ b/src/enums/ToneMappingMode.js @@ -6,15 +6,17 @@ * @property {Number} REINHARD2 - Modified Reinhard tone mapping. * @property {Number} REINHARD2_ADAPTIVE - Simulates the optic nerve responding to the amount of light it is receiving. * @property {Number} OPTIMIZED_CINEON - Optimized filmic operator by Jim Hejl and Richard Burgess-Dawson. + * @property {Number} UNCHARTED2 - Uncharted 2 tone mapping. http://filmicworlds.com/blog/filmic-tonemapping-operators. * @property {Number} ACES_FILMIC - ACES tone mapping with a scale of 1.0/0.6. - * @property {Number} UNCHARTED2 - Uncharted 2 tone mapping. http://filmicworlds.com/blog/filmic-tonemapping-operators + * @property {Number} AGX - Filmic tone mapping. Requires three r160 or higher. https://github.com/EaryChow/AgX. */ export const ToneMappingMode = { REINHARD: 0, REINHARD2: 1, REINHARD2_ADAPTIVE: 2, - OPTIMIZED_CINEON: 3, - ACES_FILMIC: 4, - UNCHARTED2: 5 + UNCHARTED2: 3, + OPTIMIZED_CINEON: 4, + ACES_FILMIC: 5, + AGX: 6 }; diff --git a/src/utils/BackCompat.js b/src/utils/BackCompat.js index 5c45bfd8b..e411db91f 100644 --- a/src/utils/BackCompat.js +++ b/src/utils/BackCompat.js @@ -1,5 +1,5 @@ import { LinearEncoding, REVISION, sRGBEncoding } from "three"; -import { LinearSRGBColorSpace, SRGBColorSpace } from "../enums/index.js"; +import { LinearSRGBColorSpace, SRGBColorSpace, ToneMappingMode } from "../enums/index.js"; const revision = Number(REVISION.replace(/\D+/g, "")); const useColorSpace = revision >= 152; @@ -128,3 +128,24 @@ export function updateVertexShader(vertexShader) { return vertexShader; } + +/** + * Validates the given tone mapping mode against the current version of three. + * + * @param {ToneMappingMode} mode - A tone mapping mode. + * @return {ToneMappingMode} The validated tone mapping mode. + * @ignore + */ + +export function validateToneMappingMode(mode) { + + if(revision < 160 && mode === ToneMappingMode.AGX) { + + console.warn("AgX requires three r160 or higher, falling back to ACES filmic"); + mode = ToneMappingMode.ACES_FILMIC; + + } + + return mode; + +}