super-three 0.163.0 → 0.164.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 (114) hide show
  1. package/build/three.cjs +473 -245
  2. package/build/three.module.js +473 -245
  3. package/build/three.module.min.js +2 -2
  4. package/examples/jsm/animation/CCDIKSolver.js +4 -2
  5. package/examples/jsm/exporters/GLTFExporter.js +45 -1
  6. package/examples/jsm/exporters/USDZExporter.js +7 -1
  7. package/examples/jsm/libs/draco/README.md +2 -2
  8. package/examples/jsm/loaders/EXRLoader.js +283 -99
  9. package/examples/jsm/loaders/GLTFLoader.js +53 -0
  10. package/examples/jsm/loaders/KTX2Loader.js +3 -6
  11. package/examples/jsm/loaders/VRMLLoader.js +1 -1
  12. package/examples/jsm/loaders/lwo/IFFParser.js +8 -5
  13. package/examples/jsm/materials/MeshGouraudMaterial.js +7 -1
  14. package/examples/jsm/math/Octree.js +26 -20
  15. package/examples/jsm/nodes/Nodes.js +4 -3
  16. package/examples/jsm/nodes/accessors/AccessorsUtils.js +16 -1
  17. package/examples/jsm/nodes/accessors/ClippingNode.js +3 -2
  18. package/examples/jsm/nodes/accessors/MaterialNode.js +107 -3
  19. package/examples/jsm/nodes/accessors/StorageBufferNode.js +9 -0
  20. package/examples/jsm/nodes/accessors/TextureNode.js +21 -3
  21. package/examples/jsm/nodes/accessors/TextureSizeNode.js +1 -1
  22. package/examples/jsm/nodes/code/FunctionNode.js +0 -8
  23. package/examples/jsm/nodes/core/Node.js +8 -0
  24. package/examples/jsm/nodes/core/NodeBuilder.js +5 -9
  25. package/examples/jsm/nodes/core/OutputStructNode.js +2 -1
  26. package/examples/jsm/nodes/core/PropertyNode.js +10 -0
  27. package/examples/jsm/nodes/display/BumpMapNode.js +7 -26
  28. package/examples/jsm/nodes/display/FrontFacingNode.js +13 -0
  29. package/examples/jsm/nodes/display/ViewportDepthNode.js +1 -1
  30. package/examples/jsm/nodes/display/ViewportNode.js +4 -2
  31. package/examples/jsm/nodes/display/ViewportTextureNode.js +4 -1
  32. package/examples/jsm/nodes/functions/BSDF/BRDF_GGX.js +26 -7
  33. package/examples/jsm/nodes/functions/BSDF/D_GGX_Anisotropic.js +28 -0
  34. package/examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js +1 -3
  35. package/examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js +29 -0
  36. package/examples/jsm/nodes/functions/PhongLightingModel.js +1 -1
  37. package/examples/jsm/nodes/functions/PhysicalLightingModel.js +164 -10
  38. package/examples/jsm/nodes/functions/ShadowMaskModel.js +31 -0
  39. package/examples/jsm/nodes/lighting/AnalyticLightNode.js +18 -4
  40. package/examples/jsm/nodes/lighting/DirectionalLightNode.js +2 -1
  41. package/examples/jsm/nodes/lighting/EnvironmentNode.js +11 -2
  42. package/examples/jsm/nodes/lighting/IrradianceNode.js +24 -0
  43. package/examples/jsm/nodes/lighting/LightsNode.js +11 -1
  44. package/examples/jsm/nodes/lighting/PointLightNode.js +2 -1
  45. package/examples/jsm/nodes/lighting/SpotLightNode.js +2 -1
  46. package/examples/jsm/nodes/materials/Line2NodeMaterial.js +10 -6
  47. package/examples/jsm/nodes/materials/Materials.js +1 -0
  48. package/examples/jsm/nodes/materials/MeshNormalNodeMaterial.js +0 -2
  49. package/examples/jsm/nodes/materials/MeshPhongNodeMaterial.js +2 -2
  50. package/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +76 -5
  51. package/examples/jsm/nodes/materials/MeshStandardNodeMaterial.js +11 -4
  52. package/examples/jsm/nodes/materials/NodeMaterial.js +31 -41
  53. package/examples/jsm/nodes/materials/ShadowNodeMaterial.js +34 -0
  54. package/examples/jsm/nodes/pmrem/PMREMUtils.js +1 -1
  55. package/examples/jsm/nodes/shadernode/ShaderNode.js +2 -8
  56. package/examples/jsm/physics/JoltPhysics.js +281 -0
  57. package/examples/jsm/postprocessing/RenderTransitionPass.js +193 -0
  58. package/examples/jsm/renderers/common/Background.js +3 -3
  59. package/examples/jsm/renderers/common/ClippingContext.js +1 -1
  60. package/examples/jsm/renderers/common/RenderList.js +1 -1
  61. package/examples/jsm/renderers/common/RenderObject.js +43 -1
  62. package/examples/jsm/renderers/common/Renderer.js +129 -14
  63. package/examples/jsm/renderers/common/Textures.js +1 -1
  64. package/examples/jsm/renderers/common/extras/PMREMGenerator.js +13 -17
  65. package/examples/jsm/renderers/common/nodes/Nodes.js +31 -47
  66. package/examples/jsm/renderers/webgl/WebGLBackend.js +7 -21
  67. package/examples/jsm/renderers/webgl/WebGLBufferRenderer.js +5 -1
  68. package/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +6 -0
  69. package/examples/jsm/renderers/webgl/utils/WebGLTextureUtils.js +21 -7
  70. package/examples/jsm/renderers/webgl/utils/WebGLUtils.js +3 -21
  71. package/examples/jsm/renderers/webgpu/WebGPUBackend.js +33 -45
  72. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +16 -1
  73. package/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js +4 -1
  74. package/examples/jsm/transpiler/GLSLDecoder.js +1 -1
  75. package/examples/jsm/transpiler/ShaderToyDecoder.js +1 -1
  76. package/examples/jsm/utils/SceneUtils.js +60 -1
  77. package/examples/jsm/webxr/OculusHandModel.js +3 -2
  78. package/examples/jsm/webxr/XRHandModelFactory.js +4 -2
  79. package/package.json +1 -1
  80. package/src/constants.js +1 -1
  81. package/src/core/RenderTarget.js +8 -0
  82. package/src/extras/PMREMGenerator.js +12 -11
  83. package/src/loaders/FileLoader.js +1 -1
  84. package/src/loaders/MaterialLoader.js +1 -0
  85. package/src/materials/Material.js +2 -0
  86. package/src/materials/MeshPhysicalMaterial.js +20 -0
  87. package/src/objects/BatchedMesh.js +23 -0
  88. package/src/objects/Line.js +66 -43
  89. package/src/renderers/WebGLRenderer.js +92 -61
  90. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +6 -0
  91. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +1 -0
  92. package/src/renderers/shaders/ShaderChunk/tonemapping_pars_fragment.glsl.js +17 -9
  93. package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +1 -1
  94. package/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js +47 -13
  95. package/src/renderers/shaders/ShaderChunk.js +0 -2
  96. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +4 -0
  97. package/src/renderers/shaders/ShaderLib.js +1 -0
  98. package/src/renderers/webgl/WebGLBackground.js +18 -3
  99. package/src/renderers/webgl/WebGLBufferRenderer.js +36 -0
  100. package/src/renderers/webgl/WebGLCapabilities.js +33 -1
  101. package/src/renderers/webgl/WebGLIndexedBufferRenderer.js +36 -0
  102. package/src/renderers/webgl/WebGLMaterials.js +6 -0
  103. package/src/renderers/webgl/WebGLProgram.js +3 -5
  104. package/src/renderers/webgl/WebGLPrograms.js +5 -0
  105. package/src/renderers/webgl/WebGLRenderStates.js +6 -2
  106. package/src/renderers/webgl/WebGLShadowMap.js +25 -25
  107. package/src/renderers/webgl/WebGLTextures.js +68 -60
  108. package/src/renderers/webgl/WebGLUtils.js +3 -21
  109. package/src/renderers/webxr/WebXRManager.js +2 -4
  110. package/examples/jsm/renderers/webgl-legacy/nodes/GLSL1NodeBuilder.js +0 -318
  111. package/examples/jsm/renderers/webgl-legacy/nodes/SlotNode.js +0 -26
  112. package/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodeBuilder.js +0 -792
  113. package/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodes.js +0 -51
  114. package/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl.js +0 -10
