Skip to content

Commit 9e9a8b7

Browse files
sunagRuthySheffi
authored andcommitted
SpotLightNode: Add custom attenuation using spotLight.attenuationNode (mrdoob#31013)
* add custom attenuation * cleanup
1 parent 21ca49a commit 9e9a8b7

File tree

4 files changed

+56
-7
lines changed

4 files changed

+56
-7
lines changed

examples/webgpu_lights_spotlight.html

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<script type="module">
2727

2828
import * as THREE from 'three';
29+
import { Fn, vec2, length, abs, max, min, div, mul, clamp, acos } from 'three/tsl';
2930

3031
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
3132

@@ -86,13 +87,35 @@
8687

8788
}
8889

90+
const boxAttenuationFn = Fn( ( [ lightNode ], builder ) => {
91+
92+
const sdBox = Fn( ( [ p, b ] ) => {
93+
94+
const d = vec2( abs( p ).sub( b ) ).toVar();
95+
96+
return length( max( d, 0.0 ) ).add( min( max( d.x, d.y ), 0.0 ) );
97+
98+
} );
99+
100+
const penumbraCos = lightNode.penumbraCosNode;
101+
const spotLightCoord = lightNode.getSpotLightCoord( builder );
102+
const coord = spotLightCoord.xyz.div( spotLightCoord.w );
103+
104+
const boxDist = sdBox( coord.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) );
105+
const angleFactor = div( 1.0, acos( penumbraCos ).sub( 1.0 ) );
106+
const attenuation = clamp( mul( 2.0, boxDist ).mul( angleFactor ), 0.0, 1.0 );
107+
108+
return attenuation;
109+
110+
} );
111+
89112
spotLight = new THREE.SpotLight( 0xffffff, 100 );
113+
spotLight.map = textures[ 'disturb.jpg' ];
90114
spotLight.position.set( 2.5, 5, 2.5 );
91115
spotLight.angle = Math.PI / 6;
92116
spotLight.penumbra = 1;
93117
spotLight.decay = 2;
94118
spotLight.distance = 0;
95-
spotLight.map = textures[ 'disturb.jpg' ];
96119

97120
spotLight.castShadow = true;
98121
spotLight.shadow.mapSize.width = 1024;
@@ -150,7 +173,8 @@
150173
penumbra: spotLight.penumbra,
151174
decay: spotLight.decay,
152175
focus: spotLight.shadow.focus,
153-
shadows: true
176+
shadows: true,
177+
customAttenuation: false
154178
};
155179

156180
gui.add( params, 'map', textures ).onChange( function ( val ) {
@@ -202,7 +226,6 @@
202226

203227
} );
204228

205-
206229
gui.add( params, 'shadows' ).onChange( function ( val ) {
207230

208231
renderer.shadowMap.enabled = val;
@@ -219,6 +242,12 @@
219242

220243
} );
221244

245+
gui.add( params, 'customAttenuation' ).name( 'custom attenuation' ).onChange( function ( val ) {
246+
247+
spotLight.attenuationNode = val ? boxAttenuationFn : null;
248+
249+
} );
250+
222251
gui.open();
223252

224253
}

src/nodes/lighting/LightsNode.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,10 @@ class LightsNode extends Node {
125125

126126
if ( light.isSpotLight === true ) {
127127

128-
const hashValue = ( light.map !== null ) ? light.map.id : - 1;
128+
const hashMap = ( light.map !== null ) ? light.map.id : - 1;
129+
const hashAttenuation = ( light.attenuationNode ) ? light.attenuationNode.id : - 1;
129130

130-
hashData.push( hashValue );
131+
hashData.push( hashMap, hashAttenuation );
131132

132133
}
133134

src/nodes/lighting/SpotLightNode.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,23 @@ class SpotLightNode extends AnalyticLightNode {
9191

9292
}
9393

94+
getSpotLightCoord( builder ) {
95+
96+
const properties = builder.getNodeProperties( this );
97+
let projectionUV = properties.projectionUV;
98+
99+
if ( projectionUV === undefined ) {
100+
101+
projectionUV = lightProjectionUV( this.light, builder.context.positionWorld );
102+
103+
properties.projectionUV = projectionUV;
104+
105+
}
106+
107+
return projectionUV;
108+
109+
}
110+
94111
setupDirect( builder ) {
95112

96113
const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this;
@@ -99,7 +116,8 @@ class SpotLightNode extends AnalyticLightNode {
99116

100117
const lightDirection = lightVector.normalize();
101118
const angleCos = lightDirection.dot( lightTargetDirection( light ) );
102-
const spotAttenuation = this.getSpotAttenuation( angleCos );
119+
120+
const spotAttenuation = light.attenuationNode ? light.attenuationNode( this ) : this.getSpotAttenuation( angleCos );
103121

104122
const lightDistance = lightVector.length();
105123

@@ -113,7 +131,7 @@ class SpotLightNode extends AnalyticLightNode {
113131

114132
if ( light.map ) {
115133

116-
const spotLightCoord = lightProjectionUV( light, builder.context.positionWorld );
134+
const spotLightCoord = this.getSpotLightCoord( builder );
117135
const projectedTexture = texture( light.map, spotLightCoord.xy ).onRenderUpdate( () => light.map );
118136

119137
const inSpotLightMap = spotLightCoord.mul( 2. ).sub( 1. ).abs().lessThan( 1. ).all();

src/nodes/tsl/TSLCore.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ export const Fn = ( jsFunc, layout = null ) => {
619619
};
620620

621621
fn.shaderNode = shaderNode;
622+
fn.id = shaderNode.id;
622623

623624
fn.setLayout = ( layout ) => {
624625

0 commit comments

Comments
 (0)