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
78 changes: 14 additions & 64 deletions examples/jsm/tsl/WebGLNodesHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,6 @@ class WebGLNodeBuilder extends GLSLNodeBuilder {

}

const _lights = new Set();
let _camera = null;

function collectLight( child ) {

if ( child.isLight && child.layers.test( _camera.layers ) ) _lights.add( child );

}

// produce and update reusable nodes for a scene
class SceneContext {

Expand All @@ -104,7 +95,6 @@ class SceneContext {
// TODO: can / should we update the fog and environment node every frame for recompile?
this.renderer = renderer;
this.scene = scene;
this.sceneLights = [];
this.lightsNode = renderer.lighting.getNode( scene );
this.fogNode = null;
this.environmentNode = null;
Expand All @@ -123,25 +113,9 @@ class SceneContext {

}

update( object, camera ) {

const { scene, lightsNode, sceneLights } = this;

// update lighting
_camera = camera;
_lights.clear();

scene.traverseVisible( collectLight );
update() {

// compile() can receive an object that has not been added to the target scene yet.
if ( object !== scene ) object.traverseVisible( collectLight );

_camera = null;

sceneLights.length = 0;
sceneLights.push( ..._lights );

lightsNode.setLights( sceneLights );
const { scene } = this;

// update fog
if ( this.prevFog !== scene.fog ) {
Expand Down Expand Up @@ -413,17 +387,6 @@ export class WebGLNodesHandler {
}


setupNodeMaterial( material ) {

if ( material && material.isNodeMaterial ) {

material.customProgramCacheKey = this.customProgramCacheKeyCallback;
material.onBeforeRender = this.onBeforeRenderCallback;

}

}

renderStart( scene, camera, targetScene = scene ) {

const { nodeFrame, renderStack, renderer, sceneContexts } = this;
Expand All @@ -440,40 +403,25 @@ export class WebGLNodesHandler {

}

sceneContext.update( scene, camera );
renderer.lighting.beginRender( targetScene );
sceneContext.update();
renderStack.push( { sceneContext, camera } );

// ensure all node material callbacks are initialized before
// traversal and build
scene.traverse( object => {

const material = object.material;

if ( material === undefined ) return;

if ( Array.isArray( material ) ) {

for ( let i = 0; i < material.length; i ++ ) {

this.setupNodeMaterial( material[ i ] );

}

} else {

this.setupNodeMaterial( material );
}

}
updateLights( lights ) {

} );
const frame = this.renderStack[ this.renderStack.length - 1 ];
frame.sceneContext.lightsNode.setLights( lights );

}

renderEnd() {

const { nodeFrame, renderStack } = this;
const { nodeFrame, renderer, renderStack } = this;

renderStack.pop();
const { sceneContext } = renderStack.pop();
renderer.lighting.finishRender( sceneContext.scene );

const frame = renderStack[ renderStack.length - 1 ];
if ( frame ) {
Expand All @@ -486,9 +434,11 @@ export class WebGLNodesHandler {

}

setObject( object ) {
setObject( object, material ) {

this.nodeFrame.object = object;
material.customProgramCacheKey = this.customProgramCacheKeyCallback;
material.onBeforeRender = this.onBeforeRenderCallback;

}

Expand Down
5 changes: 4 additions & 1 deletion src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ class WebGLRenderer {

function prepareMaterial( material, scene, object ) {

if ( _nodesHandler !== null && material.isNodeMaterial ) _nodesHandler.setObject( object );
if ( _nodesHandler !== null && material.isNodeMaterial ) _nodesHandler.setObject( object, material );

if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {

Expand Down Expand Up @@ -1436,6 +1436,7 @@ class WebGLRenderer {
}

currentRenderState.setupLights();
if ( _nodesHandler !== null ) _nodesHandler.updateLights( currentRenderState.state.lightsArray );

// node materials reference the shadow map when they are built, so it must exist by now

Expand Down Expand Up @@ -1697,6 +1698,7 @@ class WebGLRenderer {
projectObject( scene, camera, 0, _this.sortObjects );

currentRenderList.finish();
if ( _nodesHandler !== null ) _nodesHandler.updateLights( currentRenderState.state.lightsArray );

if ( _this.sortObjects === true ) {

Expand Down Expand Up @@ -2141,6 +2143,7 @@ class WebGLRenderer {

function renderObject( object, scene, camera, geometry, material, group ) {

if ( _nodesHandler !== null && material.isNodeMaterial ) _nodesHandler.setObject( object, material );
object.onBeforeRender( _this, scene, camera, geometry, material, group );

object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
Expand Down
3 changes: 0 additions & 3 deletions src/renderers/webgpu/nodes/WGSLNodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,6 @@ class WGSLNodeBuilder extends NodeBuilder {
* @param {string} gatherSnippet - A WGSL snippet that represents the index of the channel to read.
* @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
* @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
* @param {?string} flipYSnippet - A WGSL snippet that represents the y-flip. Only used for WebGL.
* @return {string} The WGSL snippet.
*/
generateTextureGather( texture, textureProperty, uvSnippet, gatherSnippet, depthSnippet, offsetSnippet ) {
Expand Down Expand Up @@ -1026,7 +1025,6 @@ class WGSLNodeBuilder extends NodeBuilder {
* @param {string} compareSnippet - A WGSL snippet that represents the reference value.
* @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
* @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
* @param {?string} flipYSnippet - A WGSL snippet that represents the y-flip. Only used for WebGL.
* @return {string} The WGSL snippet.
*/
generateTextureGatherCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet ) {
Expand Down Expand Up @@ -1062,7 +1060,6 @@ class WGSLNodeBuilder extends NodeBuilder {
* @param {string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
* @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
* @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
* @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
* @return {string} The WGSL snippet.
*/
generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ) {
Expand Down
49 changes: 49 additions & 0 deletions test/unit/addons/tsl/WebGLNodesHandler.tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
AmbientLight,
PerspectiveCamera,
PointLight,
Scene,
} from 'three';
import { WebGLNodesHandler } from '../../../../examples/jsm/tsl/WebGLNodesHandler.js';

export default QUnit.module( 'Addons', () => {

QUnit.module( 'TSL', () => {

QUnit.module( 'WebGLNodesHandler', () => {

QUnit.test( 'nested render lifecycle', ( assert ) => {

const handler = new WebGLNodesHandler();
handler.setRenderer( {
extensions: {},
getContext: () => ( {} ),
} );
assert.strictEqual( handler.nodeFrame.renderer, handler.renderer, 'initializes the renderer proxy' );

const scene = new Scene();
const outerCamera = new PerspectiveCamera();
const nestedCamera = new PerspectiveCamera();
const outerLight = new AmbientLight();
const nestedLight = new PointLight();

handler.renderStart( scene, outerCamera );
handler.updateLights( [ outerLight ] );
handler.renderStart( scene, nestedCamera );
handler.updateLights( [ nestedLight ] );
handler.renderEnd();

const sceneContext = handler.renderStack[ 0 ].sceneContext;
assert.deepEqual( sceneContext.lightsNode.getLights(), [ outerLight ], 'restores lights for the outer render' );
assert.strictEqual( handler.nodeFrame.camera, outerCamera, 'restores the outer camera' );

handler.renderEnd();
assert.strictEqual( handler.renderStack.length, 0, 'balances the render stack' );

} );

} );

} );

} );
1 change: 1 addition & 0 deletions test/unit/three.addons.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ import './addons/loaders/SPLATLoader.tests.js';
import './addons/loaders/SPZLoader.tests.js';
import './addons/loaders/USDLoader.tests.js';
import './addons/exporters/USDZExporter.tests.js';
import './addons/tsl/WebGLNodesHandler.tests.js';