Просмотр исходного кода

ProjectorLightNode: Fix back-projection. (#31473)

* ProjectorLightNode: Fix back-projection.

* ProjectorLightNode: Clean up.
Michael Herzog 5 месяцев назад
Родитель
Сommit
a880e76453
1 измененных файлов с 19 добавлено и 6 удалено
  1. 19 6
      src/nodes/lighting/ProjectorLightNode.js

+ 19 - 6
src/nodes/lighting/ProjectorLightNode.js

@@ -1,8 +1,10 @@
 import SpotLightNode from './SpotLightNode.js';
 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 { length, min, max, saturate, acos } from '../math/MathNode.js';
 import { div, sub } from '../math/OperatorNode.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 ] ) => {
 const sdBox = /*@__PURE__*/ Fn( ( [ p, b ] ) => {
 
 
@@ -61,13 +63,24 @@ class ProjectorLightNode extends SpotLightNode {
 	 */
 	 */
 	getSpotAttenuation( builder ) {
 	getSpotAttenuation( builder ) {
 
 
+		const attenuation = float( 0 ).toVar();
 		const penumbraCos = this.penumbraCosNode;
 		const penumbraCos = this.penumbraCosNode;
-		const spotLightCoord = this.getLightCoord( builder );
-		const coord = spotLightCoord.xyz.div( spotLightCoord.w );
 
 
-		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 ) );
+		// compute the fragment's position in the light's clip space
+
+		const spotLightCoord = lightShadowMatrix( this.light ).mul( builder.context.positionWorld || positionWorld );
+
+		// 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;
 		return attenuation;
 
 

粤ICP备19079148号