super-three 0.154.1 → 0.155.0

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.
Files changed (106) hide show
  1. package/build/three.cjs +256 -38
  2. package/build/three.js +256 -38
  3. package/build/three.min.js +1 -1
  4. package/build/three.module.js +255 -39
  5. package/build/three.module.min.js +1 -1
  6. package/examples/jsm/controls/OrbitControls.js +143 -21
  7. package/examples/jsm/environments/RoomEnvironment.js +1 -1
  8. package/examples/jsm/exporters/USDZExporter.js +1 -0
  9. package/examples/jsm/interactive/SelectionHelper.js +7 -0
  10. package/examples/jsm/loaders/FBXLoader.js +1 -1
  11. package/examples/jsm/loaders/GLTFLoader.js +8 -3
  12. package/examples/jsm/loaders/KTX2Loader.js +4 -4
  13. package/examples/jsm/loaders/LDrawLoader.js +1 -1
  14. package/examples/jsm/loaders/NRRDLoader.js +3 -3
  15. package/examples/jsm/loaders/PLYLoader.js +1 -1
  16. package/examples/jsm/loaders/TGALoader.js +10 -10
  17. package/examples/jsm/loaders/VRMLLoader.js +1 -1
  18. package/examples/jsm/misc/GPUComputationRenderer.js +0 -9
  19. package/examples/jsm/misc/Volume.js +4 -6
  20. package/examples/jsm/nodes/Nodes.js +5 -6
  21. package/examples/jsm/nodes/accessors/BufferAttributeNode.js +1 -1
  22. package/examples/jsm/nodes/accessors/CubeTextureNode.js +2 -0
  23. package/examples/jsm/nodes/accessors/ExtendedMaterialNode.js +14 -1
  24. package/examples/jsm/nodes/accessors/InstanceNode.js +8 -8
  25. package/examples/jsm/nodes/accessors/MaterialNode.js +34 -44
  26. package/examples/jsm/nodes/accessors/SceneNode.js +6 -0
  27. package/examples/jsm/nodes/accessors/TextureNode.js +48 -7
  28. package/examples/jsm/nodes/core/LightingModel.js +7 -9
  29. package/examples/jsm/nodes/core/Node.js +11 -2
  30. package/examples/jsm/nodes/core/PropertyNode.js +4 -0
  31. package/examples/jsm/nodes/display/BumpMapNode.js +77 -0
  32. package/examples/jsm/nodes/display/NormalMapNode.js +2 -2
  33. package/examples/jsm/nodes/functions/BSDF/BRDF_GGX.js +10 -2
  34. package/examples/jsm/nodes/functions/BSDF/Schlick_to_F0.js +13 -0
  35. package/examples/jsm/nodes/functions/PhongLightingModel.js +53 -14
  36. package/examples/jsm/nodes/functions/PhysicalLightingModel.js +236 -97
  37. package/examples/jsm/nodes/geometry/RangeNode.js +2 -2
  38. package/examples/jsm/nodes/gpgpu/ComputeNode.js +13 -0
  39. package/examples/jsm/nodes/lighting/AONode.js +1 -1
  40. package/examples/jsm/nodes/lighting/AnalyticLightNode.js +58 -20
  41. package/examples/jsm/nodes/lighting/DirectionalLightNode.js +7 -10
  42. package/examples/jsm/nodes/lighting/EnvironmentNode.js +22 -12
  43. package/examples/jsm/nodes/lighting/HemisphereLightNode.js +1 -1
  44. package/examples/jsm/nodes/lighting/LightingContextNode.js +12 -9
  45. package/examples/jsm/nodes/lighting/PointLightNode.js +7 -10
  46. package/examples/jsm/nodes/lighting/SpotLightNode.js +7 -10
  47. package/examples/jsm/nodes/materials/Materials.js +1 -0
  48. package/examples/jsm/nodes/materials/MeshLambertNodeMaterial.js +34 -0
  49. package/examples/jsm/nodes/materials/MeshNormalNodeMaterial.js +2 -0
  50. package/examples/jsm/nodes/materials/MeshPhongNodeMaterial.js +2 -2
  51. package/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +19 -2
  52. package/examples/jsm/nodes/materials/MeshStandardNodeMaterial.js +2 -2
  53. package/examples/jsm/nodes/materials/NodeMaterial.js +50 -24
  54. package/examples/jsm/nodes/materials/SpriteNodeMaterial.js +2 -2
  55. package/examples/jsm/nodes/shadernode/ShaderNode.js +2 -2
  56. package/examples/jsm/objects/Reflector.js +1 -9
  57. package/examples/jsm/objects/Refractor.js +0 -8
  58. package/examples/jsm/offscreen/scene.js +0 -1
  59. package/examples/jsm/postprocessing/MaskPass.js +4 -1
  60. package/examples/jsm/postprocessing/OutputPass.js +33 -14
  61. package/examples/jsm/postprocessing/UnrealBloomPass.js +21 -17
  62. package/examples/jsm/renderers/common/Background.js +22 -20
  63. package/examples/jsm/renderers/common/Binding.js +8 -0
  64. package/examples/jsm/renderers/common/Bindings.js +2 -6
  65. package/examples/jsm/renderers/common/Geometries.js +1 -1
  66. package/examples/jsm/renderers/common/Pipelines.js +94 -45
  67. package/examples/jsm/renderers/common/RenderContext.js +1 -0
  68. package/examples/jsm/renderers/common/RenderContexts.js +16 -5
  69. package/examples/jsm/renderers/common/RenderObject.js +20 -4
  70. package/examples/jsm/renderers/common/RenderObjects.js +10 -7
  71. package/examples/jsm/renderers/common/Renderer.js +70 -39
  72. package/examples/jsm/renderers/common/Textures.js +20 -8
  73. package/examples/jsm/renderers/common/nodes/Nodes.js +15 -4
  74. package/examples/jsm/renderers/webgpu/WebGPUBackend.js +51 -54
  75. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +33 -9
  76. package/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js +55 -36
  77. package/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js +83 -5
  78. package/examples/jsm/renderers/webgpu/utils/WebGPUConstants.js +24 -22
  79. package/examples/jsm/renderers/webgpu/utils/WebGPUPipelineUtils.js +83 -130
  80. package/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js +35 -8
  81. package/examples/jsm/renderers/webgpu/utils/WebGPUUtils.js +1 -1
  82. package/examples/jsm/shaders/OutputShader.js +19 -2
  83. package/examples/jsm/utils/BufferGeometryUtils.js +13 -4
  84. package/examples/jsm/webxr/OculusHandPointerModel.js +2 -2
  85. package/package.json +2 -2
  86. package/src/Three.js +2 -0
  87. package/src/animation/PropertyBinding.js +1 -1
  88. package/src/cameras/CubeCamera.js +1 -4
  89. package/src/constants.js +1 -1
  90. package/src/core/BufferAttribute.js +20 -0
  91. package/src/core/Object3D.js +1 -1
  92. package/src/core/RenderTarget.js +122 -0
  93. package/src/geometries/CapsuleGeometry.js +1 -1
  94. package/src/loaders/DataTextureLoader.js +21 -2
  95. package/src/renderers/WebGLMultipleRenderTargets.js +0 -2
  96. package/src/renderers/WebGLRenderTarget.js +3 -110
  97. package/src/renderers/WebGLRenderer.js +62 -8
  98. package/src/renderers/shaders/ShaderChunk/iridescence_fragment.glsl.js +1 -2
  99. package/src/renderers/webgl/WebGLGeometries.js +5 -1
  100. package/src/renderers/webgl/WebGLMaterials.js +1 -1
  101. package/src/renderers/webgl/WebGLPrograms.js +14 -2
  102. package/src/renderers/webgl/WebGLTextures.js +97 -12
  103. package/src/textures/CompressedCubeTexture.js +19 -0
  104. package/examples/jsm/nodes/functions/BSDF/BRDF_BlinnPhong.js +0 -30
  105. package/examples/jsm/renderers/common/RenderTarget.js +0 -15
  106. package/examples/jsm/renderers/common/nodes/NodeRender.js +0 -302