@@ -72,7 +72,6 @@ class NodeBuilder {
72
72
  this.lightsNode = null;
73
73
  this.environmentNode = null;
74
74
  this.fogNode = null;
75
- this.toneMappingNode = null;
76
75
 
77
76
  this.clippingContext = null;
78
77
 
@@ -1087,21 +1086,18 @@ class NodeBuilder {
1087
1086
 
1088
1087
  }
1089
1088
 
1090
- build( convertMaterial = true ) {
1089
+ build() {
1091
1090
 
1092
1091
  const { object, material } = this;
1093
1092
 
1094
- if ( convertMaterial ) {
1095
1093
 
1096
- if ( material !== null ) {
1094
+ if ( material !== null ) {
1097
1095
 
1098
- NodeMaterial.fromMaterial( material ).build( this );
1096
+ NodeMaterial.fromMaterial( material ).build( this );
1099
1097
 
1100
- } else {
1101
-
1102
- this.addFlow( 'compute', object );
1098
+ } else {
1103
1099
 
1104
- }
1100
+ this.addFlow( 'compute', object );
1105
1101
 
1106
1102
  }
1107
1103
 
@@ -8,9 +8,10 @@ class OutputStructNode extends Node {
8
8
 
9
9
  super();
10
10
 
11
- this.isOutputStructNode = true;
12
11
  this.members = members;
13
12
 
13
+ this.isOutputStructNode = true;
14
+
14
15
  }
15
16
 
16
17
  setup( builder ) {
@@ -62,11 +62,21 @@ export const sheenRoughness = nodeImmutable( PropertyNode, 'float', 'SheenRoughn
62
62
  export const iridescence = nodeImmutable( PropertyNode, 'float', 'Iridescence' );
63
63
  export const iridescenceIOR = nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' );
64
64
  export const iridescenceThickness = nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' );
65
+ export const alphaT = nodeImmutable( PropertyNode, 'float', 'AlphaT' );
66
+ export const anisotropy = nodeImmutable( PropertyNode, 'float', 'Anisotropy' );
67
+ export const anisotropyT = nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' );
68
+ export const anisotropyB = nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' );
65
69
  export const specularColor = nodeImmutable( PropertyNode, 'color', 'SpecularColor' );
70
+ export const specularF90 = nodeImmutable( PropertyNode, 'float', 'SpecularF90' );
66
71
  export const shininess = nodeImmutable( PropertyNode, 'float', 'Shininess' );
67
72
  export const output = nodeImmutable( PropertyNode, 'vec4', 'Output' );
68
73
  export const dashSize = nodeImmutable( PropertyNode, 'float', 'dashSize' );
69
74
  export const gapSize = nodeImmutable( PropertyNode, 'float', 'gapSize' );
70
75
  export const pointWidth = nodeImmutable( PropertyNode, 'float', 'pointWidth' );
76
+ export const ior = nodeImmutable( PropertyNode, 'float', 'IOR' );
77
+ export const transmission = nodeImmutable( PropertyNode, 'float', 'Transmission' );
78
+ export const thickness = nodeImmutable( PropertyNode, 'float', 'Thickness' );
79
+ export const attenuationDistance = nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' );
80
+ export const attenuationColor = nodeImmutable( PropertyNode, 'color', 'AttenuationColor' );
71
81
 
72
82
  addNodeClass( 'PropertyNode', PropertyNode );
@@ -9,41 +9,22 @@ import { addNodeElement, tslFn, nodeProxy, float, vec2 } from '../shadernode/Sha
9
9
  // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
10
10
  // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf
11
11
 
12
- // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
13
-
14
12
  const dHdxy_fwd = tslFn( ( { textureNode, bumpScale } ) => {
15
13
 
16
- let texNode = textureNode;
17
-
18
- if ( texNode.isTextureNode !== true ) {
19
-
20
- texNode.traverse( ( node ) => {
21
-
22
- if ( node.isTextureNode === true ) texNode = node;
23
-
24
- } );
25
-
26
- }
27
-
28
- if ( texNode.isTextureNode !== true ) {
29
-
30
- throw new Error( 'THREE.TSL: dHdxy_fwd() requires a TextureNode.' );
31
-
32
- }
33
-
34
- const Hll = float( textureNode );
35
- const uvNode = texNode.uvNode || uv();
36
-
37
14
  // It's used to preserve the same TextureNode instance
38
- const sampleTexture = ( uv ) => textureNode.cache().context( { getUV: () => uv, forceUVContext: true } );
15
+ const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } );
16
+
17
+ const Hll = float( sampleTexture( ( uvNode ) => uvNode ) );
39
18
 
40
19
  return vec2(
41
- float( sampleTexture( uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ),
42
- float( sampleTexture( uvNode.add( uvNode.dFdy() ) ) ).sub( Hll )
20
+ float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ),
21
+ float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdy() ) ) ).sub( Hll )
43
22
  ).mul( bumpScale );
44
23
 
45
24
  } );
46
25
 
26
+ // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
27
+
47
28
  const perturbNormalArb = tslFn( ( inputs ) => {
48
29
 
49
30
  const { surf_pos, surf_norm, dHdxy } = inputs;
@@ -1,5 +1,6 @@
1
1
  import Node, { addNodeClass } from '../core/Node.js';
2
2
  import { nodeImmutable, float } from '../shadernode/ShaderNode.js';
3
+ import { BackSide, WebGLCoordinateSystem } from 'three';
3
4
 
4
5
  class FrontFacingNode extends Node {
5
6
 
@@ -13,6 +14,18 @@ class FrontFacingNode extends Node {
13
14
 
14
15
  generate( builder ) {
15
16
 
17
+ const { renderer, material } = builder;
18
+
19
+ if ( renderer.coordinateSystem === WebGLCoordinateSystem ) {
20
+
21
+ if ( material.side === BackSide ) {
22
+
23
+ return 'false';
24
+
25
+ }
26
+
27
+ }
28
+
16
29
  return builder.getFrontFacing();
17
30
 
18
31
  }
@@ -75,7 +75,7 @@ export const orthographicDepthToViewZ = ( depth, near, far ) => near.sub( far ).
75
75
  // NOTE: https://twitter.com/gonnavis/status/1377183786949959682
76
76
 
77
77
  // -near maps to 0; -far maps to 1
78
- export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( near.sub( far ).mul( viewZ ) );
78
+ export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) );
79
79
 
80
80
  // maps perspective depth in [ 0, 1 ] to viewZ
81
81
  export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) );
@@ -21,7 +21,9 @@ class ViewportNode extends Node {
21
21
 
22
22
  getNodeType() {
23
23
 
24
- return this.scope === ViewportNode.VIEWPORT ? 'vec4' : 'vec2';
24
+ if ( this.scope === ViewportNode.VIEWPORT ) return 'vec4';
25
+ else if ( this.scope === ViewportNode.COORDINATE ) return 'vec3';
26
+ else return 'vec2';
25
27
 
26
28
  }
27
29
 
@@ -99,7 +101,7 @@ class ViewportNode extends Node {
99
101
 
100
102
  const resolution = builder.getNodeProperties( viewportResolution ).outputNode.build( builder );
101
103
 
102
- coord = `${ builder.getType( 'vec2' ) }( ${ coord }.x, ${ resolution }.y - ${ coord }.y )`;
104
+ coord = `${ builder.getType( 'vec3' ) }( ${ coord }.x, ${ resolution }.y - ${ coord }.y, ${ coord }.z )`;
103
105
 
104
106
  }
105
107
 
@@ -58,7 +58,10 @@ class ViewportTextureNode extends TextureNode {
58
58
 
59
59
  clone() {
60
60
 
61
- return new this.constructor( this.uvNode, this.levelNode, this.value );
61
+ const viewportTextureNode = new this.constructor( this.uvNode, this.levelNode, this.value );
62
+ viewportTextureNode.generateMipmaps = this.generateMipmaps;
63
+
64
+ return viewportTextureNode;
62
65
 
63
66
  }
64
67
 
@@ -1,15 +1,17 @@
1
1
  import F_Schlick from './F_Schlick.js';
2
2
  import V_GGX_SmithCorrelated from './V_GGX_SmithCorrelated.js';
3
+ import V_GGX_SmithCorrelated_Anisotropic from './V_GGX_SmithCorrelated_Anisotropic.js';
3
4
  import D_GGX from './D_GGX.js';
5
+ import D_GGX_Anisotropic from './D_GGX_Anisotropic.js';
4
6
  import { transformedNormalView } from '../../accessors/NormalNode.js';
5
7
  import { positionViewDirection } from '../../accessors/PositionNode.js';
6
- import { iridescence } from '../../core/PropertyNode.js';
7
- import { tslFn } from '../../shadernode/ShaderNode.js';
8
+ import { iridescence, alphaT, anisotropyT, anisotropyB } from '../../core/PropertyNode.js';
9
+ import { tslFn, defined } from '../../shadernode/ShaderNode.js';
8
10
 
9
11
  // GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
10
12
  const BRDF_GGX = tslFn( ( inputs ) => {
11
13
 
12
- const { lightDirection, f0, f90, roughness, iridescenceFresnel } = inputs;
14
+ const { lightDirection, f0, f90, roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } = inputs;
13
15
 
14
16
  const normalView = inputs.normalView || transformedNormalView;
15
17
 
@@ -23,15 +25,32 @@ const BRDF_GGX = tslFn( ( inputs ) => {
23
25
  const dotVH = positionViewDirection.dot( halfDir ).clamp();
24
26
 
25
27
  let F = F_Schlick( { f0, f90, dotVH } );
28
+ let V, D;
26
29
 
27
- if ( iridescenceFresnel ) {
30
+ if ( defined( USE_IRIDESCENCE ) ) {
28
31
 
29
- F = iridescence.mix( F, iridescenceFresnel );
32
+ F = iridescence.mix( F, f );
30
33
 
31
34
  }
32
35
 
33
- const V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } );
34
- const D = D_GGX( { alpha, dotNH } );
36
+ if ( defined( USE_ANISOTROPY ) ) {
37
+
38
+ const dotTL = anisotropyT.dot( lightDirection );
39
+ const dotTV = anisotropyT.dot( positionViewDirection );
40
+ const dotTH = anisotropyT.dot( halfDir );
41
+ const dotBL = anisotropyB.dot( lightDirection );
42
+ const dotBV = anisotropyB.dot( positionViewDirection );
43
+ const dotBH = anisotropyB.dot( halfDir );
44
+
45
+ V = V_GGX_SmithCorrelated_Anisotropic( { alphaT, alphaB: alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } );
46
+ D = D_GGX_Anisotropic( { alphaT, alphaB: alpha, dotNH, dotTH, dotBH } );
47
+
48
+ } else {
49
+
50
+ V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } );
51
+ D = D_GGX( { alpha, dotNH } );
52
+
53
+ }
35
54
 
36
55
  return F.mul( V ).mul( D );
37
56
 
@@ -0,0 +1,28 @@
1
+ import { tslFn, float, vec3 } from '../../shadernode/ShaderNode.js';
2
+
3
+ const RECIPROCAL_PI = float( 1 / Math.PI );
4
+
5
+ // https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf
6
+
7
+ const D_GGX_Anisotropic = tslFn( ( { alphaT, alphaB, dotNH, dotTH, dotBH } ) => {
8
+
9
+ const a2 = alphaT.mul( alphaB );
10
+ const v = vec3( alphaB.mul( dotTH ), alphaT.mul( dotBH ), a2.mul( dotNH ) );
11
+ const v2 = v.dot( v );
12
+ const w2 = a2.div( v2 );
13
+
14
+ return RECIPROCAL_PI.mul( a2.mul( w2.pow2() ) );
15
+
16
+ } ).setLayout( {
17
+ name: 'D_GGX_Anisotropic',
18
+ type: 'float',
19
+ inputs: [
20
+ { name: 'alphaT', type: 'float', qualifier: 'in' },
21
+ { name: 'alphaB', type: 'float', qualifier: 'in' },
22
+ { name: 'dotNH', type: 'float', qualifier: 'in' },
23
+ { name: 'dotTH', type: 'float', qualifier: 'in' },
24
+ { name: 'dotBH', type: 'float', qualifier: 'in' }
25
+ ]
26
+ } );
27
+
28
+ export default D_GGX_Anisotropic;
@@ -4,9 +4,7 @@ import { tslFn } from '../../shadernode/ShaderNode.js';
4
4
 
5
5
  // Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2
6
6
  // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
7
- const V_GGX_SmithCorrelated = tslFn( ( inputs ) => {
8
-
9
- const { alpha, dotNL, dotNV } = inputs;
7
+ const V_GGX_SmithCorrelated = tslFn( ( { alpha, dotNL, dotNV } ) => {
10
8
 
11
9
  const a2 = alpha.pow2();
12
10
 
@@ -0,0 +1,29 @@
1
+ import { div } from '../../math/OperatorNode.js';
2
+ import { tslFn, vec3 } from '../../shadernode/ShaderNode.js';
3
+
4
+ // https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf
5
+
6
+ const V_GGX_SmithCorrelated_Anisotropic = tslFn( ( { alphaT, alphaB, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ) => {
7
+
8
+ const gv = dotNL.mul( vec3( alphaT.mul( dotTV ), alphaB.mul( dotBV ), dotNV ).length() );
9
+ const gl = dotNV.mul( vec3( alphaT.mul( dotTL ), alphaB.mul( dotBL ), dotNL ).length() );
10
+ const v = div( 0.5, gv.add( gl ) );
11
+
12
+ return v.saturate();
13
+
14
+ } ).setLayout( {
15
+ name: 'V_GGX_SmithCorrelated_Anisotropic',
16
+ type: 'float',
17
+ inputs: [
18
+ { name: 'alphaT', type: 'float', qualifier: 'in' },
19
+ { name: 'alphaB', type: 'float', qualifier: 'in' },
20
+ { name: 'dotTV', type: 'float', qualifier: 'in' },
21
+ { name: 'dotBV', type: 'float', qualifier: 'in' },
22
+ { name: 'dotTL', type: 'float', qualifier: 'in' },
23
+ { name: 'dotBL', type: 'float', qualifier: 'in' },
24
+ { name: 'dotNV', type: 'float', qualifier: 'in' },
25
+ { name: 'dotNL', type: 'float', qualifier: 'in' }
26
+ ]
27
+ } );
28
+
29
+ export default V_GGX_SmithCorrelated_Anisotropic;
@@ -12,7 +12,7 @@ const G_BlinnPhong_Implicit = () => float( 0.25 );
12
12
 
13
13
  const D_BlinnPhong = tslFn( ( { dotNH } ) => {
14
14
 
15
- return shininess.mul( 0.5 / Math.PI ).add( 1.0 ).mul( dotNH.pow( shininess ) );
15
+ return shininess.mul( float( 0.5 ) ).add( 1.0 ).mul( float( 1 / Math.PI ) ).mul( dotNH.pow( shininess ) );
16
16
 
17
17
  } );
18
18
 
@@ -6,12 +6,135 @@ import F_Schlick from './BSDF/F_Schlick.js';
6
6
  import Schlick_to_F0 from './BSDF/Schlick_to_F0.js';
7
7
  import BRDF_Sheen from './BSDF/BRDF_Sheen.js';
8
8
  import LightingModel from '../core/LightingModel.js';
9
- import { diffuseColor, specularColor, roughness, clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness } from '../core/PropertyNode.js';
10
- import { transformedNormalView, transformedClearcoatNormalView } from '../accessors/NormalNode.js';
11
- import { positionViewDirection } from '../accessors/PositionNode.js';
12
- import { tslFn, float, vec3, mat3 } from '../shadernode/ShaderNode.js';
9
+ import { diffuseColor, specularColor, specularF90, roughness, clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness, ior, thickness, transmission, attenuationDistance, attenuationColor } from '../core/PropertyNode.js';
10
+ import { transformedNormalView, transformedClearcoatNormalView, transformedNormalWorld } from '../accessors/NormalNode.js';
11
+ import { positionViewDirection, positionWorld } from '../accessors/PositionNode.js';
12
+ import { tslFn, float, vec2, vec3, vec4, mat3, If } from '../shadernode/ShaderNode.js';
13
13
  import { cond } from '../math/CondNode.js';
14
- import { mix, smoothstep } from '../math/MathNode.js';
14
+ import { mix, normalize, refract, length, clamp, log2, log, exp, smoothstep } from '../math/MathNode.js';
15
+ import { div } from '../math/OperatorNode.js';
16
+ import { cameraPosition, cameraProjectionMatrix, cameraViewMatrix } from '../accessors/CameraNode.js';
17
+ import { modelWorldMatrix } from '../accessors/ModelNode.js';
18
+ import { viewportResolution } from '../display/ViewportNode.js';
19
+ import { viewportMipTexture } from '../display/ViewportTextureNode.js';
20
+
21
+ //
22
+ // Transmission
23
+ //
24
+
25
+ const getVolumeTransmissionRay = tslFn( ( [ n, v, thickness, ior, modelMatrix ] ) => {
26
+
27
+ // Direction of refracted light.
28
+ const refractionVector = vec3( refract( v.negate(), normalize( n ), div( 1.0, ior ) ) );
29
+
30
+ // Compute rotation-independant scaling of the model matrix.
31
+ const modelScale = vec3(
32
+ length( modelMatrix[ 0 ].xyz ),
33
+ length( modelMatrix[ 1 ].xyz ),
34
+ length( modelMatrix[ 2 ].xyz )
35
+ );
36
+
37
+ // The thickness is specified in local space.
38
+ return normalize( refractionVector ).mul( thickness.mul( modelScale ) );
39
+
40
+ } ).setLayout( {
41
+ name: 'getVolumeTransmissionRay',
42
+ type: 'vec3',
43
+ inputs: [
44
+ { name: 'n', type: 'vec3' },
45
+ { name: 'v', type: 'vec3' },
46
+ { name: 'thickness', type: 'float' },
47
+ { name: 'ior', type: 'float' },
48
+ { name: 'modelMatrix', type: 'mat4' }
49
+ ]
50
+ } );
51
+
52
+ const applyIorToRoughness = tslFn( ( [ roughness, ior ] ) => {
53
+
54
+ // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and
55
+ // an IOR of 1.5 results in the default amount of microfacet refraction.
56
+ return roughness.mul( clamp( ior.mul( 2.0 ).sub( 2.0 ), 0.0, 1.0 ) );
57
+
58
+ } ).setLayout( {
59
+ name: 'applyIorToRoughness',
60
+ type: 'float',
61
+ inputs: [
62
+ { name: 'roughness', type: 'float' },
63
+ { name: 'ior', type: 'float' }
64
+ ]
65
+ } );
66
+
67
+ const singleViewportMipTexture = viewportMipTexture();
68
+
69
+ const getTransmissionSample = tslFn( ( [ fragCoord, roughness, ior ] ) => {
70
+
71
+ const transmissionSample = singleViewportMipTexture.uv( fragCoord );
72
+ //const transmissionSample = viewportMipTexture( fragCoord );
73
+
74
+ const lod = log2( float( viewportResolution.x ) ).mul( applyIorToRoughness( roughness, ior ) );
75
+
76
+ return transmissionSample.bicubic( lod );
77
+
78
+ } );
79
+
80
+ const volumeAttenuation = tslFn( ( [ transmissionDistance, attenuationColor, attenuationDistance ] ) => {
81
+
82
+ If( attenuationDistance.notEqual( 0 ), () => {
83
+
84
+ // Compute light attenuation using Beer's law.
85
+ const attenuationCoefficient = log( attenuationColor ).negate().div( attenuationDistance );
86
+ const transmittance = exp( attenuationCoefficient.negate().mul( transmissionDistance ) );
87
+
88
+ return transmittance;
89
+
90
+ } );
91
+
92
+ // Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all.
93
+ return vec3( 1.0 );
94
+
95
+ } ).setLayout( {
96
+ name: 'volumeAttenuation',
97
+ type: 'vec3',
98
+ inputs: [
99
+ { name: 'transmissionDistance', type: 'float' },
100
+ { name: 'attenuationColor', type: 'vec3' },
101
+ { name: 'attenuationDistance', type: 'float' }
102
+ ]
103
+ } );
104
+
105
+ const getIBLVolumeRefraction = tslFn( ( [ n, v, roughness, diffuseColor, specularColor, specularF90, position, modelMatrix, viewMatrix, projMatrix, ior, thickness, attenuationColor, attenuationDistance ] ) => {
106
+
107
+ const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );
108
+ const refractedRayExit = position.add( transmissionRay );
109
+
110
+ // Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
111
+ const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) );
112
+ const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar();
113
+ refractionCoords.addAssign( 1.0 );
114
+ refractionCoords.divAssign( 2.0 );
115
+ refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu
116
+
117
+ // Sample framebuffer to get pixel the refracted ray hits.
118
+ const transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );
119
+ const transmittance = diffuseColor.mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ) );
120
+ const attenuatedColor = transmittance.rgb.mul( transmittedLight.rgb );
121
+ const dotNV = n.dot( v ).clamp();
122
+
123
+ // Get the specular component.
124
+ const F = vec3( EnvironmentBRDF( { // n, v, specularColor, specularF90, roughness
125
+ dotNV,
126
+ specularColor,
127
+ specularF90,
128
+ roughness
129
+ } ) );
130
+
131
+ // As less light is transmitted, the opacity should be increased. This simple approximation does a decent job
132
+ // of modulating a CSS background, and has no effect when the buffer is opaque, due to a solid object or clear color.
133
+ const transmittanceFactor = transmittance.r.add( transmittance.g, transmittance.b ).div( 3.0 );
134
+
135
+ return vec4( F.oneMinus().mul( attenuatedColor ), transmittedLight.a.oneMinus().mul( transmittanceFactor ).oneMinus() );
136
+
137
+ } );
15
138
 
16
139
  //
17
140
  // Iridescence
@@ -172,13 +295,15 @@ const clearcoatF90 = vec3( 1 );
172
295
 
173
296
  class PhysicalLightingModel extends LightingModel {
174
297
 
175
- constructor( clearcoat = false, sheen = false, iridescence = false ) {
298
+ constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false ) {
176
299
 
177
300
  super();
178
301
 
179
302
  this.clearcoat = clearcoat;
180
303
  this.sheen = sheen;
181
304
  this.iridescence = iridescence;
305
+ this.anisotropy = anisotropy;
306
+ this.transmission = transmission;
182
307
 
183
308
  this.clearcoatRadiance = null;
184
309
  this.clearcoatSpecularDirect = null;
@@ -190,7 +315,7 @@ class PhysicalLightingModel extends LightingModel {
190
315
 
191
316
  }
192
317
 
193
- start( /*context*/ ) {
318
+ start( context ) {
194
319
 
195
320
  if ( this.clearcoat === true ) {
196
321
 
@@ -223,13 +348,42 @@ class PhysicalLightingModel extends LightingModel {
223
348
 
224
349
  }
225
350
 
351
+ if ( this.transmission === true ) {
352
+
353
+ const position = positionWorld;
354
+ const v = cameraPosition.sub( positionWorld ).normalize(); // TODO: Create Node for this, same issue in MaterialX
355
+ const n = transformedNormalWorld;
356
+
357
+ context.backdrop = getIBLVolumeRefraction(
358
+ n,
359
+ v,
360
+ roughness,
361
+ diffuseColor,
362
+ specularColor,
363
+ specularF90, // specularF90
364
+ position, // positionWorld
365
+ modelWorldMatrix, // modelMatrix
366
+ cameraViewMatrix, // viewMatrix
367
+ cameraProjectionMatrix, // projMatrix
368
+ ior,
369
+ thickness,
370
+ attenuationColor,
371
+ attenuationDistance
372
+ );
373
+
374
+ context.backdropAlpha = transmission;
375
+
376
+ diffuseColor.a.mulAssign( mix( 1, context.backdrop.a, transmission ) );
377
+
378
+ }
379
+
226
380
  }
227
381
 
228
382
  // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
229
383
  // Approximates multiscattering in order to preserve energy.
230
384
  // http://www.jcgt.org/published/0008/01/03/
231
385
 
232
- computeMultiscattering( singleScatter, multiScatter, specularF90 = float( 1 ) ) {
386
+ computeMultiscattering( singleScatter, multiScatter, specularF90 ) {
233
387
 
234
388
  const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
235
389
 
@@ -272,7 +426,7 @@ class PhysicalLightingModel extends LightingModel {
272
426
 
273
427
  reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
274
428
 
275
- reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, iridescenceFresnel: this.iridescenceFresnel } ) ) );
429
+ reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy } ) ) );
276
430
 
277
431
  }
278
432
 
@@ -318,7 +472,7 @@ class PhysicalLightingModel extends LightingModel {
318
472
  const multiScattering = vec3().temp( 'multiScattering' );
319
473
  const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI );
320
474
 
321
- this.computeMultiscattering( singleScattering, multiScattering );
475
+ this.computeMultiscattering( singleScattering, multiScattering, specularF90 );
322
476
 
323
477
  const totalScattering = singleScattering.add( multiScattering );
324
478
 
@@ -0,0 +1,31 @@
1
+ import LightingModel from '../core/LightingModel.js';
2
+ import { diffuseColor } from '../core/PropertyNode.js';
3
+ import { float } from '../shadernode/ShaderNode.js';
4
+
5
+ class ShadowMaskModel extends LightingModel {
6
+
7
+ constructor() {
8
+
9
+ super();
10
+
11
+ this.shadowNode = float( 1 ).toVar( 'shadowMask' );
12
+
13
+ }
14
+
15
+ direct( { shadowMask } ) {
16
+
17
+ this.shadowNode.mulAssign( shadowMask );
18
+
19
+ }
20
+
21
+ finish( context ) {
22
+
23
+ diffuseColor.a.mulAssign( this.shadowNode.oneMinus() );
24
+
25
+ context.outgoingLight.rgb.assign( diffuseColor.rgb ); // TODO: Optimize LightsNode to avoid this assignment
26
+
27
+ }
28
+
29
+ }
30
+
31
+ export default ShadowMaskModel;