super-three 0.170.0 → 0.170.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/three.cjs +24410 -24422
- package/build/three.core.js +37002 -0
- package/build/three.core.min.js +6 -0
- package/build/three.module.js +10573 -47578
- package/build/three.module.min.js +1 -1
- package/build/three.tsl.js +533 -0
- package/build/three.tsl.min.js +6 -0
- package/build/three.webgpu.js +2907 -37975
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +2914 -37959
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/jsm/capabilities/WebGPU.js +1 -10
- package/examples/jsm/controls/ArcballControls.js +25 -21
- package/examples/jsm/controls/OrbitControls.js +41 -9
- package/examples/jsm/controls/PointerLockControls.js +2 -5
- package/examples/jsm/csm/CSMShadowNode.js +7 -5
- package/examples/jsm/geometries/DecalGeometry.js +5 -1
- package/examples/jsm/lighting/TiledLighting.js +1 -1
- package/examples/jsm/lines/LineGeometry.js +25 -0
- package/examples/jsm/lines/LineMaterial.js +1 -7
- package/examples/jsm/lines/webgpu/Line2.js +2 -1
- package/examples/jsm/lines/webgpu/LineSegments2.js +2 -1
- package/examples/jsm/lines/webgpu/Wireframe.js +2 -1
- package/examples/jsm/loaders/KTX2Loader.js +3 -0
- package/examples/jsm/loaders/MMDLoader.js +2 -6
- package/examples/jsm/loaders/MaterialXLoader.js +2 -2
- package/examples/jsm/materials/MeshGouraudMaterial.js +2 -6
- package/examples/jsm/misc/ProgressiveLightMapGPU.js +2 -2
- package/examples/jsm/objects/InstancedPoints.js +2 -4
- package/examples/jsm/objects/LensflareMesh.js +4 -2
- package/examples/jsm/objects/SkyMesh.js +5 -3
- package/examples/jsm/objects/Water2Mesh.js +7 -3
- package/examples/jsm/objects/WaterMesh.js +5 -3
- package/examples/jsm/transpiler/AST.js +2 -2
- package/examples/jsm/transpiler/GLSLDecoder.js +57 -25
- package/examples/jsm/transpiler/TSLEncoder.js +11 -6
- package/examples/jsm/tsl/display/AfterImageNode.js +3 -3
- package/examples/jsm/tsl/display/AnaglyphPassNode.js +2 -2
- package/examples/jsm/tsl/display/AnamorphicNode.js +2 -2
- package/examples/jsm/tsl/display/BloomNode.js +3 -3
- package/examples/jsm/tsl/display/DenoiseNode.js +48 -12
- package/examples/jsm/tsl/display/DepthOfFieldNode.js +3 -2
- package/examples/jsm/tsl/display/DotScreenNode.js +2 -2
- package/examples/jsm/tsl/display/FXAANode.js +3 -3
- package/examples/jsm/tsl/display/FilmNode.js +3 -2
- package/examples/jsm/tsl/display/GTAONode.js +62 -27
- package/examples/jsm/tsl/display/GaussianBlurNode.js +6 -8
- package/examples/jsm/tsl/display/LensflareNode.js +3 -3
- package/examples/jsm/tsl/display/Lut3DNode.js +3 -2
- package/examples/jsm/tsl/display/OutlineNode.js +2 -2
- package/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +2 -1
- package/examples/jsm/tsl/display/PixelationPassNode.js +4 -4
- package/examples/jsm/tsl/display/RGBShiftNode.js +2 -1
- package/examples/jsm/tsl/display/SMAANode.js +3 -3
- package/examples/jsm/tsl/display/SSAAPassNode.js +2 -2
- package/examples/jsm/tsl/display/SSRNode.js +31 -8
- package/examples/jsm/tsl/display/SobelOperatorNode.js +3 -3
- package/examples/jsm/tsl/display/StereoCompositePassNode.js +4 -4
- package/examples/jsm/tsl/display/StereoPassNode.js +2 -2
- package/examples/jsm/tsl/display/TRAAPassNode.js +2 -2
- package/examples/jsm/tsl/display/TransitionNode.js +3 -2
- package/examples/jsm/tsl/lighting/TiledLightsNode.js +6 -9
- package/examples/jsm/utils/SceneOptimizer.js +410 -0
- package/examples/jsm/utils/UVsDebug.js +1 -1
- package/package.json +3 -3
- package/src/Three.Core.js +178 -0
- package/src/Three.TSL.js +526 -0
- package/src/Three.WebGPU.Nodes.js +5 -186
- package/src/Three.WebGPU.js +4 -186
- package/src/Three.js +1 -177
- package/src/animation/AnimationClip.js +2 -2
- package/src/animation/AnimationObjectGroup.js +2 -2
- package/src/audio/Audio.js +38 -0
- package/src/cameras/PerspectiveCamera.js +6 -6
- package/src/cameras/StereoCamera.js +2 -2
- package/src/constants.js +1 -1
- package/src/core/BufferGeometry.js +5 -3
- package/src/core/InterleavedBuffer.js +4 -4
- package/src/core/Object3D.js +2 -2
- package/src/extras/core/Curve.js +3 -3
- package/src/extras/core/Shape.js +2 -2
- package/src/geometries/EdgesGeometry.js +2 -2
- package/src/geometries/LatheGeometry.js +2 -2
- package/src/lights/SpotLightShadow.js +2 -2
- package/src/materials/LineBasicMaterial.js +2 -6
- package/src/materials/LineDashedMaterial.js +1 -6
- package/src/materials/Material.js +3 -16
- package/src/materials/MeshBasicMaterial.js +2 -6
- package/src/materials/MeshDepthMaterial.js +2 -6
- package/src/materials/MeshDistanceMaterial.js +2 -6
- package/src/materials/MeshLambertMaterial.js +2 -6
- package/src/materials/MeshMatcapMaterial.js +2 -6
- package/src/materials/MeshNormalMaterial.js +2 -6
- package/src/materials/MeshPhongMaterial.js +3 -7
- package/src/materials/MeshPhysicalMaterial.js +4 -8
- package/src/materials/MeshStandardMaterial.js +2 -6
- package/src/materials/MeshToonMaterial.js +2 -6
- package/src/materials/PointsMaterial.js +2 -6
- package/src/materials/RawShaderMaterial.js +2 -6
- package/src/materials/ShaderMaterial.js +2 -6
- package/src/materials/ShadowMaterial.js +2 -6
- package/src/materials/SpriteMaterial.js +2 -6
- package/src/materials/nodes/Line2NodeMaterial.js +32 -13
- package/src/materials/nodes/LineDashedNodeMaterial.js +4 -2
- package/src/materials/nodes/NodeMaterial.js +64 -16
- package/src/materials/nodes/manager/NodeMaterialObserver.js +13 -10
- package/src/math/ColorManagement.js +130 -122
- package/src/math/Line3.js +2 -2
- package/src/math/Quaternion.js +2 -2
- package/src/math/Spherical.js +3 -3
- package/src/math/Vector2.js +7 -7
- package/src/math/Vector3.js +9 -9
- package/src/math/Vector4.js +11 -9
- package/src/nodes/Nodes.js +1 -0
- package/src/nodes/TSL.js +3 -1
- package/src/nodes/accessors/Arrays.js +27 -0
- package/src/nodes/accessors/BuiltinNode.js +26 -0
- package/src/nodes/accessors/ClippingNode.js +76 -42
- package/src/nodes/accessors/InstanceNode.js +17 -20
- package/src/nodes/accessors/InstancedMeshNode.js +26 -0
- package/src/nodes/accessors/Lights.js +32 -0
- package/src/nodes/accessors/StorageBufferNode.js +29 -9
- package/src/nodes/accessors/StorageTextureNode.js +10 -4
- package/src/nodes/accessors/TextureNode.js +1 -1
- package/src/nodes/core/NodeBuilder.js +2 -9
- package/src/nodes/core/NodeUtils.js +28 -0
- package/src/nodes/core/constants.js +6 -0
- package/src/nodes/display/BlendModes.js +99 -0
- package/src/nodes/display/ToonOutlinePassNode.js +3 -3
- package/src/nodes/display/ViewportDepthNode.js +21 -6
- package/src/nodes/functions/material/getAlphaHashThreshold.js +13 -7
- package/src/nodes/functions/material/getParallaxCorrectNormal.js +1 -1
- package/src/nodes/lighting/AnalyticLightNode.js +12 -4
- package/src/nodes/lighting/PointLightNode.js +10 -1
- package/src/nodes/lighting/PointShadowNode.js +254 -0
- package/src/nodes/lighting/ShadowNode.js +176 -67
- package/src/nodes/lighting/SpotLightNode.js +14 -2
- package/src/nodes/utils/RTTNode.js +9 -1
- package/src/nodes/utils/StorageArrayElementNode.js +2 -2
- package/src/objects/BatchedMesh.js +54 -95
- package/src/objects/ClippingGroup.js +19 -0
- package/src/objects/Skeleton.js +2 -2
- package/src/renderers/WebGLRenderer.js +94 -23
- package/src/renderers/common/Animation.js +23 -11
- package/src/renderers/common/Background.js +1 -1
- package/src/renderers/common/Bindings.js +20 -4
- package/src/renderers/common/ClippingContext.js +77 -85
- package/src/renderers/common/RenderList.js +9 -6
- package/src/renderers/common/RenderObject.js +27 -27
- package/src/renderers/common/RenderObjects.js +12 -6
- package/src/renderers/common/Renderer.js +63 -57
- package/src/renderers/common/Textures.js +11 -3
- package/src/renderers/common/UniformsGroup.js +16 -4
- package/src/renderers/common/extras/PMREMGenerator.js +89 -13
- package/src/renderers/common/nodes/NodeLibrary.js +2 -2
- package/src/renderers/common/nodes/NodeStorageBuffer.js +2 -3
- package/src/renderers/common/nodes/NodeUniform.js +42 -0
- package/src/renderers/webgl/WebGLBackground.js +20 -1
- package/src/renderers/webgl/WebGLGeometries.js +0 -28
- package/src/renderers/webgl-fallback/WebGLBackend.js +13 -6
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +43 -12
- package/src/renderers/webgl-fallback/utils/WebGLState.js +26 -1
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +4 -1
- package/src/renderers/webgpu/WebGPUBackend.js +47 -31
- package/src/renderers/webgpu/nodes/StandardNodeLibrary.js +13 -26
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +184 -74
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +15 -2
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +72 -7
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +5 -1
- package/src/textures/Source.js +2 -2
- package/src/textures/Texture.js +2 -2
- package/src/nodes/display/BlendMode.js +0 -54
|
@@ -34,7 +34,7 @@ class ToonOutlinePassNode extends PassNode {
|
|
|
34
34
|
|
|
35
35
|
const currentRenderObjectFunction = renderer.getRenderObjectFunction();
|
|
36
36
|
|
|
37
|
-
renderer.setRenderObjectFunction( ( object, scene, camera, geometry, material, group, lightsNode ) => {
|
|
37
|
+
renderer.setRenderObjectFunction( ( object, scene, camera, geometry, material, group, lightsNode, clippingContext ) => {
|
|
38
38
|
|
|
39
39
|
// only render outline for supported materials
|
|
40
40
|
|
|
@@ -43,7 +43,7 @@ class ToonOutlinePassNode extends PassNode {
|
|
|
43
43
|
if ( material.wireframe === false ) {
|
|
44
44
|
|
|
45
45
|
const outlineMaterial = this._getOutlineMaterial( material );
|
|
46
|
-
renderer.renderObject( object, scene, camera, geometry, outlineMaterial, group, lightsNode );
|
|
46
|
+
renderer.renderObject( object, scene, camera, geometry, outlineMaterial, group, lightsNode, clippingContext );
|
|
47
47
|
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ class ToonOutlinePassNode extends PassNode {
|
|
|
51
51
|
|
|
52
52
|
// default
|
|
53
53
|
|
|
54
|
-
renderer.renderObject( object, scene, camera, geometry, material, group, lightsNode );
|
|
54
|
+
renderer.renderObject( object, scene, camera, geometry, material, group, lightsNode, clippingContext );
|
|
55
55
|
|
|
56
56
|
} );
|
|
57
57
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Node from '../core/Node.js';
|
|
2
|
-
import { log2, nodeImmutable, nodeProxy } from '../tsl/TSLBase.js';
|
|
2
|
+
import { float, log, log2, nodeImmutable, nodeProxy } from '../tsl/TSLBase.js';
|
|
3
3
|
import { cameraNear, cameraFar } from '../accessors/Camera.js';
|
|
4
4
|
import { positionView } from '../accessors/Position.js';
|
|
5
5
|
import { viewportDepthTexture } from './ViewportDepthTextureNode.js';
|
|
@@ -116,8 +116,10 @@ export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ )
|
|
|
116
116
|
// maps perspective depth in [ 0, 1 ] to viewZ
|
|
117
117
|
export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) );
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
// -near maps to 0; -far maps to 1
|
|
120
|
+
export const viewZToLogarithmicDepth = ( viewZ, near, far ) => {
|
|
120
121
|
|
|
122
|
+
// NOTE: viewZ must be negative--see explanation at the end of this comment block.
|
|
121
123
|
// The final logarithmic depth formula used here is adapted from one described in an
|
|
122
124
|
// article by Thatcher Ulrich (see http://tulrich.com/geekstuff/log_depth_buffer.txt),
|
|
123
125
|
// which was an improvement upon an earlier formula one described in an
|
|
@@ -139,15 +141,28 @@ export const perspectiveDepthToLogarithmicDepth = ( perspectiveW, near, far ) =>
|
|
|
139
141
|
// 1. Clamp the camera near plane so we don't divide by 0.
|
|
140
142
|
// 2. Use log2 instead of log to avoid an extra multiply (shaders implement log using log2).
|
|
141
143
|
// 3. Assume K is 1 (K = maximum value in depth buffer; see Ulrich's formula above).
|
|
142
|
-
// 4.
|
|
143
|
-
//
|
|
144
|
+
// 4. To maintain consistency with the functions "viewZToOrthographicDepth" and "viewZToPerspectiveDepth",
|
|
145
|
+
// we modify the formula here to use 'viewZ' instead of 'w'. The other functions expect a negative viewZ,
|
|
146
|
+
// so we do the same here, hence the 'viewZ.negate()' call.
|
|
147
|
+
// For visual representation of this depth curve, see https://www.desmos.com/calculator/uyqk0vex1u
|
|
144
148
|
near = near.max( 1e-6 ).toVar();
|
|
145
|
-
const numerator = log2(
|
|
146
|
-
const denominator = log2( far.div( near )
|
|
149
|
+
const numerator = log2( viewZ.negate().div( near ) );
|
|
150
|
+
const denominator = log2( far.div( near ) );
|
|
147
151
|
return numerator.div( denominator );
|
|
148
152
|
|
|
149
153
|
};
|
|
150
154
|
|
|
155
|
+
// maps logarithmic depth in [ 0, 1 ] to viewZ
|
|
156
|
+
export const logarithmicDepthToViewZ = ( depth, near, far ) => {
|
|
157
|
+
|
|
158
|
+
// NOTE: we add a 'negate()' call to the return value here to maintain consistency with
|
|
159
|
+
// the functions "orthographicDepthToViewZ" and "perspectiveDepthToViewZ" (they return
|
|
160
|
+
// a negative viewZ).
|
|
161
|
+
const exponent = depth.mul( log( far.div( near ) ) );
|
|
162
|
+
return float( Math.E ).pow( exponent ).mul( near ).negate();
|
|
163
|
+
|
|
164
|
+
};
|
|
165
|
+
|
|
151
166
|
const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE );
|
|
152
167
|
|
|
153
168
|
export const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH );
|
|
@@ -24,7 +24,7 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => {
|
|
|
24
24
|
const maxDeriv = max(
|
|
25
25
|
length( dFdx( position.xyz ) ),
|
|
26
26
|
length( dFdy( position.xyz ) )
|
|
27
|
-
)
|
|
27
|
+
);
|
|
28
28
|
|
|
29
29
|
const pixScale = float( 1 ).div( float( ALPHA_HASH_SCALE ).mul( maxDeriv ) ).toVar( 'pixScale' );
|
|
30
30
|
|
|
@@ -32,26 +32,26 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => {
|
|
|
32
32
|
const pixScales = vec2(
|
|
33
33
|
exp2( floor( log2( pixScale ) ) ),
|
|
34
34
|
exp2( ceil( log2( pixScale ) ) )
|
|
35
|
-
)
|
|
35
|
+
);
|
|
36
36
|
|
|
37
37
|
// Compute alpha thresholds at our two noise scales
|
|
38
38
|
const alpha = vec2(
|
|
39
39
|
hash3D( floor( pixScales.x.mul( position.xyz ) ) ),
|
|
40
40
|
hash3D( floor( pixScales.y.mul( position.xyz ) ) ),
|
|
41
|
-
)
|
|
41
|
+
);
|
|
42
42
|
|
|
43
43
|
// Factor to interpolate lerp with
|
|
44
|
-
const lerpFactor = fract( log2( pixScale ) )
|
|
44
|
+
const lerpFactor = fract( log2( pixScale ) );
|
|
45
45
|
|
|
46
46
|
// Interpolate alpha threshold from noise at two scales
|
|
47
|
-
const x = add( mul( lerpFactor.oneMinus(), alpha.x ), mul( lerpFactor, alpha.y ) )
|
|
47
|
+
const x = add( mul( lerpFactor.oneMinus(), alpha.x ), mul( lerpFactor, alpha.y ) );
|
|
48
48
|
|
|
49
49
|
// Pass into CDF to compute uniformly distrib threshold
|
|
50
|
-
const a = min( lerpFactor, lerpFactor.oneMinus() )
|
|
50
|
+
const a = min( lerpFactor, lerpFactor.oneMinus() );
|
|
51
51
|
const cases = vec3(
|
|
52
52
|
x.mul( x ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ),
|
|
53
53
|
x.sub( mul( 0.5, a ) ).div( sub( 1.0, a ) ),
|
|
54
|
-
sub( 1.0, sub( 1.0, x ).mul( sub( 1.0, x ) ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ) ) )
|
|
54
|
+
sub( 1.0, sub( 1.0, x ).mul( sub( 1.0, x ) ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ) ) );
|
|
55
55
|
|
|
56
56
|
// Find our final, uniformly distributed alpha threshold (ατ)
|
|
57
57
|
const threshold = x.lessThan( a.oneMinus() ).select( x.lessThan( a ).select( cases.x, cases.y ), cases.z );
|
|
@@ -59,6 +59,12 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => {
|
|
|
59
59
|
// Avoids ατ == 0. Could also do ατ =1-ατ
|
|
60
60
|
return clamp( threshold, 1.0e-6, 1.0 );
|
|
61
61
|
|
|
62
|
+
} ).setLayout( {
|
|
63
|
+
name: 'getAlphaHashThreshold',
|
|
64
|
+
type: 'float',
|
|
65
|
+
inputs: [
|
|
66
|
+
{ name: 'position', type: 'vec3' }
|
|
67
|
+
]
|
|
62
68
|
} );
|
|
63
69
|
|
|
64
70
|
export default getAlphaHashThreshold;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { positionWorld } from '../../accessors/Position';
|
|
1
|
+
import { positionWorld } from '../../accessors/Position.js';
|
|
2
2
|
import { float, Fn, min, normalize, sub, vec3 } from '../../tsl/TSLBase.js';
|
|
3
3
|
|
|
4
4
|
// https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html
|
|
@@ -19,12 +19,10 @@ class AnalyticLightNode extends LightingNode {
|
|
|
19
19
|
|
|
20
20
|
super();
|
|
21
21
|
|
|
22
|
-
this.updateType = NodeUpdateType.FRAME;
|
|
23
|
-
|
|
24
22
|
this.light = light;
|
|
25
23
|
|
|
26
24
|
this.color = new Color();
|
|
27
|
-
this.colorNode = uniform( this.color ).setGroup( renderGroup );
|
|
25
|
+
this.colorNode = ( light && light.colorNode ) || uniform( this.color ).setGroup( renderGroup );
|
|
28
26
|
|
|
29
27
|
this.baseColorNode = null;
|
|
30
28
|
|
|
@@ -33,6 +31,8 @@ class AnalyticLightNode extends LightingNode {
|
|
|
33
31
|
|
|
34
32
|
this.isAnalyticLightNode = true;
|
|
35
33
|
|
|
34
|
+
this.updateType = NodeUpdateType.FRAME;
|
|
35
|
+
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
getCacheKey() {
|
|
@@ -47,6 +47,12 @@ class AnalyticLightNode extends LightingNode {
|
|
|
47
47
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
setupShadowNode() {
|
|
51
|
+
|
|
52
|
+
return shadow( this.light );
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
50
56
|
setupShadow( builder ) {
|
|
51
57
|
|
|
52
58
|
const { renderer } = builder;
|
|
@@ -67,7 +73,7 @@ class AnalyticLightNode extends LightingNode {
|
|
|
67
73
|
|
|
68
74
|
} else {
|
|
69
75
|
|
|
70
|
-
shadowNode =
|
|
76
|
+
shadowNode = this.setupShadowNode( builder );
|
|
71
77
|
|
|
72
78
|
}
|
|
73
79
|
|
|
@@ -100,6 +106,8 @@ class AnalyticLightNode extends LightingNode {
|
|
|
100
106
|
} else if ( this.shadowNode !== null ) {
|
|
101
107
|
|
|
102
108
|
this.shadowNode.dispose();
|
|
109
|
+
this.shadowNode = null;
|
|
110
|
+
this.shadowColorNode = null;
|
|
103
111
|
|
|
104
112
|
}
|
|
105
113
|
|
|
@@ -5,6 +5,7 @@ import { lightViewPosition } from '../accessors/Lights.js';
|
|
|
5
5
|
import { positionView } from '../accessors/Position.js';
|
|
6
6
|
import { Fn } from '../tsl/TSLBase.js';
|
|
7
7
|
import { renderGroup } from '../core/UniformGroupNode.js';
|
|
8
|
+
import { pointShadow } from './PointShadowNode.js';
|
|
8
9
|
|
|
9
10
|
export const directPointLight = Fn( ( { color, lightViewPosition, cutoffDistance, decayExponent }, builder ) => {
|
|
10
11
|
|
|
@@ -61,7 +62,15 @@ class PointLightNode extends AnalyticLightNode {
|
|
|
61
62
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
setupShadowNode() {
|
|
66
|
+
|
|
67
|
+
return pointShadow( this.light );
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setup( builder ) {
|
|
72
|
+
|
|
73
|
+
super.setup( builder );
|
|
65
74
|
|
|
66
75
|
directPointLight( {
|
|
67
76
|
color: this.colorNode,
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import ShadowNode from './ShadowNode.js';
|
|
2
|
+
import { uniform } from '../core/UniformNode.js';
|
|
3
|
+
import { float, vec2, If, Fn, nodeObject } from '../tsl/TSLBase.js';
|
|
4
|
+
import { reference } from '../accessors/ReferenceNode.js';
|
|
5
|
+
import { texture } from '../accessors/TextureNode.js';
|
|
6
|
+
import { max, abs, sign } from '../math/MathNode.js';
|
|
7
|
+
import { sub, div } from '../math/OperatorNode.js';
|
|
8
|
+
import { renderGroup } from '../core/UniformGroupNode.js';
|
|
9
|
+
import { Vector2 } from '../../math/Vector2.js';
|
|
10
|
+
import { Vector4 } from '../../math/Vector4.js';
|
|
11
|
+
import { Color } from '../../math/Color.js';
|
|
12
|
+
import { BasicShadowMap } from '../../constants.js';
|
|
13
|
+
|
|
14
|
+
const _clearColor = /*@__PURE__*/ new Color();
|
|
15
|
+
|
|
16
|
+
// cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D
|
|
17
|
+
// vector suitable for 2D texture mapping. This code uses the following layout for the
|
|
18
|
+
// 2D texture:
|
|
19
|
+
//
|
|
20
|
+
// xzXZ
|
|
21
|
+
// y Y
|
|
22
|
+
//
|
|
23
|
+
// Y - Positive y direction
|
|
24
|
+
// y - Negative y direction
|
|
25
|
+
// X - Positive x direction
|
|
26
|
+
// x - Negative x direction
|
|
27
|
+
// Z - Positive z direction
|
|
28
|
+
// z - Negative z direction
|
|
29
|
+
//
|
|
30
|
+
// Source and test bed:
|
|
31
|
+
// https://gist.github.com/tschw/da10c43c467ce8afd0c4
|
|
32
|
+
|
|
33
|
+
export const cubeToUV = /*@__PURE__*/ Fn( ( [ pos, texelSizeY ] ) => {
|
|
34
|
+
|
|
35
|
+
const v = pos.toVar();
|
|
36
|
+
|
|
37
|
+
// Number of texels to avoid at the edge of each square
|
|
38
|
+
|
|
39
|
+
const absV = abs( v );
|
|
40
|
+
|
|
41
|
+
// Intersect unit cube
|
|
42
|
+
|
|
43
|
+
const scaleToCube = div( 1.0, max( absV.x, max( absV.y, absV.z ) ) );
|
|
44
|
+
absV.mulAssign( scaleToCube );
|
|
45
|
+
|
|
46
|
+
// Apply scale to avoid seams
|
|
47
|
+
|
|
48
|
+
// two texels less per square (one texel will do for NEAREST)
|
|
49
|
+
v.mulAssign( scaleToCube.mul( texelSizeY.mul( 2 ).oneMinus() ) );
|
|
50
|
+
|
|
51
|
+
// Unwrap
|
|
52
|
+
|
|
53
|
+
// space: -1 ... 1 range for each square
|
|
54
|
+
//
|
|
55
|
+
// #X## dim := ( 4 , 2 )
|
|
56
|
+
// # # center := ( 1 , 1 )
|
|
57
|
+
|
|
58
|
+
const planar = vec2( v.xy ).toVar();
|
|
59
|
+
|
|
60
|
+
const almostATexel = texelSizeY.mul( 1.5 );
|
|
61
|
+
const almostOne = almostATexel.oneMinus();
|
|
62
|
+
|
|
63
|
+
If( absV.z.greaterThanEqual( almostOne ), () => {
|
|
64
|
+
|
|
65
|
+
If( v.z.greaterThan( 0.0 ), () => {
|
|
66
|
+
|
|
67
|
+
planar.x.assign( sub( 4.0, v.x ) );
|
|
68
|
+
|
|
69
|
+
} );
|
|
70
|
+
|
|
71
|
+
} ).ElseIf( absV.x.greaterThanEqual( almostOne ), () => {
|
|
72
|
+
|
|
73
|
+
const signX = sign( v.x );
|
|
74
|
+
planar.x.assign( v.z.mul( signX ).add( signX.mul( 2.0 ) ) );
|
|
75
|
+
|
|
76
|
+
} ).ElseIf( absV.y.greaterThanEqual( almostOne ), () => {
|
|
77
|
+
|
|
78
|
+
const signY = sign( v.y );
|
|
79
|
+
planar.x.assign( v.x.add( signY.mul( 2.0 ) ).add( 2.0 ) );
|
|
80
|
+
planar.y.assign( v.z.mul( signY ).sub( 2.0 ) );
|
|
81
|
+
|
|
82
|
+
} );
|
|
83
|
+
|
|
84
|
+
// Transform to UV space
|
|
85
|
+
|
|
86
|
+
// scale := 0.5 / dim
|
|
87
|
+
// translate := ( center + 0.5 ) / dim
|
|
88
|
+
return vec2( 0.125, 0.25 ).mul( planar ).add( vec2( 0.375, 0.75 ) ).flipY();
|
|
89
|
+
|
|
90
|
+
} ).setLayout( {
|
|
91
|
+
name: 'cubeToUV',
|
|
92
|
+
type: 'vec2',
|
|
93
|
+
inputs: [
|
|
94
|
+
{ name: 'pos', type: 'vec3' },
|
|
95
|
+
{ name: 'texelSizeY', type: 'float' }
|
|
96
|
+
]
|
|
97
|
+
} );
|
|
98
|
+
|
|
99
|
+
export const BasicPointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize } ) => {
|
|
100
|
+
|
|
101
|
+
return texture( depthTexture, cubeToUV( bd3D, texelSize.y ) ).compare( dp );
|
|
102
|
+
|
|
103
|
+
} );
|
|
104
|
+
|
|
105
|
+
export const PointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize, shadow } ) => {
|
|
106
|
+
|
|
107
|
+
const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup );
|
|
108
|
+
const offset = vec2( - 1.0, 1.0 ).mul( radius ).mul( texelSize.y );
|
|
109
|
+
|
|
110
|
+
return texture( depthTexture, cubeToUV( bd3D.add( offset.xyy ), texelSize.y ) ).compare( dp )
|
|
111
|
+
.add( texture( depthTexture, cubeToUV( bd3D.add( offset.yyy ), texelSize.y ) ).compare( dp ) )
|
|
112
|
+
.add( texture( depthTexture, cubeToUV( bd3D.add( offset.xyx ), texelSize.y ) ).compare( dp ) )
|
|
113
|
+
.add( texture( depthTexture, cubeToUV( bd3D.add( offset.yyx ), texelSize.y ) ).compare( dp ) )
|
|
114
|
+
.add( texture( depthTexture, cubeToUV( bd3D, texelSize.y ) ).compare( dp ) )
|
|
115
|
+
.add( texture( depthTexture, cubeToUV( bd3D.add( offset.xxy ), texelSize.y ) ).compare( dp ) )
|
|
116
|
+
.add( texture( depthTexture, cubeToUV( bd3D.add( offset.yxy ), texelSize.y ) ).compare( dp ) )
|
|
117
|
+
.add( texture( depthTexture, cubeToUV( bd3D.add( offset.xxx ), texelSize.y ) ).compare( dp ) )
|
|
118
|
+
.add( texture( depthTexture, cubeToUV( bd3D.add( offset.yxx ), texelSize.y ) ).compare( dp ) )
|
|
119
|
+
.mul( 1.0 / 9.0 );
|
|
120
|
+
|
|
121
|
+
} );
|
|
122
|
+
|
|
123
|
+
const pointShadowFilter = /*@__PURE__*/ Fn( ( { filterFn, depthTexture, shadowCoord, shadow } ) => {
|
|
124
|
+
|
|
125
|
+
// for point lights, the uniform @vShadowCoord is re-purposed to hold
|
|
126
|
+
// the vector from the light to the world-space position of the fragment.
|
|
127
|
+
const lightToPosition = shadowCoord.xyz.toVar();
|
|
128
|
+
const lightToPositionLength = lightToPosition.length();
|
|
129
|
+
|
|
130
|
+
const cameraNearLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.near );
|
|
131
|
+
const cameraFarLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.far );
|
|
132
|
+
const bias = reference( 'bias', 'float', shadow ).setGroup( renderGroup );
|
|
133
|
+
const mapSize = uniform( shadow.mapSize ).setGroup( renderGroup );
|
|
134
|
+
|
|
135
|
+
const result = float( 1.0 ).toVar();
|
|
136
|
+
|
|
137
|
+
If( lightToPositionLength.sub( cameraFarLocal ).lessThanEqual( 0.0 ).and( lightToPositionLength.sub( cameraNearLocal ).greaterThanEqual( 0.0 ) ), () => {
|
|
138
|
+
|
|
139
|
+
// dp = normalized distance from light to fragment position
|
|
140
|
+
const dp = lightToPositionLength.sub( cameraNearLocal ).div( cameraFarLocal.sub( cameraNearLocal ) ).toVar(); // need to clamp?
|
|
141
|
+
dp.addAssign( bias );
|
|
142
|
+
|
|
143
|
+
// bd3D = base direction 3D
|
|
144
|
+
const bd3D = lightToPosition.normalize();
|
|
145
|
+
const texelSize = vec2( 1.0 ).div( mapSize.mul( vec2( 4.0, 2.0 ) ) );
|
|
146
|
+
|
|
147
|
+
// percentage-closer filtering
|
|
148
|
+
result.assign( filterFn( { depthTexture, bd3D, dp, texelSize, shadow } ) );
|
|
149
|
+
|
|
150
|
+
} );
|
|
151
|
+
|
|
152
|
+
return result;
|
|
153
|
+
|
|
154
|
+
} );
|
|
155
|
+
|
|
156
|
+
const _viewport = /*@__PURE__*/ new Vector4();
|
|
157
|
+
const _viewportSize = /*@__PURE__*/ new Vector2();
|
|
158
|
+
const _shadowMapSize = /*@__PURE__*/ new Vector2();
|
|
159
|
+
|
|
160
|
+
//
|
|
161
|
+
|
|
162
|
+
class PointShadowNode extends ShadowNode {
|
|
163
|
+
|
|
164
|
+
static get type() {
|
|
165
|
+
|
|
166
|
+
return 'PointShadowNode';
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
constructor( light, shadow = null ) {
|
|
171
|
+
|
|
172
|
+
super( light, shadow );
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getShadowFilterFn( type ) {
|
|
177
|
+
|
|
178
|
+
return type === BasicShadowMap ? BasicPointShadowFilter : PointShadowFilter;
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
setupShadowCoord( builder, shadowPosition ) {
|
|
183
|
+
|
|
184
|
+
return shadowPosition;
|
|
185
|
+
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
setupShadowFilter( builder, { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ) {
|
|
189
|
+
|
|
190
|
+
return pointShadowFilter( { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } );
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
renderShadow( frame ) {
|
|
195
|
+
|
|
196
|
+
const { shadow, shadowMap, light } = this;
|
|
197
|
+
const { renderer, scene } = frame;
|
|
198
|
+
|
|
199
|
+
const shadowFrameExtents = shadow.getFrameExtents();
|
|
200
|
+
|
|
201
|
+
_shadowMapSize.copy( shadow.mapSize );
|
|
202
|
+
_shadowMapSize.multiply( shadowFrameExtents );
|
|
203
|
+
|
|
204
|
+
shadowMap.setSize( _shadowMapSize.width, _shadowMapSize.height );
|
|
205
|
+
|
|
206
|
+
_viewportSize.copy( shadow.mapSize );
|
|
207
|
+
|
|
208
|
+
//
|
|
209
|
+
|
|
210
|
+
const previousAutoClear = renderer.autoClear;
|
|
211
|
+
|
|
212
|
+
const previousClearColor = renderer.getClearColor( _clearColor );
|
|
213
|
+
const previousClearAlpha = renderer.getClearAlpha();
|
|
214
|
+
|
|
215
|
+
renderer.autoClear = false;
|
|
216
|
+
renderer.setClearColor( shadow.clearColor, shadow.clearAlpha );
|
|
217
|
+
renderer.clear();
|
|
218
|
+
|
|
219
|
+
const viewportCount = shadow.getViewportCount();
|
|
220
|
+
|
|
221
|
+
for ( let vp = 0; vp < viewportCount; vp ++ ) {
|
|
222
|
+
|
|
223
|
+
const viewport = shadow.getViewport( vp );
|
|
224
|
+
|
|
225
|
+
const x = _viewportSize.x * viewport.x;
|
|
226
|
+
const y = _shadowMapSize.y - _viewportSize.y - ( _viewportSize.y * viewport.y );
|
|
227
|
+
|
|
228
|
+
_viewport.set(
|
|
229
|
+
x,
|
|
230
|
+
y,
|
|
231
|
+
_viewportSize.x * viewport.z,
|
|
232
|
+
_viewportSize.y * viewport.w
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
shadowMap.viewport.copy( _viewport );
|
|
236
|
+
|
|
237
|
+
shadow.updateMatrices( light, vp );
|
|
238
|
+
|
|
239
|
+
renderer.render( scene, shadow.camera );
|
|
240
|
+
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
//
|
|
244
|
+
|
|
245
|
+
renderer.autoClear = previousAutoClear;
|
|
246
|
+
renderer.setClearColor( previousClearColor, previousClearAlpha );
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export default PointShadowNode;
|
|
253
|
+
|
|
254
|
+
export const pointShadow = ( light, shadow ) => nodeObject( new PointShadowNode( light, shadow ) );
|