From 8ab4cab1c44b0d91c0a6894aaee6d5a8210be480 Mon Sep 17 00:00:00 2001 From: sunag Date: Thu, 1 Aug 2024 13:36:23 -0300 Subject: [PATCH] NodeBuilder: Optional comparison methods --- src/nodes/core/NodeBuilder.js | 2 + src/nodes/math/OperatorNode.js | 40 ++++++++- .../webgl-fallback/nodes/GLSLNodeBuilder.js | 2 + src/renderers/webgpu/nodes/WGSLNodeBuilder.js | 82 +++++++------------ 4 files changed, 70 insertions(+), 56 deletions(-) diff --git a/src/nodes/core/NodeBuilder.js b/src/nodes/core/NodeBuilder.js index c85b413a85efea..1e2201e8321909 100644 --- a/src/nodes/core/NodeBuilder.js +++ b/src/nodes/core/NodeBuilder.js @@ -125,6 +125,8 @@ class NodeBuilder { this.shaderStage = null; this.buildStage = null; + this.useComparisonMethod = false; + } getBingGroupsCache() { diff --git a/src/nodes/math/OperatorNode.js b/src/nodes/math/OperatorNode.js index 104cc1113cad1e..62834651611182 100644 --- a/src/nodes/math/OperatorNode.js +++ b/src/nodes/math/OperatorNode.js @@ -163,19 +163,51 @@ class OperatorNode extends TempNode { if ( op === '<' && outputLength > 1 ) { - return builder.format( `${ builder.getMethod( 'lessThan' ) }( ${ a }, ${ b } )`, type, output ); + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'lessThan', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } < ${ b } )`, type, output ); + + } } else if ( op === '<=' && outputLength > 1 ) { - return builder.format( `${ builder.getMethod( 'lessThanEqual' ) }( ${ a }, ${ b } )`, type, output ); + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'lessThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } <= ${ b } )`, type, output ); + + } } else if ( op === '>' && outputLength > 1 ) { - return builder.format( `${ builder.getMethod( 'greaterThan' ) }( ${ a }, ${ b } )`, type, output ); + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'greaterThan', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } > ${ b } )`, type, output ); + + } } else if ( op === '>=' && outputLength > 1 ) { - return builder.format( `${ builder.getMethod( 'greaterThanEqual' ) }( ${ a }, ${ b } )`, type, output ); + if ( builder.useComparisonMethod ) { + + return builder.format( `${ builder.getMethod( 'greaterThanEqual', output ) }( ${ a }, ${ b } )`, type, output ); + + } else { + + return builder.format( `( ${ a } >= ${ b } )`, type, output ); + + } } else if ( op === '!' || op === '~' ) { diff --git a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js index cb3d556964c838..a1c488ecf962c9 100644 --- a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +++ b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js @@ -58,6 +58,8 @@ class GLSLNodeBuilder extends NodeBuilder { this.instanceBindGroups = false; + this.useComparisonMethod = true; + } getMethod( method ) { diff --git a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js index 342a0521c3a48f..551fac923aa270 100644 --- a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -31,7 +31,7 @@ const supports = { }; const wgslFnOpLib = { - '^^': 'threejs_xor' + '^^': 'tsl_xor' }; const wgslTypeLib = { @@ -73,37 +73,17 @@ const wgslTypeLib = { }; const wgslPolyfill = { - threejs_xor: new CodeNode( ` -fn threejs_xor( a : bool, b : bool ) -> bool { - - return ( a || b ) && !( a && b ); - -} -` ), - lessThanEqual: new CodeNode( ` -fn threejs_lessThanEqual( a : vec3, b : vec3 ) -> vec3 { - - return vec3( a.x <= b.x, a.y <= b.y, a.z <= b.z ); - -} -` ), - greaterThan: new CodeNode( ` -fn threejs_greaterThan( a : vec3, b : vec3 ) -> vec3 { - - return vec3( a.x > b.x, a.y > b.y, a.z > b.z ); - -} -` ), - mod_float: new CodeNode( 'fn threejs_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }' ), - mod_vec2: new CodeNode( 'fn threejs_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }' ), - mod_vec3: new CodeNode( 'fn threejs_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }' ), - mod_vec4: new CodeNode( 'fn threejs_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }' ), - equals_bool: new CodeNode( 'fn threejs_equals_bool( a : bool, b : bool ) -> bool { return a == b; }' ), - equals_bvec2: new CodeNode( 'fn threejs_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }' ), - equals_bvec3: new CodeNode( 'fn threejs_equals_bvec3( a : vec3f, b : vec3f ) -> vec3 { return vec3( a.x == b.x, a.y == b.y, a.z == b.z ); }' ), - equals_bvec4: new CodeNode( 'fn threejs_equals_bvec4( a : vec4f, b : vec4f ) -> vec4 { return vec4( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }' ), + tsl_xor: new CodeNode( 'fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }' ), + mod_float: new CodeNode( 'fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }' ), + mod_vec2: new CodeNode( 'fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }' ), + mod_vec3: new CodeNode( 'fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }' ), + mod_vec4: new CodeNode( 'fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }' ), + equals_bool: new CodeNode( 'fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }' ), + equals_bvec2: new CodeNode( 'fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }' ), + equals_bvec3: new CodeNode( 'fn tsl_equals_bvec3( a : vec3f, b : vec3f ) -> vec3 { return vec3( a.x == b.x, a.y == b.y, a.z == b.z ); }' ), + equals_bvec4: new CodeNode( 'fn tsl_equals_bvec4( a : vec4f, b : vec4f ) -> vec4 { return vec4( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }' ), repeatWrapping: new CodeNode( ` -fn threejs_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 { +fn tsl_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 { let uvScaled = vec2( uv * vec2( dimension ) ); @@ -112,7 +92,7 @@ fn threejs_repeatWrapping( uv : vec2, dimension : vec2 ) -> vec2 } ` ), biquadraticTexture: new CodeNode( ` -fn threejs_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) -> vec4f { +fn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 ) -> vec4f { let res = vec2f( textureDimensions( map, level ) ); @@ -139,16 +119,14 @@ fn threejs_biquadraticTexture( map : texture_2d, coord : vec2f, level : i32 const wgslMethods = { dFdx: 'dpdx', dFdy: '- dpdy', - mod_float: 'threejs_mod_float', - mod_vec2: 'threejs_mod_vec2', - mod_vec3: 'threejs_mod_vec3', - mod_vec4: 'threejs_mod_vec4', - equals_bool: 'threejs_equals_bool', - equals_bvec2: 'threejs_equals_bvec2', - equals_bvec3: 'threejs_equals_bvec3', - equals_bvec4: 'threejs_equals_bvec4', - lessThanEqual: 'threejs_lessThanEqual', - greaterThan: 'threejs_greaterThan', + mod_float: 'tsl_mod_float', + mod_vec2: 'tsl_mod_vec2', + mod_vec3: 'tsl_mod_vec3', + mod_vec4: 'tsl_mod_vec4', + equals_bool: 'tsl_equals_bool', + equals_bvec2: 'tsl_equals_bvec2', + equals_bvec3: 'tsl_equals_bvec3', + equals_bvec4: 'tsl_equals_bvec4', inversesqrt: 'inverseSqrt', bitcast: 'bitcast' }; @@ -157,15 +135,15 @@ const wgslMethods = { if ( /Windows/g.test( navigator.userAgent ) ) { - wgslPolyfill.pow_float = new CodeNode( 'fn threejs_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }' ); - wgslPolyfill.pow_vec2 = new CodeNode( 'fn threejs_pow_vec2( a : vec2f, b : vec2f ) -> vec2f { return vec2f( threejs_pow_float( a.x, b.x ), threejs_pow_float( a.y, b.y ) ); }', [ wgslPolyfill.pow_float ] ); - wgslPolyfill.pow_vec3 = new CodeNode( 'fn threejs_pow_vec3( a : vec3f, b : vec3f ) -> vec3f { return vec3f( threejs_pow_float( a.x, b.x ), threejs_pow_float( a.y, b.y ), threejs_pow_float( a.z, b.z ) ); }', [ wgslPolyfill.pow_float ] ); - wgslPolyfill.pow_vec4 = new CodeNode( 'fn threejs_pow_vec4( a : vec4f, b : vec4f ) -> vec4f { return vec4f( threejs_pow_float( a.x, b.x ), threejs_pow_float( a.y, b.y ), threejs_pow_float( a.z, b.z ), threejs_pow_float( a.w, b.w ) ); }', [ wgslPolyfill.pow_float ] ); + wgslPolyfill.pow_float = new CodeNode( 'fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }' ); + wgslPolyfill.pow_vec2 = new CodeNode( 'fn tsl_pow_vec2( a : vec2f, b : vec2f ) -> vec2f { return vec2f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ) ); }', [ wgslPolyfill.pow_float ] ); + wgslPolyfill.pow_vec3 = new CodeNode( 'fn tsl_pow_vec3( a : vec3f, b : vec3f ) -> vec3f { return vec3f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ) ); }', [ wgslPolyfill.pow_float ] ); + wgslPolyfill.pow_vec4 = new CodeNode( 'fn tsl_pow_vec4( a : vec4f, b : vec4f ) -> vec4f { return vec4f( tsl_pow_float( a.x, b.x ), tsl_pow_float( a.y, b.y ), tsl_pow_float( a.z, b.z ), tsl_pow_float( a.w, b.w ) ); }', [ wgslPolyfill.pow_float ] ); - wgslMethods.pow_float = 'threejs_pow_float'; - wgslMethods.pow_vec2 = 'threejs_pow_vec2'; - wgslMethods.pow_vec3 = 'threejs_pow_vec3'; - wgslMethods.pow_vec4 = 'threejs_pow_vec4'; + wgslMethods.pow_float = 'tsl_pow_float'; + wgslMethods.pow_vec2 = 'tsl_pow_vec2'; + wgslMethods.pow_vec3 = 'tsl_pow_vec3'; + wgslMethods.pow_vec4 = 'tsl_pow_vec4'; } @@ -253,7 +231,7 @@ class WGSLNodeBuilder extends NodeBuilder { this._include( 'biquadraticTexture' ); - return `threejs_biquadraticTexture( ${ textureProperty }, ${ uvSnippet }, i32( ${ levelSnippet } ) )`; + return `tsl_biquadraticTexture( ${ textureProperty }, ${ uvSnippet }, i32( ${ levelSnippet } ) )`; } @@ -263,7 +241,7 @@ class WGSLNodeBuilder extends NodeBuilder { const dimension = texture.isMultisampleRenderTargetTexture === true ? `textureDimensions( ${ textureProperty } )` : `textureDimensions( ${ textureProperty }, 0 )`; - return `textureLoad( ${ textureProperty }, threejs_repeatWrapping( ${ uvSnippet }, ${ dimension } ), i32( ${ levelSnippet } ) )`; + return `textureLoad( ${ textureProperty }, tsl_repeatWrapping( ${ uvSnippet }, ${ dimension } ), i32( ${ levelSnippet } ) )`; }