|
@@ -2,16 +2,66 @@ import LightingNode from './LightingNode.js';
|
|
|
import { NodeUpdateType } from '../core/constants.js';
|
|
import { NodeUpdateType } from '../core/constants.js';
|
|
|
import { uniform } from '../core/UniformNode.js';
|
|
import { uniform } from '../core/UniformNode.js';
|
|
|
import { addNodeClass } from '../core/Node.js';
|
|
import { addNodeClass } from '../core/Node.js';
|
|
|
-import { vec3, vec4 } from '../shadernode/ShaderNode.js';
|
|
|
|
|
|
|
+import { float, vec2, vec3, vec4 } from '../shadernode/ShaderNode.js';
|
|
|
import { reference } from '../accessors/ReferenceNode.js';
|
|
import { reference } from '../accessors/ReferenceNode.js';
|
|
|
import { texture } from '../accessors/TextureNode.js';
|
|
import { texture } from '../accessors/TextureNode.js';
|
|
|
import { positionWorld } from '../accessors/PositionNode.js';
|
|
import { positionWorld } from '../accessors/PositionNode.js';
|
|
|
import { normalWorld } from '../accessors/NormalNode.js';
|
|
import { normalWorld } from '../accessors/NormalNode.js';
|
|
|
import { mix } from '../math/MathNode.js';
|
|
import { mix } from '../math/MathNode.js';
|
|
|
-//import { add } from '../math/OperatorNode.js';
|
|
|
|
|
|
|
+import { add } from '../math/OperatorNode.js';
|
|
|
import { Color } from '../../math/Color.js';
|
|
import { Color } from '../../math/Color.js';
|
|
|
import { DepthTexture } from '../../textures/DepthTexture.js';
|
|
import { DepthTexture } from '../../textures/DepthTexture.js';
|
|
|
-import { NearestFilter, LessCompare, NoToneMapping, WebGPUCoordinateSystem } from '../../constants.js';
|
|
|
|
|
|
|
+import { tslFn } from '../shadernode/ShaderNode.js';
|
|
|
|
|
+import { LessCompare, WebGPUCoordinateSystem } from '../../constants.js';
|
|
|
|
|
+
|
|
|
|
|
+const BasicShadowMap = tslFn( ( { depthTexture, shadowCoord } ) => {
|
|
|
|
|
+
|
|
|
|
|
+ return texture( depthTexture, shadowCoord.xy ).compare( shadowCoord.z );
|
|
|
|
|
+
|
|
|
|
|
+} );
|
|
|
|
|
+
|
|
|
|
|
+const PCFShadowMap = tslFn( ( { depthTexture, shadowCoord, shadow } ) => {
|
|
|
|
|
+
|
|
|
|
|
+ const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare );
|
|
|
|
|
+
|
|
|
|
|
+ const mapSize = reference( 'mapSize', 'vec2', shadow );
|
|
|
|
|
+ const radius = reference( 'radius', 'float', shadow );
|
|
|
|
|
+
|
|
|
|
|
+ const texelSize = vec2( 1 ).div( mapSize );
|
|
|
|
|
+ const dx0 = texelSize.x.negate().mul( radius );
|
|
|
|
|
+ const dy0 = texelSize.y.negate().mul( radius );
|
|
|
|
|
+ const dx1 = texelSize.x.mul( radius );
|
|
|
|
|
+ const dy1 = texelSize.y.mul( radius );
|
|
|
|
|
+ const dx2 = dx0.div( 2 );
|
|
|
|
|
+ const dy2 = dy0.div( 2 );
|
|
|
|
|
+ const dx3 = dx1.div( 2 );
|
|
|
|
|
+ const dy3 = dy1.div( 2 );
|
|
|
|
|
+
|
|
|
|
|
+ return add(
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy, shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ),
|
|
|
|
|
+ depthCompare( shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z )
|
|
|
|
|
+ ).mul( 1 / 17 );
|
|
|
|
|
+
|
|
|
|
|
+} );
|
|
|
|
|
+
|
|
|
|
|
+const shadowFilterLib = [ BasicShadowMap, PCFShadowMap ];
|
|
|
|
|
+
|
|
|
|
|
+//
|
|
|
|
|
|
|
|
let overrideMaterial = null;
|
|
let overrideMaterial = null;
|
|
|
|
|
|
|
@@ -25,15 +75,14 @@ class AnalyticLightNode extends LightingNode {
|
|
|
|
|
|
|
|
this.light = light;
|
|
this.light = light;
|
|
|
|
|
|
|
|
- this.rtt = null;
|
|
|
|
|
- this.shadowNode = null;
|
|
|
|
|
- this.shadowMaskNode = null;
|
|
|
|
|
-
|
|
|
|
|
this.color = new Color();
|
|
this.color = new Color();
|
|
|
- this._defaultColorNode = uniform( this.color );
|
|
|
|
|
- this._shadowColorNode = null;
|
|
|
|
|
|
|
+ this.colorNode = uniform( this.color );
|
|
|
|
|
+
|
|
|
|
|
+ this.baseColorNode = null;
|
|
|
|
|
|
|
|
- this.colorNode = this._defaultColorNode;
|
|
|
|
|
|
|
+ this.shadowMap = null;
|
|
|
|
|
+ this.shadowNode = null;
|
|
|
|
|
+ this.shadowColorNode = null;
|
|
|
|
|
|
|
|
this.isAnalyticLightNode = true;
|
|
this.isAnalyticLightNode = true;
|
|
|
|
|
|
|
@@ -53,19 +102,11 @@ class AnalyticLightNode extends LightingNode {
|
|
|
|
|
|
|
|
setupShadow( builder ) {
|
|
setupShadow( builder ) {
|
|
|
|
|
|
|
|
- const { object } = builder;
|
|
|
|
|
-
|
|
|
|
|
- if ( object.receiveShadow === false ) {
|
|
|
|
|
|
|
+ const { object, renderer } = builder;
|
|
|
|
|
|
|
|
- this.colorNode = this._defaultColorNode;
|
|
|
|
|
|
|
+ let shadowColorNode = this.shadowColorNode;
|
|
|
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let shadowNode = this.shadowNode;
|
|
|
|
|
-
|
|
|
|
|
- if ( shadowNode === null ) {
|
|
|
|
|
|
|
+ if ( shadowColorNode === null ) {
|
|
|
|
|
|
|
|
if ( overrideMaterial === null ) {
|
|
if ( overrideMaterial === null ) {
|
|
|
|
|
|
|
@@ -75,17 +116,12 @@ class AnalyticLightNode extends LightingNode {
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const shadow = this.light.shadow;
|
|
|
|
|
- const rtt = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height );
|
|
|
|
|
-
|
|
|
|
|
const depthTexture = new DepthTexture();
|
|
const depthTexture = new DepthTexture();
|
|
|
- depthTexture.minFilter = NearestFilter;
|
|
|
|
|
- depthTexture.magFilter = NearestFilter;
|
|
|
|
|
- depthTexture.image.width = shadow.mapSize.width;
|
|
|
|
|
- depthTexture.image.height = shadow.mapSize.height;
|
|
|
|
|
depthTexture.compareFunction = LessCompare;
|
|
depthTexture.compareFunction = LessCompare;
|
|
|
|
|
|
|
|
- rtt.depthTexture = depthTexture;
|
|
|
|
|
|
|
+ const shadow = this.light.shadow;
|
|
|
|
|
+ const shadowMap = builder.createRenderTarget( shadow.mapSize.width, shadow.mapSize.height );
|
|
|
|
|
+ shadowMap.depthTexture = depthTexture;
|
|
|
|
|
|
|
|
shadow.camera.updateProjectionMatrix();
|
|
shadow.camera.updateProjectionMatrix();
|
|
|
|
|
|
|
@@ -100,15 +136,9 @@ class AnalyticLightNode extends LightingNode {
|
|
|
let shadowCoord = uniform( shadow.matrix ).mul( position.add( normalWorld.mul( normalBias ) ) );
|
|
let shadowCoord = uniform( shadow.matrix ).mul( position.add( normalWorld.mul( normalBias ) ) );
|
|
|
shadowCoord = shadowCoord.xyz.div( shadowCoord.w );
|
|
shadowCoord = shadowCoord.xyz.div( shadowCoord.w );
|
|
|
|
|
|
|
|
- const frustumTest = shadowCoord.x.greaterThanEqual( 0 )
|
|
|
|
|
- .and( shadowCoord.x.lessThanEqual( 1 ) )
|
|
|
|
|
- .and( shadowCoord.y.greaterThanEqual( 0 ) )
|
|
|
|
|
- .and( shadowCoord.y.lessThanEqual( 1 ) )
|
|
|
|
|
- .and( shadowCoord.z.lessThanEqual( 1 ) );
|
|
|
|
|
-
|
|
|
|
|
let coordZ = shadowCoord.z.add( bias );
|
|
let coordZ = shadowCoord.z.add( bias );
|
|
|
|
|
|
|
|
- if ( builder.renderer.coordinateSystem === WebGPUCoordinateSystem ) {
|
|
|
|
|
|
|
+ if ( renderer.coordinateSystem === WebGPUCoordinateSystem ) {
|
|
|
|
|
|
|
|
coordZ = coordZ.mul( 2 ).sub( 1 ); // WebGPU: Convertion [ 0, 1 ] to [ - 1, 1 ]
|
|
coordZ = coordZ.mul( 2 ).sub( 1 ); // WebGPU: Convertion [ 0, 1 ] to [ - 1, 1 ]
|
|
|
|
|
|
|
@@ -120,94 +150,75 @@ class AnalyticLightNode extends LightingNode {
|
|
|
coordZ
|
|
coordZ
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- const textureCompare = ( depthTexture, shadowCoord, compare ) => texture( depthTexture, shadowCoord ).compare( compare );
|
|
|
|
|
- //const textureCompare = ( depthTexture, shadowCoord, compare ) => compare.step( texture( depthTexture, shadowCoord ) );
|
|
|
|
|
-
|
|
|
|
|
- // BasicShadowMap
|
|
|
|
|
-
|
|
|
|
|
- shadowNode = textureCompare( depthTexture, shadowCoord.xy, shadowCoord.z );
|
|
|
|
|
-
|
|
|
|
|
- // PCFShadowMap
|
|
|
|
|
- /*
|
|
|
|
|
- const mapSize = reference( 'mapSize', 'vec2', shadow );
|
|
|
|
|
- const radius = reference( 'radius', 'float', shadow );
|
|
|
|
|
-
|
|
|
|
|
- const texelSize = vec2( 1 ).div( mapSize );
|
|
|
|
|
- const dx0 = texelSize.x.negate().mul( radius );
|
|
|
|
|
- const dy0 = texelSize.y.negate().mul( radius );
|
|
|
|
|
- const dx1 = texelSize.x.mul( radius );
|
|
|
|
|
- const dy1 = texelSize.y.mul( radius );
|
|
|
|
|
- const dx2 = dx0.mul( 2 );
|
|
|
|
|
- const dy2 = dy0.mul( 2 );
|
|
|
|
|
- const dx3 = dx1.mul( 2 );
|
|
|
|
|
- const dy3 = dy1.mul( 2 );
|
|
|
|
|
-
|
|
|
|
|
- shadowNode = add(
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy, shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ),
|
|
|
|
|
- textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z )
|
|
|
|
|
- ).mul( 1 / 17 );
|
|
|
|
|
- */
|
|
|
|
|
|
|
+ const frustumTest = shadowCoord.x.greaterThanEqual( 0 )
|
|
|
|
|
+ .and( shadowCoord.x.lessThanEqual( 1 ) )
|
|
|
|
|
+ .and( shadowCoord.y.greaterThanEqual( 0 ) )
|
|
|
|
|
+ .and( shadowCoord.y.lessThanEqual( 1 ) )
|
|
|
|
|
+ .and( shadowCoord.z.lessThanEqual( 1 ) );
|
|
|
|
|
+
|
|
|
//
|
|
//
|
|
|
|
|
|
|
|
- const shadowColor = texture( rtt.texture, shadowCoord );
|
|
|
|
|
- const shadowMaskNode = frustumTest.mix( 1, shadowNode.mix( shadowColor.a.mix( 1, shadowColor ), 1 ) );
|
|
|
|
|
|
|
+ const filterFuncion = shadow.filterNode || shadowFilterLib[ renderer.shadowMap.type ] || null;
|
|
|
|
|
|
|
|
- this.rtt = rtt;
|
|
|
|
|
- this.colorNode = this.colorNode.mul( mix( 1, shadowMaskNode, shadowIntensity ) );
|
|
|
|
|
- this._shadowColorNode = this.colorNode;
|
|
|
|
|
|
|
+ if ( filterFuncion === null ) {
|
|
|
|
|
|
|
|
- this.shadowNode = shadowNode;
|
|
|
|
|
- this.shadowMaskNode = shadowMaskNode;
|
|
|
|
|
|
|
+ throw new Error( 'THREE.WebGPURenderer: Shadow map type not supported yet.' );
|
|
|
|
|
|
|
|
- //
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- this.updateBeforeType = NodeUpdateType.RENDER;
|
|
|
|
|
|
|
+ const shadowNode = frustumTest.cond( filterFuncion( { depthTexture, shadowCoord, shadow } ), float( 1 ) );
|
|
|
|
|
|
|
|
- } else {
|
|
|
|
|
|
|
+ this.shadowMap = shadowMap;
|
|
|
|
|
|
|
|
- this.colorNode = this._shadowColorNode;
|
|
|
|
|
|
|
+ this.shadowNode = shadowNode;
|
|
|
|
|
+ this.shadowColorNode = shadowColorNode = this.colorNode.mul( mix( 1, shadowNode, shadowIntensity ) );
|
|
|
|
|
+
|
|
|
|
|
+ this.baseColorNode = this.colorNode;
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ //
|
|
|
|
|
+
|
|
|
|
|
+ this.colorNode = shadowColorNode;
|
|
|
|
|
+
|
|
|
|
|
+ this.updateBeforeType = NodeUpdateType.RENDER;
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
setup( builder ) {
|
|
setup( builder ) {
|
|
|
|
|
|
|
|
- if ( this.light.castShadow ) this.setupShadow( builder );
|
|
|
|
|
- else if ( this.shadowNode !== null ) this.disposeShadow();
|
|
|
|
|
|
|
+ this.colorNode = this.baseColorNode || this.colorNode;
|
|
|
|
|
+
|
|
|
|
|
+ if ( this.light.castShadow ) {
|
|
|
|
|
+
|
|
|
|
|
+ if ( builder.object.receiveShadow ) {
|
|
|
|
|
+
|
|
|
|
|
+ this.setupShadow( builder );
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else if ( this.shadowNode !== null ) {
|
|
|
|
|
+
|
|
|
|
|
+ this.disposeShadow();
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
updateShadow( frame ) {
|
|
updateShadow( frame ) {
|
|
|
|
|
|
|
|
- const { rtt, light } = this;
|
|
|
|
|
|
|
+ const { shadowMap, light } = this;
|
|
|
const { renderer, scene, camera } = frame;
|
|
const { renderer, scene, camera } = frame;
|
|
|
|
|
|
|
|
const currentOverrideMaterial = scene.overrideMaterial;
|
|
const currentOverrideMaterial = scene.overrideMaterial;
|
|
|
|
|
|
|
|
scene.overrideMaterial = overrideMaterial;
|
|
scene.overrideMaterial = overrideMaterial;
|
|
|
|
|
|
|
|
- rtt.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height );
|
|
|
|
|
|
|
+ shadowMap.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height );
|
|
|
|
|
|
|
|
light.shadow.updateMatrices( light );
|
|
light.shadow.updateMatrices( light );
|
|
|
light.shadow.camera.layers.mask = camera.layers.mask;
|
|
light.shadow.camera.layers.mask = camera.layers.mask;
|
|
|
|
|
|
|
|
- const currentToneMapping = renderer.toneMapping;
|
|
|
|
|
const currentRenderTarget = renderer.getRenderTarget();
|
|
const currentRenderTarget = renderer.getRenderTarget();
|
|
|
const currentRenderObjectFunction = renderer.getRenderObjectFunction();
|
|
const currentRenderObjectFunction = renderer.getRenderObjectFunction();
|
|
|
|
|
|
|
@@ -221,30 +232,27 @@ class AnalyticLightNode extends LightingNode {
|
|
|
|
|
|
|
|
} );
|
|
} );
|
|
|
|
|
|
|
|
- renderer.setRenderTarget( rtt );
|
|
|
|
|
- renderer.toneMapping = NoToneMapping;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ renderer.setRenderTarget( shadowMap );
|
|
|
renderer.render( scene, light.shadow.camera );
|
|
renderer.render( scene, light.shadow.camera );
|
|
|
|
|
|
|
|
renderer.setRenderTarget( currentRenderTarget );
|
|
renderer.setRenderTarget( currentRenderTarget );
|
|
|
renderer.setRenderObjectFunction( currentRenderObjectFunction );
|
|
renderer.setRenderObjectFunction( currentRenderObjectFunction );
|
|
|
|
|
|
|
|
- renderer.toneMapping = currentToneMapping;
|
|
|
|
|
-
|
|
|
|
|
scene.overrideMaterial = currentOverrideMaterial;
|
|
scene.overrideMaterial = currentOverrideMaterial;
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
disposeShadow() {
|
|
disposeShadow() {
|
|
|
|
|
|
|
|
- this.rtt.dispose();
|
|
|
|
|
|
|
+ this.shadowMap.dispose();
|
|
|
|
|
+ this.shadowMap = null;
|
|
|
|
|
|
|
|
this.shadowNode = null;
|
|
this.shadowNode = null;
|
|
|
- this.shadowMaskNode = null;
|
|
|
|
|
- this._shadowColorNode = null;
|
|
|
|
|
- this.rtt = null;
|
|
|
|
|
|
|
+ this.shadowColorNode = null;
|
|
|
|
|
+
|
|
|
|
|
+ this.baseColorNode = null;
|
|
|
|
|
|
|
|
- this.colorNode = this._defaultColorNode;
|
|
|
|
|
|
|
+ this.updateBeforeType = NodeUpdateType.NONE;
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|