@@ -3,16 +3,129 @@ import BRDF_GGX from './BSDF/BRDF_GGX.js';
3
3
  import DFGApprox from './BSDF/DFGApprox.js';
4
4
  import EnvironmentBRDF from './BSDF/EnvironmentBRDF.js';
5
5
  import F_Schlick from './BSDF/F_Schlick.js';
6
+ import Schlick_to_F0 from './BSDF/Schlick_to_F0.js';
6
7
  import BRDF_Sheen from './BSDF/BRDF_Sheen.js';
7
- import { lightingModel } from '../core/LightingModel.js';
8
- import { diffuseColor, specularColor, roughness, clearcoat, clearcoatRoughness, sheen, sheenRoughness } from '../core/PropertyNode.js';
8
+ import LightingModel from '../core/LightingModel.js';
9
+ import { diffuseColor, specularColor, roughness, clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness } from '../core/PropertyNode.js';
9
10
  import { transformedNormalView, transformedClearcoatNormalView } from '../accessors/NormalNode.js';
10
11
  import { positionViewDirection } from '../accessors/PositionNode.js';
11
- import { tslFn, float, vec3 } from '../shadernode/ShaderNode.js';
12
+ import { float, vec3, mat3 } from '../shadernode/ShaderNode.js';
12
13
  import { cond } from '../math/CondNode.js';
