From cb29f6f17ee47ca6d5741b309150317716cbfc70 Mon Sep 17 00:00:00 2001 From: Don McCurdy Date: Sun, 20 Oct 2024 19:40:32 -0400 Subject: [PATCH] TSL: Support defined color spaces in ColorSpaceNode (#29694) * TSL: Support defined color spaces in ColorSpaceNode * TSL: Add .convertColorNode() * fix circular dependency * remove chaining method --------- --- src/math/ColorManagement.js | 1 - src/nodes/display/ColorSpaceFunctions.js | 10 +-- src/nodes/display/ColorSpaceNode.js | 66 ++++++++----------- src/renderers/common/nodes/NodeLibrary.js | 13 ---- .../webgpu/nodes/BasicNodeLibrary.js | 8 --- .../webgpu/nodes/StandardNodeLibrary.js | 8 --- 6 files changed, 32 insertions(+), 74 deletions(-) diff --git a/src/math/ColorManagement.js b/src/math/ColorManagement.js index 00a151d2343a67..aa8806ea0f3e05 100644 --- a/src/math/ColorManagement.js +++ b/src/math/ColorManagement.js @@ -124,7 +124,6 @@ export const ColorManagement = { }; - export function SRGBToLinear( c ) { return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); diff --git a/src/nodes/display/ColorSpaceFunctions.js b/src/nodes/display/ColorSpaceFunctions.js index 0ecac7cbf1305a..acdc210d0376f3 100644 --- a/src/nodes/display/ColorSpaceFunctions.js +++ b/src/nodes/display/ColorSpaceFunctions.js @@ -1,7 +1,7 @@ import { mix } from '../math/MathNode.js'; -import { Fn } from '../tsl/TSLBase.js'; +import { Fn } from '../tsl/TSLCore.js'; -export const sRGBToLinearSRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { +export const sRGBTransferEOTF = /*@__PURE__*/ Fn( ( [ color ] ) => { const a = color.mul( 0.9478672986 ).add( 0.0521327014 ).pow( 2.4 ); const b = color.mul( 0.0773993808 ); @@ -12,14 +12,14 @@ export const sRGBToLinearSRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { return rgbResult; } ).setLayout( { - name: 'sRGBToLinearSRGB', + name: 'sRGBTransferEOTF', type: 'vec3', inputs: [ { name: 'color', type: 'vec3' } ] } ); -export const linearSRGBTosRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { +export const sRGBTransferOETF = /*@__PURE__*/ Fn( ( [ color ] ) => { const a = color.pow( 0.41666 ).mul( 1.055 ).sub( 0.055 ); const b = color.mul( 12.92 ); @@ -30,7 +30,7 @@ export const linearSRGBTosRGB = /*@__PURE__*/ Fn( ( [ color ] ) => { return rgbResult; } ).setLayout( { - name: 'linearSRGBTosRGB', + name: 'sRGBTransferOETF', type: 'vec3', inputs: [ { name: 'color', type: 'vec3' } diff --git a/src/nodes/display/ColorSpaceNode.js b/src/nodes/display/ColorSpaceNode.js index 3c56138312b373..e3ba8d6ecfa400 100644 --- a/src/nodes/display/ColorSpaceNode.js +++ b/src/nodes/display/ColorSpaceNode.js @@ -1,36 +1,14 @@ import TempNode from '../core/TempNode.js'; -import { addMethodChaining, nodeObject, vec4 } from '../tsl/TSLCore.js'; +import { addMethodChaining, mat3, nodeObject, vec4 } from '../tsl/TSLCore.js'; -import { LinearSRGBColorSpace, SRGBColorSpace } from '../../constants.js'; +import { SRGBTransfer } from '../../constants.js'; import { ColorManagement } from '../../math/ColorManagement.js'; +import { sRGBTransferEOTF, sRGBTransferOETF } from './ColorSpaceFunctions.js'; +import { Matrix3 } from '../../math/Matrix3.js'; const WORKING_COLOR_SPACE = 'WorkingColorSpace'; const OUTPUT_COLOR_SPACE = 'OutputColorSpace'; -function getColorSpaceName( colorSpace ) { - - let method = null; - - if ( colorSpace === LinearSRGBColorSpace ) { - - method = 'Linear'; - - } else if ( colorSpace === SRGBColorSpace ) { - - method = 'sRGB'; - - } - - return method; - -} - -export function getColorSpaceMethod( source, target ) { - - return getColorSpaceName( source ) + 'To' + getColorSpaceName( target ); - -} - class ColorSpaceNode extends TempNode { static get type() { @@ -49,7 +27,7 @@ class ColorSpaceNode extends TempNode { } - getColorSpace( builder, colorSpace ) { + resolveColorSpace( builder, colorSpace ) { if ( colorSpace === WORKING_COLOR_SPACE ) { @@ -67,29 +45,37 @@ class ColorSpaceNode extends TempNode { setup( builder ) { - const { renderer } = builder; const { colorNode } = this; - const source = this.getColorSpace( builder, this.source ); - const target = this.getColorSpace( builder, this.target ); + const source = this.resolveColorSpace( builder, this.source ); + const target = this.resolveColorSpace( builder, this.target ); - if ( source === target ) return colorNode; + let outputNode = colorNode; - const colorSpace = getColorSpaceMethod( source, target ); + if ( ColorManagement.enabled === false || source === target || ! source || ! target ) { - let outputNode = null; + return outputNode; - const colorSpaceFn = renderer.library.getColorSpaceFunction( colorSpace ); + } - if ( colorSpaceFn !== null ) { + if ( ColorManagement.getTransfer( source ) === SRGBTransfer ) { - outputNode = vec4( colorSpaceFn( colorNode.rgb ), colorNode.a ); + outputNode = vec4( sRGBTransferEOTF( outputNode.rgb ), outputNode.a ); - } else { + } - console.error( 'ColorSpaceNode: Unsupported Color Space configuration.', colorSpace ); + if ( ColorManagement.getPrimaries( source ) !== ColorManagement.getPrimaries( target ) ) { - outputNode = colorNode; + outputNode = vec4( + mat3( ColorManagement._getMatrix( new Matrix3(), source, target ) ).mul( outputNode.rgb ), + outputNode.a + ); + + } + + if ( ColorManagement.getTransfer( target ) === SRGBTransfer ) { + + outputNode = vec4( sRGBTransferOETF( outputNode.rgb ), outputNode.a ); } @@ -107,6 +93,8 @@ export const toWorkingColorSpace = ( node ) => nodeObject( new ColorSpaceNode( n export const workingToColorSpace = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, colorSpace ) ); export const colorSpaceToWorking = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), colorSpace, WORKING_COLOR_SPACE ) ); +export const convertColorSpace = ( node, sourceColorSpace, targetColorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), sourceColorSpace, targetColorSpace ) ); + addMethodChaining( 'toOutputColorSpace', toOutputColorSpace ); addMethodChaining( 'toWorkingColorSpace', toWorkingColorSpace ); diff --git a/src/renderers/common/nodes/NodeLibrary.js b/src/renderers/common/nodes/NodeLibrary.js index ee08f321726249..8d1e56ee9a8bd8 100644 --- a/src/renderers/common/nodes/NodeLibrary.js +++ b/src/renderers/common/nodes/NodeLibrary.js @@ -5,7 +5,6 @@ class NodeLibrary { this.lightNodes = new WeakMap(); this.materialNodes = new Map(); this.toneMappingNodes = new Map(); - this.colorSpaceNodes = new Map(); } @@ -33,18 +32,6 @@ class NodeLibrary { } - addColorSpace( colorSpaceNode, colorSpace ) { - - this.addType( colorSpaceNode, colorSpace, this.colorSpaceNodes ); - - } - - getColorSpaceFunction( colorSpace ) { - - return this.colorSpaceNodes.get( colorSpace ) || null; - - } - addToneMapping( toneMappingNode, toneMapping ) { this.addType( toneMappingNode, toneMapping, this.toneMappingNodes ); diff --git a/src/renderers/webgpu/nodes/BasicNodeLibrary.js b/src/renderers/webgpu/nodes/BasicNodeLibrary.js index b5bc5d9b3e6bcd..36fa775bf25645 100644 --- a/src/renderers/webgpu/nodes/BasicNodeLibrary.js +++ b/src/renderers/webgpu/nodes/BasicNodeLibrary.js @@ -22,11 +22,6 @@ import { IESSpotLightNode } from '../../../nodes/Nodes.js'; import { LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping } from '../../../constants.js'; import { linearToneMapping, reinhardToneMapping, cineonToneMapping, acesFilmicToneMapping, agxToneMapping, neutralToneMapping } from '../../../nodes/display/ToneMappingFunctions.js'; -// Color Space -import { LinearSRGBColorSpace, SRGBColorSpace } from '../../../constants.js'; -import { linearSRGBTosRGB, sRGBToLinearSRGB } from '../../../nodes/display/ColorSpaceFunctions.js'; -import { getColorSpaceMethod } from '../../../nodes/display/ColorSpaceNode.js'; - class BasicNodeLibrary extends NodeLibrary { constructor() { @@ -49,9 +44,6 @@ class BasicNodeLibrary extends NodeLibrary { this.addToneMapping( agxToneMapping, AgXToneMapping ); this.addToneMapping( neutralToneMapping, NeutralToneMapping ); - this.addColorSpace( linearSRGBTosRGB, getColorSpaceMethod( LinearSRGBColorSpace, SRGBColorSpace ) ); - this.addColorSpace( sRGBToLinearSRGB, getColorSpaceMethod( SRGBColorSpace, LinearSRGBColorSpace ) ); - } } diff --git a/src/renderers/webgpu/nodes/StandardNodeLibrary.js b/src/renderers/webgpu/nodes/StandardNodeLibrary.js index 3c001da565092f..626900e4b46f96 100644 --- a/src/renderers/webgpu/nodes/StandardNodeLibrary.js +++ b/src/renderers/webgpu/nodes/StandardNodeLibrary.js @@ -54,11 +54,6 @@ import { IESSpotLightNode } from '../../../nodes/Nodes.js'; import { LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping } from '../../../constants.js'; import { linearToneMapping, reinhardToneMapping, cineonToneMapping, acesFilmicToneMapping, agxToneMapping, neutralToneMapping } from '../../../nodes/display/ToneMappingFunctions.js'; -// Color Space -import { LinearSRGBColorSpace, SRGBColorSpace } from '../../../constants.js'; -import { linearSRGBTosRGB, sRGBToLinearSRGB } from '../../../nodes/display/ColorSpaceFunctions.js'; -import { getColorSpaceMethod } from '../../../nodes/display/ColorSpaceNode.js'; - class StandardNodeLibrary extends NodeLibrary { constructor() { @@ -95,9 +90,6 @@ class StandardNodeLibrary extends NodeLibrary { this.addToneMapping( agxToneMapping, AgXToneMapping ); this.addToneMapping( neutralToneMapping, NeutralToneMapping ); - this.addColorSpace( linearSRGBTosRGB, getColorSpaceMethod( LinearSRGBColorSpace, SRGBColorSpace ) ); - this.addColorSpace( sRGBToLinearSRGB, getColorSpaceMethod( SRGBColorSpace, LinearSRGBColorSpace ) ); - } }