Skip to content

[pull] dev from mrdoob:dev #709

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

Merged
merged 3 commits into from
Aug 5, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion build/three.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -67148,7 +67148,7 @@ function WebGLShadowMap( renderer, objects, capabilities ) {
// Set GL state for depth map.
_state.setBlending( NoBlending );

if ( _state.buffers.depth.getReversed() ) {
if ( _state.buffers.depth.getReversed() === true ) {

_state.buffers.color.setClear( 0, 0, 0, 0 );

Expand Down
2 changes: 1 addition & 1 deletion build/three.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -8474,7 +8474,7 @@ function WebGLShadowMap( renderer, objects, capabilities ) {
// Set GL state for depth map.
_state.setBlending( NoBlending );

if ( _state.buffers.depth.getReversed() ) {
if ( _state.buffers.depth.getReversed() === true ) {

_state.buffers.color.setClear( 0, 0, 0, 0 );

Expand Down
2 changes: 1 addition & 1 deletion build/three.module.min.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion build/three.tsl.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/three.tsl.min.js

Large diffs are not rendered by default.

199 changes: 176 additions & 23 deletions build/three.webgpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,16 @@ class Node extends EventDispatcher {

}

if ( result === '' && output !== null && output !== 'void' && output !== 'OutputType' ) {

// if no snippet is generated, return a default value

console.error( `THREE.TSL: Invalid generated code, expected a "${ output }".` );

result = builder.generateConst( output );

}

}

builder.removeChain( this );
Expand Down Expand Up @@ -3528,25 +3538,57 @@ class ShaderCallNodeInternal extends Node {
let index = 0;

inputs = new Proxy( inputs, {

get: ( target, property, receiver ) => {

let value;

if ( target[ property ] === undefined ) {

return target[ index ++ ];
value = target[ index ++ ];

} else {

return Reflect.get( target, property, receiver );
value = Reflect.get( target, property, receiver );

}

return value;

}

} );

}

const secureNodeBuilder = new Proxy( builder, {

get: ( target, property, receiver ) => {

let value;

if ( Symbol.iterator === property ) {

value = function* () {

yield undefined;

};

} else {

value = Reflect.get( target, property, receiver );

}

return value;

}

} );

const jsFunc = shaderNode.jsFunc;
const outputNode = inputs !== null || jsFunc.length > 1 ? jsFunc( inputs || [], builder ) : jsFunc( builder );
const outputNode = inputs !== null || jsFunc.length > 1 ? jsFunc( inputs || [], secureNodeBuilder ) : jsFunc( secureNodeBuilder );

result = nodeObject( outputNode );

Expand Down Expand Up @@ -3732,6 +3774,18 @@ const ConvertType = function ( type, cacheMap = null ) {

return ( ...params ) => {

for ( const param of params ) {

if ( param === undefined ) {

console.error( `THREE.TSL: Invalid parameter for the type "${ type }".` );

return nodeObject( new ConstNode( 0, type ) );

}

}

if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => {

const paramType = typeof param;
Expand Down Expand Up @@ -3913,7 +3967,7 @@ class FnNode extends Node {

const type = this.getNodeType( builder );

console.warn( 'THREE.TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".' );
console.error( 'THREE.TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".' );

return builder.generateConst( type );

Expand Down Expand Up @@ -4780,16 +4834,24 @@ class UniformNode extends InputNode {
*
* @tsl
* @function
* @param {any} arg1 - The value of this node. Usually a JS primitive or three.js object (vector, matrix, color, texture).
* @param {string} [arg2] - The node type. If no explicit type is defined, the node tries to derive the type from its value.
* @param {any|string} value - The value of this uniform or your type. Usually a JS primitive or three.js object (vector, matrix, color, texture).
* @param {string} [type] - The node type. If no explicit type is defined, the node tries to derive the type from its value.
* @returns {UniformNode}
*/
const uniform = ( arg1, arg2 ) => {
const uniform = ( value, type ) => {

const nodeType = getConstNodeType( type || value );

if ( nodeType === value ) {

// if the value is a type but no having a value

const nodeType = getConstNodeType( arg2 || arg1 );
value = getValueFromType( nodeType );

}

// @TODO: get ConstNode from .traverse() in the future
const value = ( arg1 && arg1.isNode === true ) ? ( arg1.node && arg1.node.value ) || arg1.value : arg1;
value = ( value && value.isNode === true ) ? ( value.node && value.node.value ) || value.value : value;

return nodeObject( new UniformNode( value, nodeType ) );

Expand Down Expand Up @@ -5055,11 +5117,10 @@ class AssignNode extends TempNode {

const needsSplitAssign = this.needsSplitAssign( builder );

const target = targetNode.build( builder );
const targetType = targetNode.getNodeType( builder );

const target = targetNode.build( builder );
const source = sourceNode.build( builder, targetType );

const sourceType = sourceNode.getNodeType( builder );

const nodeData = builder.getDataFromNode( this );
Expand Down Expand Up @@ -7309,10 +7370,12 @@ class ConditionalNode extends Node {

//

const isUniformFlow = builder.context.uniformFlow;

const properties = builder.getNodeProperties( this );
properties.condNode = condNode;
properties.ifNode = ifNode.context( { nodeBlock: ifNode } );
properties.elseNode = elseNode ? elseNode.context( { nodeBlock: elseNode } ) : null;
properties.ifNode = isUniformFlow ? ifNode : ifNode.context( { nodeBlock: ifNode } );
properties.elseNode = elseNode ? ( isUniformFlow ? elseNode : elseNode.context( { nodeBlock: elseNode } ) ) : null;

}

Expand All @@ -7337,6 +7400,20 @@ class ConditionalNode extends Node {
nodeData.nodeProperty = nodeProperty;

const nodeSnippet = condNode.build( builder, 'bool' );
const isUniformFlow = builder.context.uniformFlow;

if ( isUniformFlow && elseNode !== null ) {

const ifSnippet = ifNode.build( builder, type );
const elseSnippet = elseNode.build( builder, type );

const mathSnippet = builder.getTernary( nodeSnippet, ifSnippet, elseSnippet );

// TODO: If node property already exists return something else

return builder.format( mathSnippet, type, output );

}

builder.addFlowCode( `\n${ builder.tab }if ( ${ nodeSnippet } ) {\n\n` ).addFlowTab();

Expand Down Expand Up @@ -7550,6 +7627,16 @@ class ContextNode extends Node {
*/
const context = /*@__PURE__*/ nodeProxy( ContextNode ).setParameterLength( 1, 2 );

/**
* TSL function for defining a uniformFlow context value for a given node.
*
* @tsl
* @function
* @param {Node} node - The node whose dependencies should all execute within a uniform control-flow path.
* @returns {ContextNode}
*/
const uniformFlow = ( node ) => context( node, { uniformFlow: true } );

/**
* TSL function for defining a name for the context value for a given node.
*
Expand Down Expand Up @@ -7581,6 +7668,7 @@ function label( node, name ) {

addMethodChaining( 'context', context );
addMethodChaining( 'label', label );
addMethodChaining( 'uniformFlow', uniformFlow );
addMethodChaining( 'setName', setName );

/**
Expand Down Expand Up @@ -30936,13 +31024,13 @@ class StackNode extends Node {

getNodeType( builder ) {

return this.outputNode ? this.outputNode.getNodeType( builder ) : 'void';
return this.hasOutput ? this.outputNode.getNodeType( builder ) : 'void';

}

getMemberType( builder, name ) {

return this.outputNode ? this.outputNode.getMemberType( builder, name ) : 'void';
return this.hasOutput ? this.outputNode.getMemberType( builder, name ) : 'void';

}

Expand All @@ -30954,6 +31042,13 @@ class StackNode extends Node {
*/
add( node ) {

if ( node.isNode !== true ) {

console.error( 'THREE.TSL: Invalid node added to stack.' );
return this;

}

this.nodes.push( node );

return this;
Expand Down Expand Up @@ -31047,7 +31142,7 @@ class StackNode extends Node {

} else {

throw new Error( 'TSL: Invalid parameter length. Case() requires at least two parameters.' );
console.error( 'THREE.TSL: Invalid parameter length. Case() requires at least two parameters.' );

}

Expand Down Expand Up @@ -31131,6 +31226,12 @@ class StackNode extends Node {

}

get hasOutput() {

return this.outputNode && this.outputNode.isNode;

}

build( builder, ...params ) {

const previousBuildStack = builder.currentStack;
Expand Down Expand Up @@ -31181,7 +31282,19 @@ class StackNode extends Node {

}

const result = this.outputNode ? this.outputNode.build( builder, ...params ) : super.build( builder, ...params );
//

let result;

if ( this.hasOutput ) {

result = this.outputNode.build( builder, ...params );

} else {

result = super.build( builder, ...params );

}

setCurrentStack( previousStack );

Expand Down Expand Up @@ -43380,6 +43493,7 @@ var TSL = /*#__PURE__*/Object.freeze({
uniform: uniform,
uniformArray: uniformArray,
uniformCubeTexture: uniformCubeTexture,
uniformFlow: uniformFlow,
uniformGroup: uniformGroup,
uniformTexture: uniformTexture,
unpremultiplyAlpha: unpremultiplyAlpha,
Expand Down Expand Up @@ -45781,6 +45895,22 @@ class NodeBuilder {

}

/**
* Returns the native snippet for a ternary operation. E.g. GLSL would output
* a ternary op as `cond ? x : y` whereas WGSL would output it as `select(y, x, cond)`
*
* @abstract
* @param {string} condSnippet - The condition determining which expression gets resolved.
* @param {string} ifSnippet - The expression to resolve to if the condition is true.
* @param {string} elseSnippet - The expression to resolve to if the condition is false.
* @return {string} The resolved method name.
*/
getTernary( /* condSnippet, ifSnippet, elseSnippet*/ ) {

return null;

}

/**
* Returns a node for the given hash, see {@link NodeBuilder#setHashNode}.
*
Expand Down Expand Up @@ -46097,7 +46227,6 @@ class NodeBuilder {

}


/**
* Generates the shader string for the given type and value.
*
Expand Down Expand Up @@ -47876,11 +48005,6 @@ class NodeBuilder {

}

/**
* Prevents the node builder from being used as an iterable in TSL.Fn(), avoiding potential runtime errors.
*/
*[ Symbol.iterator ]() { }

}

/**
Expand Down Expand Up @@ -56502,6 +56626,20 @@ class GLSLNodeBuilder extends NodeBuilder {

}

/**
* Returns the native snippet for a ternary operation.
*
* @param {string} condSnippet - The condition determining which expression gets resolved.
* @param {string} ifSnippet - The expression to resolve to if the condition is true.
* @param {string} elseSnippet - The expression to resolve to if the condition is false.
* @return {string} The resolved method name.
*/
getTernary( condSnippet, ifSnippet, elseSnippet ) {

return `${condSnippet} ? ${ifSnippet} : ${elseSnippet}`;

}

/**
* Returns the output struct name. Not relevant for GLSL.
*
Expand Down Expand Up @@ -69029,6 +69167,21 @@ ${ flowData.code }

}

/**
* Returns the native snippet for a ternary operation.
*
* @param {string} condSnippet - The condition determining which expression gets resolved.
* @param {string} ifSnippet - The expression to resolve to if the condition is true.
* @param {string} elseSnippet - The expression to resolve to if the condition is false.
* @return {string} The resolved method name.
*/
getTernary( condSnippet, ifSnippet, elseSnippet ) {

return `select( ${elseSnippet}, ${ifSnippet}, ${condSnippet} )`;

}


/**
* Returns the WGSL type of the given node data type.
*
Expand Down
2 changes: 1 addition & 1 deletion build/three.webgpu.min.js

Large diffs are not rendered by default.

Loading