14
+ import { mix, smoothstep } from '../math/MathNode.js';
13
15
 
14
- const clearcoatF0 = vec3( 0.04 );
15
- const clearcoatF90 = vec3( 1 );
16
+ //
17
+ // Iridescence
18
+ //
19
+
20
+ // XYZ to linear-sRGB color space
21
+ const XYZ_TO_REC709 = mat3(
22
+ 3.2404542, - 0.9692660, 0.0556434,
23
+ - 1.5371385, 1.8760108, - 0.2040259,
24
+ - 0.4985314, 0.0415560, 1.0572252
25
+ );
26
+
27
+ // Assume air interface for top
28
+ // Note: We don't handle the case fresnel0 == 1
29
+ const Fresnel0ToIor = ( fresnel0 ) => {
30
+
31
+ const sqrtF0 = fresnel0.sqrt();
32
+ return vec3( 1.0 ).add( sqrtF0 ).div( vec3( 1.0 ).sub( sqrtF0 ) );
33
+
34
+ };
35
+
36
+ // ior is a value between 1.0 and 3.0. 1.0 is air interface
37
+ const IorToFresnel0 = ( transmittedIor, incidentIor ) => {
38
+
39
+ return transmittedIor.sub( incidentIor ).div( transmittedIor.add( incidentIor ) ).pow2();
40
+
41
+ };
42
+
43
+ // Fresnel equations for dielectric/dielectric interfaces.
44
+ // Ref: https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html
45
+ // Evaluation XYZ sensitivity curves in Fourier space
46
+ const evalSensitivity = ( OPD, shift ) => {
47
+
48
+ const phase = OPD.mul( 2.0 * Math.PI * 1.0e-9 );
49
+ const val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );
50
+ const pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );
51
+ const VAR = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );
52
+
53
+ const x = float( 9.7470e-14 * Math.sqrt( 2.0 * Math.PI * 4.5282e+09 ) ).mul( phase.mul( 2.2399e+06 ).add( shift.x ).cos() ).mul( phase.pow2().mul( - 4.5282e+09 ).exp() );
54
+
55
+ let xyz = val.mul( VAR.mul( 2.0 * Math.PI ).sqrt() ).mul( pos.mul( phase ).add( shift ).cos() ).mul( phase.pow2().negate().mul( VAR ).exp() );
56
+ xyz = vec3( xyz.x.add( x ), xyz.y, xyz.z ).div( 1.0685e-7 );
57
+
58
+ const rgb = XYZ_TO_REC709.mul( xyz );
59
+ return rgb;
60
+
61
+ };
62
+
63
+ const evalIridescence = ( outsideIOR, eta2, cosTheta1, thinFilmThickness, baseF0 ) => {
64
+
65
+ // Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0
66
+ const iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );
67
+ // Evaluate the cosTheta on the base layer (Snell law)
68
+ const sinTheta2Sq = outsideIOR.div( iridescenceIOR ).pow2().mul( float( 1 ).sub( cosTheta1.pow2() ) );
69
+
70
+ // Handle TIR:
71
+ const cosTheta2Sq = float( 1 ).sub( sinTheta2Sq );
72
+ /*if ( cosTheta2Sq < 0.0 ) {
73
+
74
+ return vec3( 1.0 );
75
+
76
+ }*/
77
+
78
+ const cosTheta2 = cosTheta2Sq.sqrt();
79
+
80
+ // First interface
81
+ const R0 = IorToFresnel0( iridescenceIOR, outsideIOR );
82
+ const R12 = F_Schlick( { f0: R0, f90: 1.0, dotVH: cosTheta1 } );
83
+ //const R21 = R12;
84
+ const T121 = R12.oneMinus();
85
+ const phi12 = iridescenceIOR.lessThan( outsideIOR ).cond( Math.PI, 0.0 );
86
+ const phi21 = float( Math.PI ).sub( phi12 );
87
+
88
+ // Second interface
89
+ const baseIOR = Fresnel0ToIor( baseF0.clamp( 0.0, 0.9999 ) ); // guard against 1.0
90
+ const R1 = IorToFresnel0( baseIOR, iridescenceIOR.vec3() );
91
+ const R23 = F_Schlick( { f0: R1, f90: 1.0, dotVH: cosTheta2 } );
92
+ const phi23 = vec3(
93
+ baseIOR.x.lessThan( iridescenceIOR ).cond( Math.PI, 0.0 ),
94
+ baseIOR.y.lessThan( iridescenceIOR ).cond( Math.PI, 0.0 ),
95
+ baseIOR.z.lessThan( iridescenceIOR ).cond( Math.PI, 0.0 )
96
+ );
97
+
98
+ // Phase shift
99
+ const OPD = iridescenceIOR.mul( thinFilmThickness, cosTheta2, 2.0 );
100
+ const phi = vec3( phi21 ).add( phi23 );
101
+
102
+ // Compound terms
103
+ const R123 = R12.mul( R23 ).clamp( 1e-5, 0.9999 );
104
+ const r123 = R123.sqrt();
105
+ const Rs = T121.pow2().mul( R23 ).div( vec3( 1.0 ).sub( R123 ) );
106
+
107
+ // Reflectance term for m = 0 (DC term amplitude)
108
+ const C0 = R12.add( Rs );
109
+ let I = C0;
110
+
111
+ // Reflectance term for m > 0 (pairs of diracs)
112
+ let Cm = Rs.sub( T121 );
113
+ for ( let m = 1; m <= 2; ++ m ) {
114
+
115
+ Cm = Cm.mul( r123 );
116
+ const Sm = evalSensitivity( float( m ).mul( OPD ), float( m ).mul( phi ) ).mul( 2.0 );
117
+ I = I.add( Cm.mul( Sm ) );
118
+
119
+ }
120
+
121
+ // Since out of gamut colors might be produced, negative color values are clamped to 0.
122
+ return I.max( vec3( 0.0 ) );
123
+
124
+ };
125
+
126
+ //
127
+ // Sheen
128
+ //
16
129
 
