Skip to content
Merged
Changes from 1 commit
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
Next Next commit
ProjectorLightNode: Fix back-projection.
  • Loading branch information
Mugen87 committed Jul 22, 2025
commit 12964ce630d5098953265acecbaba16ded09d2c2
23 changes: 17 additions & 6 deletions src/nodes/lighting/ProjectorLightNode.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import SpotLightNode from './SpotLightNode.js';

import { Fn, vec2 } from '../tsl/TSLCore.js';
import { float, Fn, If, vec2 } from '../tsl/TSLCore.js';
import { length, min, max, saturate, acos } from '../math/MathNode.js';
import { div, sub } from '../math/OperatorNode.js';
import { lightShadowMatrix } from '../accessors/Lights.js';
import { positionWorld } from '../accessors/Position.js';

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

Expand Down Expand Up @@ -62,12 +64,21 @@ class ProjectorLightNode extends SpotLightNode {
getSpotAttenuation( builder ) {

const penumbraCos = this.penumbraCosNode;
const spotLightCoord = this.getLightCoord( builder );
Comment thread
sunag marked this conversation as resolved.
const coord = spotLightCoord.xyz.div( spotLightCoord.w );
Comment thread
sunag marked this conversation as resolved.
const spotLightCoord = lightShadowMatrix( this.light ).mul( builder.context.positionWorld || positionWorld );

const boxDist = sdBox( coord.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) );
const angleFactor = div( - 1.0, sub( 1.0, acos( penumbraCos ) ).sub( 1.0 ) );
const attenuation = saturate( boxDist.mul( - 2.0 ).mul( angleFactor ) );
const attenuation = float( 0 ).toVar( 'attenuation' );

// the sign of w determines whether the current fragment is in front or behind the light
// to avoid a back-projection, it's important to only compute an attenuation if w is positive

If( spotLightCoord.w.greaterThan( 0 ), () => {

const projectionUV = spotLightCoord.xyz.div( spotLightCoord.w );
const boxDist = sdBox( projectionUV.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) );
const angleFactor = div( - 1.0, sub( 1.0, acos( penumbraCos ) ).sub( 1.0 ) );
attenuation.assign( saturate( boxDist.mul( - 2.0 ).mul( angleFactor ) ) );

} );

return attenuation;

Expand Down