Skip to content

Commit a880e76

Browse files
authored
ProjectorLightNode: Fix back-projection. (#31473)
* ProjectorLightNode: Fix back-projection. * ProjectorLightNode: Clean up.
1 parent 1388d16 commit a880e76

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

src/nodes/lighting/ProjectorLightNode.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import SpotLightNode from './SpotLightNode.js';
22

3-
import { Fn, vec2 } from '../tsl/TSLCore.js';
3+
import { float, Fn, If, vec2 } from '../tsl/TSLCore.js';
44
import { length, min, max, saturate, acos } from '../math/MathNode.js';
55
import { div, sub } from '../math/OperatorNode.js';
6+
import { lightShadowMatrix } from '../accessors/Lights.js';
7+
import { positionWorld } from '../accessors/Position.js';
68

79
const sdBox = /*@__PURE__*/ Fn( ( [ p, b ] ) => {
810

@@ -61,13 +63,24 @@ class ProjectorLightNode extends SpotLightNode {
6163
*/
6264
getSpotAttenuation( builder ) {
6365

66+
const attenuation = float( 0 ).toVar();
6467
const penumbraCos = this.penumbraCosNode;
65-
const spotLightCoord = this.getLightCoord( builder );
66-
const coord = spotLightCoord.xyz.div( spotLightCoord.w );
6768

68-
const boxDist = sdBox( coord.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) );
69-
const angleFactor = div( - 1.0, sub( 1.0, acos( penumbraCos ) ).sub( 1.0 ) );
70-
const attenuation = saturate( boxDist.mul( - 2.0 ).mul( angleFactor ) );
69+
// compute the fragment's position in the light's clip space
70+
71+
const spotLightCoord = lightShadowMatrix( this.light ).mul( builder.context.positionWorld || positionWorld );
72+
73+
// the sign of w determines whether the current fragment is in front or behind the light.
74+
// to avoid a back-projection, it's important to only compute an attenuation if w is positive
75+
76+
If( spotLightCoord.w.greaterThan( 0 ), () => {
77+
78+
const projectionUV = spotLightCoord.xyz.div( spotLightCoord.w );
79+
const boxDist = sdBox( projectionUV.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) );
80+
const angleFactor = div( - 1.0, sub( 1.0, acos( penumbraCos ) ).sub( 1.0 ) );
81+
attenuation.assign( saturate( boxDist.mul( - 2.0 ).mul( angleFactor ) ) );
82+
83+
} );
7184

7285
return attenuation;
7386

0 commit comments

Comments
 (0)