17
130
  // This is a curve-fit approxmation to the "Charlie sheen" BRDF integrated over the hemisphere from
18
131
  // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF". The analysis can be found
@@ -41,164 +154,190 @@ const IBLSheenBRDF = ( normal, viewDir, roughness ) => {
41
154
 
42
155
  };
43
156
 
44
- // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
45
- // Approximates multiscattering in order to preserve energy.
46
- // http://www.jcgt.org/published/0008/01/03/
47
- const computeMultiscattering = ( singleScatter, multiScatter, specularF90 = float( 1 ) ) => {
157
+ const clearcoatF0 = vec3( 0.04 );
158
+ const clearcoatF90 = vec3( 1 );
48
159
 
49
- const fab = DFGApprox( { roughness } );
160
+ //
50
161
 
51
- const FssEss = specularColor.mul( fab.x ).add( specularF90.mul( fab.y ) );
162
+ class PhysicalLightingModel extends LightingModel {
52
163
 
53
- const Ess = fab.x.add( fab.y );
54
- const Ems = Ess.oneMinus();
164
+ constructor( clearcoat = true, sheen = true, iridescence = true ) {
55
165
 
56
- const Favg = specularColor.add( specularColor.oneMinus().mul( 0.047619 ) ); // 1/21
57
- const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).oneMinus() );
166
+ super();
58
167
 
59
- singleScatter.addAssign( FssEss );
60
- multiScatter.addAssign( Fms.mul( Ems ) );
168
+ this.clearcoat = clearcoat;
169
+ this.sheen = sheen;
170
+ this.iridescence = iridescence;
61
171
 
62
- };
172
+ this.clearcoatRadiance = null;
173
+ this.clearcoatSpecular = null;
174
+ this.sheenSpecular = null;
175
+ this.iridescenceFresnel = null;
176
+ this.iridescenceF0 = null;
63
177
 
