Skip to content
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
1 change: 1 addition & 0 deletions src/Three.TSL.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ export const remapClamp = TSL.remapClamp;
export const renderGroup = TSL.renderGroup;
export const renderOutput = TSL.renderOutput;
export const rendererReference = TSL.rendererReference;
export const replaceDefaultUV = TSL.replaceDefaultUV;
export const rotate = TSL.rotate;
export const rotateUV = TSL.rotateUV;
export const roughness = TSL.roughness;
Expand Down
46 changes: 45 additions & 1 deletion src/materials/nodes/NodeMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js';
import { vertexColor } from '../../nodes/accessors/VertexColorNode.js';
import { premultiplyAlpha } from '../../nodes/display/BlendModes.js';
import { subBuild } from '../../nodes/core/SubBuildNode.js';
import { warn } from '../../utils.js';
import { error, warn } from '../../utils.js';

/**
* Base class for all node materials.
Expand Down Expand Up @@ -382,6 +382,14 @@ class NodeMaterial extends Material {
*/
this.vertexNode = null;

/**
* This node can be used as a global context management component for this material.
*
* @type {?ContextNode}
* @default null
*/
this.contextNode = null;

// Deprecated properties

Object.defineProperty( this, 'shadowPositionNode', { // @deprecated, r176
Expand Down Expand Up @@ -489,6 +497,32 @@ class NodeMaterial extends Material {
const renderer = builder.renderer;
const renderTarget = renderer.getRenderTarget();

// < CONTEXT >

if ( renderer.contextNode.isContextNode === true ) {

builder.context = { ...builder.context, ...renderer.contextNode.getFlowContextData() };

} else {

error( 'NodeMaterial: "renderer.contextNode" must be an instance of `context()`.' );

}

if ( this.contextNode !== null ) {

if ( this.contextNode.isContextNode === true ) {

builder.context = { ...builder.context, ...this.contextNode.getFlowContextData() };

} else {

error( 'NodeMaterial: "material.contextNode" must be an instance of `context()`.' );

}

}

// < VERTEX STAGE >

builder.addStack();
Expand Down Expand Up @@ -558,6 +592,14 @@ class NodeMaterial extends Material {

if ( isCustomOutput ) resultNode = this.outputNode;

//

if ( builder.context.getOutput ) {

resultNode = builder.context.getOutput( resultNode, builder );

}

// MRT

if ( renderTarget !== null ) {
Expand Down Expand Up @@ -1301,6 +1343,8 @@ class NodeMaterial extends Material {
this.fragmentNode = source.fragmentNode;
this.vertexNode = source.vertexNode;

this.contextNode = source.contextNode;

return super.copy( source );

}
Expand Down
2 changes: 1 addition & 1 deletion src/materials/nodes/manager/NodeMaterialObserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ class NodeMaterialObserver {

}

if ( builder.renderer.overrideNodes.modelViewMatrix !== null || builder.renderer.overrideNodes.modelNormalViewMatrix !== null )
if ( builder.context.modelViewMatrix || builder.context.modelNormalViewMatrix )
return true;

return false;
Expand Down
2 changes: 1 addition & 1 deletion src/nodes/accessors/ModelNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export const modelWorldMatrixInverse = /*@__PURE__*/ uniform( new Matrix4() ).on
*/
export const modelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => {

return builder.renderer.overrideNodes.modelViewMatrix || mediumpModelViewMatrix;
return builder.context.modelViewMatrix || mediumpModelViewMatrix;

} ).once() )().toVar( 'modelViewMatrix' );

Expand Down
4 changes: 2 additions & 2 deletions src/nodes/accessors/Normal.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ export const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorld
*/
export const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => {

const modelNormalViewMatrix = builder.renderer.overrideNodes.modelNormalViewMatrix;
const modelNormalViewMatrix = builder.context.modelNormalViewMatrix;

if ( modelNormalViewMatrix !== null ) {
if ( modelNormalViewMatrix ) {

return modelNormalViewMatrix.transformDirection( normal );

Expand Down
50 changes: 46 additions & 4 deletions src/nodes/core/ContextNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Node from './Node.js';
import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js';
import { addMethodChaining } from '../tsl/TSLCore.js';
import { warn } from '../../utils.js';

/**
Expand All @@ -9,6 +9,12 @@ import { warn } from '../../utils.js';
*
* ```js
*node.context( { getUV: () => customCoord } );
*\// or
*material.contextNode = context( { getUV: () => customCoord } );
*\// or
*renderer.contextNode = context( { getUV: () => customCoord } );
*\// or
*scenePass.contextNode = context( { getUV: () => customCoord } );
*```
* @augments Node
*/
Expand All @@ -26,7 +32,7 @@ class ContextNode extends Node {
* @param {Node} node - The node whose context should be modified.
* @param {Object} [value={}] - The modified context data.
*/
constructor( node, value = {} ) {
constructor( node = null, value = {} ) {

super();

Expand Down Expand Up @@ -79,6 +85,29 @@ class ContextNode extends Node {

}

/**
* Gathers the context data from all parent context nodes.
*
* @return {Object} The gathered context data.
*/
getFlowContextData() {

const children = [];

this.traverse( ( node ) => {

if ( node.isContextNode === true ) {

children.push( node.value );

}

} );

return Object.assign( {}, ...children );

}

/**
* This method is overwritten to ensure it returns the member type of {@link ContextNode#node}.
*
Expand Down Expand Up @@ -133,11 +162,24 @@ export default ContextNode;
*
* @tsl
* @function
* @param {Node} node - The node whose context should be modified.
* @param {Node|Object} [nodeOrValue={}] - The node whose context should be modified or the modified context data.
* @param {Object} [value={}] - The modified context data.
* @returns {ContextNode}
*/
export const context = /*@__PURE__*/ nodeProxy( ContextNode ).setParameterLength( 1, 2 );
export const context = /*@__PURE__*/ ( nodeOrValue = null, value = {} ) => {

let node = nodeOrValue;

if ( node === null || node.isNode !== true ) {

value = node || value;
node = null;

}

return new ContextNode( node, value );

};

/**
* TSL function for defining a uniformFlow context value for a given node.
Expand Down
35 changes: 34 additions & 1 deletion src/nodes/display/PassNode.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import TempNode from '../core/TempNode.js';
import { default as TextureNode/*, texture*/ } from '../accessors/TextureNode.js';
import { NodeUpdateType } from '../core/constants.js';
import { nodeObject } from '../tsl/TSLBase.js';
import { nodeObject, context } from '../tsl/TSLBase.js';
import { uniform } from '../core/UniformNode.js';
import { viewZToOrthographicDepth, perspectiveDepthToViewZ } from './ViewportDepthNode.js';

Expand Down Expand Up @@ -248,6 +248,22 @@ class PassNode extends TempNode {
*/
this.renderTarget = renderTarget;

/**
* An optional global context for the pass.
*
* @type {ContextNode|null}
*/
this.contextNode = null;

/**
* A cache for the context node.
*
* @private
* @type {?Object}
* @default null
*/
this._contextNodeCache = null;

/**
* A dictionary holding the internal result textures.
*
Expand Down Expand Up @@ -739,6 +755,7 @@ class PassNode extends TempNode {
const currentMRT = renderer.getMRT();
const currentAutoClear = renderer.autoClear;
const currentMask = camera.layers.mask;
const currentContextNode = renderer.contextNode;

this._cameraNear.value = camera.near;
this._cameraFar.value = camera.far;
Expand All @@ -759,6 +776,21 @@ class PassNode extends TempNode {
renderer.setMRT( this._mrt );
renderer.autoClear = true;

if ( this.contextNode !== null ) {

if ( this._contextNodeCache === null || this._contextNodeCache.version !== this.version ) {

this._contextNodeCache = {
version: this.version,
context: context( { ...renderer.contextNode.value, ...this.contextNode.getFlowContextData() } )
};

}

renderer.contextNode = this._contextNodeCache.context;

}

const currentSceneName = scene.name;

scene.name = this.name ? this.name : scene.name;
Expand All @@ -770,6 +802,7 @@ class PassNode extends TempNode {
renderer.setRenderTarget( currentRenderTarget );
renderer.setMRT( currentMRT );
renderer.autoClear = currentAutoClear;
renderer.contextNode = currentContextNode;

camera.layers.mask = currentMask;

Expand Down
2 changes: 1 addition & 1 deletion src/nodes/pmrem/PMREMNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ class PMREMNode extends TempNode {

if ( uvNode === null && builder.context.getUV ) {

uvNode = builder.context.getUV( this );
uvNode = builder.context.getUV( this, builder );

}

Expand Down
26 changes: 26 additions & 0 deletions src/nodes/utils/UVUtils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
import { Fn, vec2 } from '../tsl/TSLBase.js';
import { rotate } from './RotateNode.js';
import { context } from '../core/ContextNode.js';

/**
* Replaces the default UV coordinates used in texture lookups.
*
* ```js
*material.contextNode = replaceDefaultUV( ( textureNode ) => {
*
* // ...
* return customUVCoordinates;
*
*} );
*```
*
* @tsl
* @function
* @param {function(Node):Node<vec2>} callback - A callback that receives the texture node
* and must return the new uv coordinates.
* @param {Node} [node=null] - An optional node to which the context will be applied.
* @return {ContextNode} A context node that replaces the default UV coordinates.
*/
export function replaceDefaultUV( callback, node = null ) {

return context( node, { getUV: callback } );

}

/**
* Rotates the given uv coordinates around a center point
Expand Down
4 changes: 2 additions & 2 deletions src/renderers/common/Background.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import DataMap from './DataMap.js';
import Color4 from './Color4.js';
import { vec4, context, normalWorldGeometry, backgroundBlurriness, backgroundIntensity, backgroundRotation, positionLocal, cameraProjectionMatrix, modelViewMatrix, div } from '../../nodes/TSL.js';
import { vec4, normalWorldGeometry, backgroundBlurriness, backgroundIntensity, backgroundRotation, positionLocal, cameraProjectionMatrix, modelViewMatrix, div } from '../../nodes/TSL.js';
import NodeMaterial from '../../materials/nodes/NodeMaterial.js';

import { Mesh } from '../../objects/Mesh.js';
Expand Down Expand Up @@ -88,7 +88,7 @@ class Background extends DataMap {

if ( backgroundMesh === undefined ) {

const backgroundMeshNode = context( vec4( backgroundNode ).mul( backgroundIntensity ), {
const backgroundMeshNode = vec4( backgroundNode ).mul( backgroundIntensity ).context( {
// @TODO: Add Texture2D support using node context
getUV: () => backgroundRotation.mul( normalWorldGeometry ),
getTextureLevel: () => backgroundBlurriness
Expand Down
2 changes: 1 addition & 1 deletion src/renderers/common/RenderObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,7 @@ class RenderObject {

}

cacheKey = hash( cacheKey, this.camera.id );
cacheKey = hash( cacheKey, this.camera.id, this.renderer.contextNode.id, this.renderer.contextNode.version );

return cacheKey;

Expand Down
Loading