Skip to content

Commit f250f75

Browse files
authored
TSL: Use dynamic parameters eval for Fn() (mrdoob#31592)
1 parent 01b8d30 commit f250f75

File tree

1 file changed

+121
-59
lines changed

1 file changed

+121
-59
lines changed

src/nodes/tsl/TSLCore.js

Lines changed: 121 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,12 @@ const ShaderNodeImmutable = function ( NodeClass, ...params ) {
322322

323323
class ShaderCallNodeInternal extends Node {
324324

325-
constructor( shaderNode, inputNodes ) {
325+
constructor( shaderNode, rawInputs ) {
326326

327327
super();
328328

329329
this.shaderNode = shaderNode;
330-
this.inputNodes = inputNodes;
330+
this.rawInputs = rawInputs;
331331

332332
this.isShaderCallNodeInternal = true;
333333

@@ -347,7 +347,7 @@ class ShaderCallNodeInternal extends Node {
347347

348348
call( builder ) {
349349

350-
const { shaderNode, inputNodes } = this;
350+
const { shaderNode, rawInputs } = this;
351351

352352
const properties = builder.getNodeProperties( shaderNode );
353353

@@ -392,43 +392,13 @@ class ShaderCallNodeInternal extends Node {
392392

393393
builder.addInclude( functionNode );
394394

395-
result = nodeObject( functionNode.call( inputNodes ) );
395+
//
396396

397-
} else {
398-
399-
let inputs = inputNodes;
400-
401-
if ( Array.isArray( inputs ) ) {
402-
403-
// If inputs is an array, we need to convert it to a Proxy
404-
// so we can call TSL functions using the syntax `Fn( ( { r, g, b } ) => { ... } )`
405-
// and call through `fn( 0, 1, 0 )` or `fn( { r: 0, g: 1, b: 0 } )`
406-
407-
let index = 0;
408-
409-
inputs = new Proxy( inputs, {
410-
411-
get: ( target, property, receiver ) => {
397+
const inputs = rawInputs ? getLayoutParameters( rawInputs ) : null;
412398

413-
let value;
414-
415-
if ( target[ property ] === undefined ) {
416-
417-
value = target[ index ++ ];
418-
419-
} else {
420-
421-
value = Reflect.get( target, property, receiver );
422-
423-
}
399+
result = nodeObject( functionNode.call( inputs ) );
424400

425-
return value;
426-
427-
}
428-
429-
} );
430-
431-
}
401+
} else {
432402

433403
const secureNodeBuilder = new Proxy( builder, {
434404

@@ -456,8 +426,14 @@ class ShaderCallNodeInternal extends Node {
456426

457427
} );
458428

429+
//
430+
431+
const inputs = rawInputs ? getProxyParameters( rawInputs ) : null;
432+
433+
const hasParameters = Array.isArray( rawInputs ) ? rawInputs.length > 0 : rawInputs !== null;
434+
459435
const jsFunc = shaderNode.jsFunc;
460-
const outputNode = inputs !== null || jsFunc.length > 1 ? jsFunc( inputs || [], secureNodeBuilder ) : jsFunc( secureNodeBuilder );
436+
const outputNode = hasParameters || jsFunc.length > 1 ? jsFunc( inputs, secureNodeBuilder ) : jsFunc( secureNodeBuilder );
461437

462438
result = nodeObject( outputNode );
463439

@@ -560,6 +536,110 @@ class ShaderCallNodeInternal extends Node {
560536

561537
}
562538

539+
function getLayoutParameters( params ) {
540+
541+
let output;
542+
543+
nodeObjects( params );
544+
545+
const isArrayAsParameter = params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype );
546+
547+
if ( isArrayAsParameter ) {
548+
549+
output = [ ...params ];
550+
551+
} else {
552+
553+
output = params[ 0 ];
554+
555+
}
556+
557+
return output;
558+
559+
}
560+
561+
function getProxyParameters( params ) {
562+
563+
let index = 0;
564+
565+
nodeObjects( params );
566+
567+
return new Proxy( params, {
568+
569+
get: ( target, property, receiver ) => {
570+
571+
let value;
572+
573+
if ( property === 'length' ) {
574+
575+
value = params.length;
576+
577+
return value;
578+
579+
}
580+
581+
if ( Symbol.iterator === property ) {
582+
583+
value = function* () {
584+
585+
for ( const inputNode of params ) {
586+
587+
yield nodeObject( inputNode );
588+
589+
}
590+
591+
};
592+
593+
} else {
594+
595+
if ( params.length > 0 ) {
596+
597+
if ( Object.getPrototypeOf( params[ 0 ] ) === Object.prototype ) {
598+
599+
const objectTarget = params[ 0 ];
600+
601+
if ( objectTarget[ property ] === undefined ) {
602+
603+
value = objectTarget[ index ++ ];
604+
605+
} else {
606+
607+
value = Reflect.get( objectTarget, property, receiver );
608+
609+
}
610+
611+
} else if ( params[ 0 ] instanceof Node ) {
612+
613+
if ( params[ property ] === undefined ) {
614+
615+
value = params[ index ++ ];
616+
617+
} else {
618+
619+
value = Reflect.get( params, property, receiver );
620+
621+
}
622+
623+
}
624+
625+
} else {
626+
627+
value = Reflect.get( target, property, receiver );
628+
629+
}
630+
631+
value = nodeObject( value );
632+
633+
}
634+
635+
return value;
636+
637+
}
638+
639+
} );
640+
641+
}
642+
563643
class ShaderNodeInternal extends Node {
564644

565645
constructor( jsFunc, nodeType ) {
@@ -583,11 +663,9 @@ class ShaderNodeInternal extends Node {
583663

584664
}
585665

586-
call( inputs = null ) {
666+
call( rawInputs = null ) {
587667

588-
nodeObjects( inputs );
589-
590-
return nodeObject( new ShaderCallNodeInternal( this, inputs ) );
668+
return nodeObject( new ShaderCallNodeInternal( this, rawInputs ) );
591669

592670
}
593671

@@ -799,23 +877,7 @@ class FnNode extends Node {
799877

800878
call( ...params ) {
801879

802-
let inputs;
803-
804-
nodeObjects( params );
805-
806-
const isArrayAsParameter = params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype );
807-
808-
if ( isArrayAsParameter ) {
809-
810-
inputs = [ ...params ];
811-
812-
} else {
813-
814-
inputs = params[ 0 ];
815-
816-
}
817-
818-
const fnCall = this.shaderNode.call( inputs );
880+
const fnCall = this.shaderNode.call( params );
819881

820882
if ( this.shaderNode.nodeType === 'void' ) fnCall.toStack();
821883

0 commit comments

Comments
 (0)