64
- const LM_Init = tslFn( ( context, stack, builder ) => {
178
+ }
65
179
 
66
- if ( builder.includes( clearcoat ) ) {
180
+ init( { reflectedLight } ) {
67
181
 
68
- context.clearcoatRadiance = vec3().temp();
69
- context.reflectedLight.clearcoatSpecular = vec3().temp();
182
+ if ( this.clearcoat === true ) {
70
183
 
71
- const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
184
+ this.clearcoatRadiance = vec3().temp();
185
+ this.clearcoatSpecular = vec3().temp();
72
186
 
73
- const Fcc = F_Schlick( {
74
- dotVH: dotNVcc,
75
- f0: clearcoatF0,
76
- f90: clearcoatF90
77
- } );
187
+ const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
78
188
 
79
- const outgoingLight = context.reflectedLight.total;
80
- const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( context.reflectedLight.clearcoatSpecular.mul( clearcoat ) );
189
+ const Fcc = F_Schlick( {
190
+ dotVH: dotNVcc,
191
+ f0: clearcoatF0,
192
+ f90: clearcoatF90
193
+ } );
81
194
 
82
- outgoingLight.assign( clearcoatLight );
195
+ const outgoingLight = reflectedLight.total;
196
+ const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecular.mul( clearcoat ) );
83
197
 
84
- }
198
+ outgoingLight.assign( clearcoatLight );
85
199
 
86
- if ( builder.includes( sheen ) ) {
200
+ }
87
201
 
88
- context.reflectedLight.sheenSpecular = vec3().temp();
202
+ if ( this.sheen === true ) {
89
203
 
90
- const outgoingLight = context.reflectedLight.total;
204
+ this.sheenSpecular = vec3().temp();
91
205
 
92
- const sheenEnergyComp = sheen.r.max( sheen.g ).max( sheen.b ).mul( 0.157 ).oneMinus();
93
- const sheenLight = outgoingLight.mul( sheenEnergyComp ).add( context.reflectedLight.sheenSpecular );
206
+ const outgoingLight = reflectedLight.total;
94
207
 
95
- outgoingLight.assign( sheenLight );
208
+ const sheenEnergyComp = sheen.r.max( sheen.g ).max( sheen.b ).mul( 0.157 ).oneMinus();
209
+ const sheenLight = outgoingLight.mul( sheenEnergyComp ).add( this.sheenSpecular );
96
210
 
97
- }
211
+ outgoingLight.assign( sheenLight );
98
212
 
99
- } );
213
+ }
100
214
 
101
- const RE_IndirectSpecular_Physical = tslFn( ( context ) => {
215
+ if ( this.iridescence === true ) {
102
216
 
103
- const { radiance, iblIrradiance, reflectedLight } = context;
217
+ const dotNVi = transformedNormalView.dot( positionViewDirection ).clamp();
104
218
 
105
- if ( reflectedLight.sheenSpecular ) {
219
+ this.iridescenceFresnel = evalIridescence( float( 1.0 ), iridescenceIOR, dotNVi, iridescenceThickness, specularColor );
220
+ this.iridescenceF0 = Schlick_to_F0( { f: this.iridescenceFresnel, f90: 1.0, dotVH: dotNVi } );
106
221
 
107
- reflectedLight.sheenSpecular.addAssign( iblIrradiance.mul(
108
- sheen,
109
- IBLSheenBRDF( transformedNormalView, positionViewDirection, sheenRoughness )
110
- ) );
222
+ }
111
223
 
112
224
  }
113
225
 
114
- if ( reflectedLight.clearcoatSpecular ) {
226
+ // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
227
+ // Approximates multiscattering in order to preserve energy.
228
+ // http://www.jcgt.org/published/0008/01/03/
115
229
 
116
- const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
230
+ computeMultiscattering( singleScatter, multiScatter, specularF90 = float( 1 ) ) {
117
231
 
118
- const clearcoatEnv = EnvironmentBRDF( {
119
- dotNV: dotNVcc,
120
- specularColor: clearcoatF0,
121
- specularF90: clearcoatF90,
122
- roughness: clearcoatRoughness
123
- } );
232
+ const fab = DFGApprox( { roughness } );
124
233
 
125
- reflectedLight.clearcoatSpecular.addAssign( context.clearcoatRadiance.mul( clearcoatEnv ) );
234
+ const Fr = this.iridescenceF0 ? iridescence.mix( specularColor, this.iridescenceF0 ) : specularColor;
126
235
 
127
- }
236
+ const FssEss = Fr.mul( fab.x ).add( specularF90.mul( fab.y ) );
128
237
 
129
- // Both indirect specular and indirect diffuse light accumulate here
238
+ const Ess = fab.x.add( fab.y );
239
+ const Ems = Ess.oneMinus();
130
240
 
131
- const singleScattering = vec3().temp();
132
- const multiScattering = vec3().temp();
133
- const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI );
241
+ const Favg = specularColor.add( specularColor.oneMinus().mul( 0.047619 ) ); // 1/21
242
+ const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).oneMinus() );
134
243
 
135
- computeMultiscattering( singleScattering, multiScattering );
244
+ singleScatter.addAssign( FssEss );
245
+ multiScatter.addAssign( Fms.mul( Ems ) );
136
246
 
