Skip to content
Closed
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
134 changes: 99 additions & 35 deletions examples/jsm/tsl/lighting/DynamicLightsNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LightsNode, NodeUtils, warn } from 'three/webgpu';
import { nodeObject } from 'three/tsl';
import { clearcoatNormalView, nodeObject, normalView, positionViewDirection } from 'three/tsl';

import AmbientLightDataNode from './data/AmbientLightDataNode.js';
import DirectionalLightDataNode from './data/DirectionalLightDataNode.js';
Expand All @@ -25,20 +25,42 @@ const _lightTypeToMaxProp = {
HemisphereLight: 'maxHemisphereLights'
};

const _persistentBatchLightTypes = [
'PointLight',
'SpotLight'
];

const _batchLightTypes = [
'AmbientLight',
'DirectionalLight',
'PointLight',
'SpotLight',
'HemisphereLight'
];

const sortLights = ( lights ) => lights.sort( ( a, b ) => a.id - b.id );

const isSpecialSpotLight = ( light ) => {

return light.isSpotLight === true && ( light.map !== null || light.colorNode !== undefined );
return light.isSpotLight === true && (
light.map !== null ||
light.colorNode !== undefined ||
( light.iesMap && light.iesMap.isTexture === true )
);

};

const canBatchLight = ( light ) => {
const getBatchLightType = ( light ) => {

if ( light.isNode === true || light.castShadow === true || isSpecialSpotLight( light ) === true ) return null;

return light.isNode !== true &&
light.castShadow !== true &&
isSpecialSpotLight( light ) === false &&
_lightTypeToDataNode[ light.constructor.name ] !== undefined;
if ( light.isAmbientLight === true ) return 'AmbientLight';
if ( light.isDirectionalLight === true ) return 'DirectionalLight';
if ( light.isPointLight === true && light.isSpotLight !== true ) return 'PointLight';
if ( light.isSpotLight === true ) return 'SpotLight';
if ( light.isHemisphereLight === true ) return 'HemisphereLight';

return null;

};

Expand Down Expand Up @@ -100,6 +122,7 @@ class DynamicLightsNode extends LightsNode {
this.maxHemisphereLights = options.maxHemisphereLights !== undefined ? options.maxHemisphereLights : 4;

this._dataNodes = new Map();
this._initPersistentDataNodes();

}

Expand All @@ -110,10 +133,11 @@ class DynamicLightsNode extends LightsNode {
for ( let i = 0; i < this._lights.length; i ++ ) {

const light = this._lights[ i ];
const typeName = getBatchLightType( light );

if ( canBatchLight( light ) ) {
if ( typeName !== null ) {

typeSet.add( light.constructor.name );
typeSet.add( typeName );

} else {

Expand All @@ -124,8 +148,9 @@ class DynamicLightsNode extends LightsNode {

const hashMap = light.map !== null ? light.map.id : - 1;
const hashColorNode = light.colorNode ? light.colorNode.getCacheKey() : - 1;
const hashIESMap = light.iesMap && light.iesMap.isTexture === true ? light.iesMap.id : - 1;

_hashData.push( hashMap, hashColorNode );
_hashData.push( hashMap, hashColorNode, hashIESMap );

}

Expand Down Expand Up @@ -169,9 +194,10 @@ class DynamicLightsNode extends LightsNode {

}

if ( canBatchLight( light ) ) {
const typeName = getBatchLightType( light );

if ( typeName !== null ) {

const typeName = light.constructor.name;
const typeLights = lightsByType.get( typeName );

if ( typeLights === undefined ) {
Expand All @@ -198,39 +224,29 @@ class DynamicLightsNode extends LightsNode {

}

for ( const [ typeName, typeLights ] of lightsByType ) {

let dataNode = this._dataNodes.get( typeName );
for ( const typeName of _batchLightTypes ) {

if ( dataNode === undefined ) {

const DataNodeClass = _lightTypeToDataNode[ typeName ];
const maxProp = _lightTypeToMaxProp[ typeName ];
const maxCount = maxProp !== undefined ? this[ maxProp ] : undefined;

dataNode = maxCount !== undefined ? new DataNodeClass( maxCount ) : new DataNodeClass();
const typeLights = lightsByType.get( typeName );
const hasType = typeLights !== undefined || this._dataNodes.has( typeName ) === true;

this._dataNodes.set( typeName, dataNode );
if ( hasType === false ) continue;

}
const dataNode = this._getDataNode( typeName );

dataNode.setLights( typeLights );
dataNode.setLights( typeLights || [] );
lightNodes.push( dataNode );

}

for ( const [ typeName, dataNode ] of this._dataNodes ) {

if ( lightsByType.has( typeName ) === false ) {
this._lightNodes = lightNodes;

dataNode.setLights( [] );
lightNodes.push( dataNode );
}

}
setupLights( builder, lightNodes ) {

}
this._setupSharedLightingInputs( builder );

this._lightNodes = lightNodes;
super.setupLights( builder, lightNodes );

}

Expand All @@ -248,15 +264,63 @@ class DynamicLightsNode extends LightsNode {

}

_setupSharedLightingInputs( builder ) {

normalView.toStack();
positionViewDirection.toStack();

if ( builder.context.lightingModel?.clearcoat === true ) {

clearcoatNormalView.toStack();

}

}

_initPersistentDataNodes() {

for ( const typeName of _persistentBatchLightTypes ) {

const maxProp = _lightTypeToMaxProp[ typeName ];
const maxCount = maxProp !== undefined ? this[ maxProp ] : undefined;

if ( maxCount !== undefined && maxCount <= 0 ) continue;

this._getDataNode( typeName );

}

}

_getDataNode( typeName ) {

let dataNode = this._dataNodes.get( typeName );

if ( dataNode === undefined ) {

const DataNodeClass = _lightTypeToDataNode[ typeName ];
const maxProp = _lightTypeToMaxProp[ typeName ];
const maxCount = maxProp !== undefined ? this[ maxProp ] : undefined;

dataNode = maxCount !== undefined ? new DataNodeClass( maxCount ) : new DataNodeClass();

this._dataNodes.set( typeName, dataNode );

}

return dataNode;

}

_updateDataNodeLights( lights ) {

const lightsByType = new Map();

for ( const light of lights ) {

if ( canBatchLight( light ) === false ) continue;
const typeName = getBatchLightType( light );

const typeName = light.constructor.name;
if ( typeName === null ) continue;
const typeLights = lightsByType.get( typeName );

if ( typeLights === undefined ) {
Expand Down
5 changes: 4 additions & 1 deletion examples/jsm/tsl/lighting/data/DirectionalLightDataNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Color, Node, Vector3 } from 'three/webgpu';
import { Loop, NodeUpdateType, renderGroup, uniform, uniformArray, vec3 } from 'three/tsl';
import { Loop, NodeUpdateType, normalView, positionViewDirection, renderGroup, uniform, uniformArray, vec3 } from 'three/tsl';

const _lightPosition = /*@__PURE__*/ new Vector3();
const _targetPosition = /*@__PURE__*/ new Vector3();
Expand Down Expand Up @@ -87,6 +87,9 @@ class DirectionalLightDataNode extends Node {
const dynDiffuse = vec3( 0 ).toVar( 'dynDirectionalDiffuse' );
const dynSpecular = vec3( 0 ).toVar( 'dynDirectionalSpecular' );

normalView.toStack();
positionViewDirection.toStack();

Loop( this.countNode, ( { i } ) => {

const lightColor = this.colorsNode.element( i ).toVar();
Expand Down
5 changes: 4 additions & 1 deletion examples/jsm/tsl/lighting/data/PointLightDataNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Color, Node, Vector3, Vector4 } from 'three/webgpu';
import { Loop, NodeUpdateType, getDistanceAttenuation, positionView, renderGroup, uniform, uniformArray, vec3 } from 'three/tsl';
import { Loop, NodeUpdateType, getDistanceAttenuation, normalView, positionView, positionViewDirection, renderGroup, uniform, uniformArray, vec3 } from 'three/tsl';

const _position = /*@__PURE__*/ new Vector3();

Expand Down Expand Up @@ -96,6 +96,9 @@ class PointLightDataNode extends Node {
const dynDiffuse = vec3( 0 ).toVar( 'dynPointDiffuse' );
const dynSpecular = vec3( 0 ).toVar( 'dynPointSpecular' );

normalView.toStack();
positionViewDirection.toStack();

Loop( this.countNode, ( { i } ) => {

const positionAndCutoff = this.positionsAndCutoffNode.element( i );
Expand Down
5 changes: 4 additions & 1 deletion examples/jsm/tsl/lighting/data/SpotLightDataNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Color, Node, Vector3, Vector4 } from 'three/webgpu';
import { Loop, NodeUpdateType, getDistanceAttenuation, positionView, renderGroup, smoothstep, uniform, uniformArray, vec3 } from 'three/tsl';
import { Loop, NodeUpdateType, getDistanceAttenuation, normalView, positionView, positionViewDirection, renderGroup, smoothstep, uniform, uniformArray, vec3 } from 'three/tsl';

const _lightPosition = /*@__PURE__*/ new Vector3();
const _targetPosition = /*@__PURE__*/ new Vector3();
Expand Down Expand Up @@ -114,6 +114,9 @@ class SpotLightDataNode extends Node {
const dynDiffuse = vec3( 0 ).toVar( 'dynSpotDiffuse' );
const dynSpecular = vec3( 0 ).toVar( 'dynSpotSpecular' );

normalView.toStack();
positionViewDirection.toStack();

Loop( this.countNode, ( { i } ) => {

const positionAndCutoff = this.positionsAndCutoffNode.element( i );
Expand Down
Loading