137
- const totalScattering = singleScattering.add( multiScattering );
247
+ }
248
+
249
+ direct( { lightDirection, lightColor, reflectedLight } ) {
138
250
 
139
- const diffuse = diffuseColor.mul( totalScattering.r.max( totalScattering.g ).max( totalScattering.b ).oneMinus() );
251
+ const dotNL = transformedNormalView.dot( lightDirection ).clamp();
252
+ const irradiance = dotNL.mul( lightColor );
140
253
 
141
- reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) );
142
- reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) );
254
+ if ( this.sheen === true ) {
143
255
 
144
- reflectedLight.indirectDiffuse.addAssign( diffuse.mul( cosineWeightedIrradiance ) );
256
+ this.sheenSpecular.addAssign( irradiance.mul( BRDF_Sheen( { lightDirection } ) ) );
145
257
 
146
- } );
258
+ }
147
259
 
148
- const RE_IndirectDiffuse_Physical = tslFn( ( context ) => {
260
+ if ( this.clearcoat === true ) {
149
261
 
150
- const { irradiance, reflectedLight } = context;
262
+ const dotNLcc = transformedClearcoatNormalView.dot( lightDirection ).clamp();
263
+ const ccIrradiance = dotNLcc.mul( lightColor );
151
264
 
152
- reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) );
265
+ this.clearcoatSpecular.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) );
153
266
 
154
- } );
267
+ }
155
268
 
156
- const RE_Direct_Physical = tslFn( ( inputs ) => {
269
+ reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
157
270
 
158
- const { lightDirection, lightColor, reflectedLight } = inputs;
271
+ reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, iridescenceFresnel: this.iridescenceFresnel } ) ) );
159
272
 
160
- const dotNL = transformedNormalView.dot( lightDirection ).clamp();
161
- const irradiance = dotNL.mul( lightColor );
273
+ }
162
274
 
163
- if ( reflectedLight.sheenSpecular ) {
275
+ indirectDiffuse( { irradiance, reflectedLight } ) {
164
276
 
165
- reflectedLight.sheenSpecular.addAssign( irradiance.mul( BRDF_Sheen( { lightDirection } ) ) );
277
+ reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) );
166
278
 
167
279
  }
168
280
 
169
- if ( reflectedLight.clearcoatSpecular ) {
281
+ indirectSpecular( { radiance, iblIrradiance, reflectedLight, } ) {
170
282
 
171
- const dotNLcc = transformedClearcoatNormalView.dot( lightDirection ).clamp();
172
- const ccIrradiance = dotNLcc.mul( lightColor );
283
+ if ( this.sheen === true ) {
173
284
 
174
- reflectedLight.clearcoatSpecular.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) );
285
+ this.sheenSpecular.addAssign( iblIrradiance.mul(
286
+ sheen,
287
+ IBLSheenBRDF( transformedNormalView, positionViewDirection, sheenRoughness )
288
+ ) );
175
289
 
176
- }
290
+ }
291
+
292
+ if ( this.clearcoat === true ) {
293
+
294
+ const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
295
+
296
+ const clearcoatEnv = EnvironmentBRDF( {
297
+ dotNV: dotNVcc,
298
+ specularColor: clearcoatF0,
299
+ specularF90: clearcoatF90,
300
+ roughness: clearcoatRoughness
301
+ } );
177
302
 
178
- reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
303
+ this.clearcoatSpecular.addAssign( this.clearcoatRadiance.mul( clearcoatEnv ) );
179
304
 
180
- reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness } ) ) );
305
+ }
181
306
 
182
- } );
307
+ // Both indirect specular and indirect diffuse light accumulate here
183
308
 
184
- const RE_AmbientOcclusion_Physical = tslFn( ( context ) => {
309
+ const singleScattering = vec3().temp();
310
+ const multiScattering = vec3().temp();
311
+ const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI );
185
312
 
186
- const { ambientOcclusion, reflectedLight } = context;
313
+ this.computeMultiscattering( singleScattering, multiScattering );
187
314
 
188
- const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
315
+ const totalScattering = singleScattering.add( multiScattering );
189
316
 
190
- const aoNV = dotNV.add( ambientOcclusion );
191
- const aoExp = roughness.mul( - 16.0 ).oneMinus().negate().exp2();
317
+ const diffuse = diffuseColor.mul( totalScattering.r.max( totalScattering.g ).max( totalScattering.b ).oneMinus() );
192
318
 
193
- const aoNode = ambientOcclusion.sub( aoNV.pow( aoExp ).oneMinus() ).clamp();
319
+ reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) );
320
+ reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) );
194
321
 
195
- reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion );
322
+ reflectedLight.indirectDiffuse.addAssign( diffuse.mul( cosineWeightedIrradiance ) );
196
323
 
197
- reflectedLight.indirectSpecular.mulAssign( aoNode );
324
+ }
325
+
326
+ ambientOcclusion( { ambientOcclusion, reflectedLight } ) {
327
+
328
+ const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
329
+
330
+ const aoNV = dotNV.add( ambientOcclusion );
331
+ const aoExp = roughness.mul( - 16.0 ).oneMinus().negate().exp2();
198
332
 
333
+ const aoNode = ambientOcclusion.sub( aoNV.pow( aoExp ).oneMinus() ).clamp();
199
334
 
200
- } );
335
+ reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion );
336
+
337
+ reflectedLight.indirectSpecular.mulAssign( aoNode );
338
+
339
+ }
201
340
 
202
- const physicalLightingModel = lightingModel( LM_Init, RE_Direct_Physical, RE_IndirectDiffuse_Physical, RE_IndirectSpecular_Physical, RE_AmbientOcclusion_Physical );
341
+ }
203
342
 
204
- export default physicalLightingModel;
343
+ export default PhysicalLightingModel;
@@ -44,8 +44,8 @@ class RangeNode extends Node {
44
44
 
45
45
  if ( object.isInstancedMesh === true ) {
46
46
 
47
- let minValue = this.minNode.value;
48
- let maxValue = this.maxNode.value;
47
+ const minValue = this.minNode.value;
48
+ const maxValue = this.maxNode.value;
49
49
 
50
50
  const minLength = builder.getTypeLength( getValueType( minValue ) );
51
51
  const maxLength = builder.getTypeLength( getValueType( maxValue ) );
@@ -16,12 +16,25 @@ class ComputeNode extends Node {
16
16
  this.workgroupSize = workgroupSize;
17
17
  this.dispatchCount = 0;
18
18
 
19
+ this.version = 1;
19
20
  this.updateType = NodeUpdateType.OBJECT;
20
21
 
21
22
  this.updateDispatchCount();
22
23
 
23
24
  }
24
25
 
26
+ dispose() {
27
+
28
+ this.dispatchEvent( { type: 'dispose' } );
29
+
30
+ }
31
+
32
+ set needsUpdate( value ) {
33
+
34
+ if ( value === true ) this.version ++;
35
+
36
+ }
37
+
25
38
  updateDispatchCount() {
26
39
 
27
40
  const { count, workgroupSize } = this;
@@ -14,7 +14,7 @@ class AONode extends LightingNode {
14
14
  construct( builder ) {
15
15
 
16
16
  const aoIntensity = 1;
17
- const aoNode = this.aoNode.sub( 1.0 ).mul( aoIntensity ).add( 1.0 );
17
+ const aoNode = this.aoNode.x.sub( 1.0 ).mul( aoIntensity ).add( 1.0 );
18
18
 
19
19
  builder.context.ambientOcclusion.mulAssign( aoNode );
20
20
 
@@ -2,14 +2,14 @@ import LightingNode from './LightingNode.js';
2
2
  import { NodeUpdateType } from '../core/constants.js';
3
3
  import { uniform } from '../core/UniformNode.js';
4
4
  import { addNodeClass } from '../core/Node.js';
5
- import { vec3 } from '../shadernode/ShaderNode.js';
5
+ import { /*vec2,*/ vec3 } from '../shadernode/ShaderNode.js';
6
6
  import { reference } from '../accessors/ReferenceNode.js';
7
7
  import { texture } from '../accessors/TextureNode.js';
8
8
  import { positionWorld } from '../accessors/PositionNode.js';
9
- //import { step } from '../math/MathNode.js';
10
- import { cond } from '../math/CondNode.js';
9
+ import { normalWorld } from '../accessors/NormalNode.js';
10
+ //import { add } from '../math/OperatorNode.js';
11
11
 
12
- import { Color, DepthTexture, NearestFilter } from 'three';
12
+ import { Color, DepthTexture, NearestFilter, LessCompare } from 'three';
13
13
 
14
14
  let depthMaterial = null;
15
15
 
@@ -53,7 +53,7 @@ class AnalyticLightNode extends LightingNode {
53
53
  depthTexture.magFilter = NearestFilter;
54
54
  depthTexture.image.width = shadow.mapSize.width;
55
55
  depthTexture.image.height = shadow.mapSize.height;
56
- //depthTexture.compareFunction = THREE.LessCompare;
56
+ depthTexture.compareFunction = LessCompare;
57
57
 
58
58
  rtt.depthTexture = depthTexture;
59
59
 
@@ -62,31 +62,69 @@ class AnalyticLightNode extends LightingNode {
62
62
  //
63
63
 
64
64
  const bias = reference( 'bias', 'float', shadow );
65
+ const normalBias = reference( 'normalBias', 'float', shadow );
65
66
 
66
- //const diffuseFactor = normalView.dot( objectViewPosition( this.light ).sub( positionView ).normalize().negate() );
67
- //bias = mix( bias, 0, diffuseFactor );
68
-
69
- let shadowCoord = uniform( shadow.matrix ).mul( positionWorld );
67
+ let shadowCoord = uniform( shadow.matrix ).mul( positionWorld.add( normalWorld.mul( normalBias ) ) );
70
68
  shadowCoord = shadowCoord.xyz.div( shadowCoord.w );
71
69
 
70
+ const frustumTest = shadowCoord.x.greaterThanEqual( 0 )
71
+ .and( shadowCoord.x.lessThanEqual( 1 ) )
72
+ .and( shadowCoord.y.greaterThanEqual( 0 ) )
73
+ .and( shadowCoord.y.lessThanEqual( 1 ) )
74
+ .and( shadowCoord.z.lessThanEqual( 1 ) );
75
+
72
76
  shadowCoord = vec3(
73
77
  shadowCoord.x,
74
- shadowCoord.y.oneMinus(),
75
- shadowCoord.z
78
+ shadowCoord.y.oneMinus(), // WebGPU: Flip Y
79
+ shadowCoord.z.add( bias ).mul( 2 ).sub( 1 ) // WebGPU: Convertion [ 0, 1 ] to [ - 1, 1 ]
76
80
  );
77
81
 
78
- // @TODO: Optimize using WebGPU compare-sampler
79
-
80
- let depth = texture( depthTexture, shadowCoord.xy );
81
- depth = depth.mul( .5 ).add( .5 ).add( bias );
82
-
83
- shadowNode = cond( shadowCoord.z.lessThan( depth ).or( shadowCoord.y.lessThan( .000001 ) /*@TODO: find the cause and remove it soon */ ), 1, 0 );
84
- //shadowNode = step( shadowCoord.z, depth );
85
-
82
+ const textureCompare = ( depthTexture, shadowCoord, compare ) => texture( depthTexture, shadowCoord ).compare( compare );
83
+ //const textureCompare = ( depthTexture, shadowCoord, compare ) => compare.step( texture( depthTexture, shadowCoord ) );
84
+
85
+ // BasicShadowMap
86
+
87
+ shadowNode = textureCompare( depthTexture, shadowCoord.xy, shadowCoord.z );
88
+
89
+ // PCFShadowMap
90
+ /*
91
+ const mapSize = reference( 'mapSize', 'vec2', shadow );
92
+ const radius = reference( 'radius', 'float', shadow );
93
+
94
+ const texelSize = vec2( 1 ).div( mapSize );
95
+ const dx0 = texelSize.x.negate().mul( radius );
96
+ const dy0 = texelSize.y.negate().mul( radius );
97
+ const dx1 = texelSize.x.mul( radius );
98
+ const dy1 = texelSize.y.mul( radius );
99
+ const dx2 = dx0.mul( 2 );
100
+ const dy2 = dy0.mul( 2 );
101
+ const dx3 = dx1.mul( 2 );
102
+ const dy3 = dy1.mul( 2 );
103
+
104
+ shadowNode = add(
105
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ),
106
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ),
107
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ),
108
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ),
109
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ),
110
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ),
111
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ),
112
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ),
113
+ textureCompare( depthTexture, shadowCoord.xy, shadowCoord.z ),
114
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ),
115
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ),
116
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ),
117
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ),
118
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ),
119
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ),
120
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ),
121
+ textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z )
122
+ ).mul( 1 / 17 );
123
+ */
86
124
  //
87
125
 
88
126
  this.rtt = rtt;
89
- this.colorNode = this.colorNode.mul( shadowNode );
127
+ this.colorNode = this.colorNode.mul( frustumTest.mix( 1, shadowNode ) );
90
128
 
91
129
  this.shadowNode = shadowNode;
92
130
 
@@ -17,20 +17,17 @@ class DirectionalLightNode extends AnalyticLightNode {
17
17
 
18
18
  super.construct( builder );
19
19
 
20
+ const lightingModel = builder.context.lightingModel;
21
+
20
22
  const lightColor = this.colorNode;
21
23
  const lightDirection = lightTargetDirection( this.light );
22
- const lightingModelFunctionNode = builder.context.lightingModelNode;
23
24
  const reflectedLight = builder.context.reflectedLight;
24
25
 
25
- if ( lightingModelFunctionNode && lightingModelFunctionNode.direct ) {
26
-
27
- lightingModelFunctionNode.direct( {
28
- lightDirection,
29
- lightColor,
30
- reflectedLight
31
- } );
32
-
33
- }
26
+ lightingModel.direct( {
27
+ lightDirection,
28
+ lightColor,
29
+ reflectedLight
30
+ } );
34
31
 
35
32
  }
36
33