@luma.gl/shadertools 9.2.6 → 9.3.0-alpha.10

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 (174) hide show
  1. package/dist/dist.dev.js +4798 -6439
  2. package/dist/dist.min.js +2047 -311
  3. package/dist/index.cjs +3033 -507
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +12 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +5 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/preprocessor/preprocessor.d.ts.map +1 -1
  10. package/dist/lib/preprocessor/preprocessor.js +35 -8
  11. package/dist/lib/preprocessor/preprocessor.js.map +1 -1
  12. package/dist/lib/shader-assembler.d.ts +10 -0
  13. package/dist/lib/shader-assembler.d.ts.map +1 -1
  14. package/dist/lib/shader-assembler.js +20 -3
  15. package/dist/lib/shader-assembler.js.map +1 -1
  16. package/dist/lib/shader-assembly/assemble-shaders.d.ts +23 -2
  17. package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
  18. package/dist/lib/shader-assembly/assemble-shaders.js +214 -11
  19. package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
  20. package/dist/lib/shader-assembly/wgsl-binding-debug.d.ts +37 -0
  21. package/dist/lib/shader-assembly/wgsl-binding-debug.d.ts.map +1 -0
  22. package/dist/lib/shader-assembly/wgsl-binding-debug.js +140 -0
  23. package/dist/lib/shader-assembly/wgsl-binding-debug.js.map +1 -0
  24. package/dist/lib/shader-generator/glsl/generate-glsl.js +7 -4
  25. package/dist/lib/shader-generator/glsl/generate-glsl.js.map +1 -1
  26. package/dist/lib/shader-generator/wgsl/generate-wgsl.d.ts.map +1 -1
  27. package/dist/lib/shader-generator/wgsl/generate-wgsl.js +3 -0
  28. package/dist/lib/shader-generator/wgsl/generate-wgsl.js.map +1 -1
  29. package/dist/lib/shader-module/shader-module-uniform-layout.d.ts +91 -0
  30. package/dist/lib/shader-module/shader-module-uniform-layout.d.ts.map +1 -0
  31. package/dist/lib/shader-module/shader-module-uniform-layout.js +209 -0
  32. package/dist/lib/shader-module/shader-module-uniform-layout.js.map +1 -0
  33. package/dist/lib/shader-module/shader-module.d.ts +12 -6
  34. package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
  35. package/dist/lib/shader-module/shader-module.js.map +1 -1
  36. package/dist/lib/utils/assert.d.ts.map +1 -1
  37. package/dist/lib/utils/assert.js +3 -1
  38. package/dist/lib/utils/assert.js.map +1 -1
  39. package/dist/lib/utils/uniform-types.d.ts +11 -7
  40. package/dist/lib/utils/uniform-types.d.ts.map +1 -1
  41. package/dist/modules/engine/picking/picking.d.ts +5 -2
  42. package/dist/modules/engine/picking/picking.d.ts.map +1 -1
  43. package/dist/modules/engine/picking/picking.js +5 -2
  44. package/dist/modules/engine/picking/picking.js.map +1 -1
  45. package/dist/modules/engine/project/project.d.ts +1 -1
  46. package/dist/modules/engine/project/project.js +1 -1
  47. package/dist/modules/engine/skin/skin.d.ts +30 -0
  48. package/dist/modules/engine/skin/skin.d.ts.map +1 -0
  49. package/dist/modules/engine/skin/skin.js +86 -0
  50. package/dist/modules/engine/skin/skin.js.map +1 -0
  51. package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts +1 -0
  52. package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts.map +1 -1
  53. package/dist/modules/lighting/gouraud-material/gouraud-material.js +3 -0
  54. package/dist/modules/lighting/gouraud-material/gouraud-material.js.map +1 -1
  55. package/dist/modules/lighting/ibl/ibl.d.ts +26 -0
  56. package/dist/modules/lighting/ibl/ibl.d.ts.map +1 -0
  57. package/dist/modules/lighting/ibl/ibl.js +33 -0
  58. package/dist/modules/lighting/ibl/ibl.js.map +1 -0
  59. package/dist/modules/lighting/lambert-material/lambert-material.d.ts +10 -0
  60. package/dist/modules/lighting/lambert-material/lambert-material.d.ts.map +1 -0
  61. package/dist/modules/lighting/lambert-material/lambert-material.js +33 -0
  62. package/dist/modules/lighting/lambert-material/lambert-material.js.map +1 -0
  63. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts +3 -0
  64. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts.map +1 -0
  65. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js +60 -0
  66. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js.map +1 -0
  67. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.d.ts +2 -0
  68. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.d.ts.map +1 -0
  69. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.js +73 -0
  70. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.js.map +1 -0
  71. package/dist/modules/lighting/lights/lighting-glsl.d.ts +1 -1
  72. package/dist/modules/lighting/lights/lighting-glsl.d.ts.map +1 -1
  73. package/dist/modules/lighting/lights/lighting-glsl.js +44 -38
  74. package/dist/modules/lighting/lights/lighting-glsl.js.map +1 -1
  75. package/dist/modules/lighting/lights/lighting-wgsl.d.ts +1 -1
  76. package/dist/modules/lighting/lights/lighting-wgsl.d.ts.map +1 -1
  77. package/dist/modules/lighting/lights/lighting-wgsl.js +46 -18
  78. package/dist/modules/lighting/lights/lighting-wgsl.js.map +1 -1
  79. package/dist/modules/lighting/lights/lighting.d.ts +104 -62
  80. package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
  81. package/dist/modules/lighting/lights/lighting.js +107 -68
  82. package/dist/modules/lighting/lights/lighting.js.map +1 -1
  83. package/dist/modules/lighting/no-material/dirlight.d.ts +8 -3
  84. package/dist/modules/lighting/no-material/dirlight.d.ts.map +1 -1
  85. package/dist/modules/lighting/no-material/dirlight.js +4 -2
  86. package/dist/modules/lighting/no-material/dirlight.js.map +1 -1
  87. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +1 -1
  88. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
  89. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +581 -28
  90. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js.map +1 -1
  91. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +2 -2
  92. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
  93. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +850 -107
  94. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
  95. package/dist/modules/lighting/pbr-material/pbr-material.d.ts +172 -41
  96. package/dist/modules/lighting/pbr-material/pbr-material.d.ts.map +1 -1
  97. package/dist/modules/lighting/pbr-material/pbr-material.js +109 -1
  98. package/dist/modules/lighting/pbr-material/pbr-material.js.map +1 -1
  99. package/dist/modules/lighting/pbr-material/pbr-projection.d.ts.map +1 -1
  100. package/dist/modules/lighting/pbr-material/pbr-projection.js +14 -2
  101. package/dist/modules/lighting/pbr-material/pbr-projection.js.map +1 -1
  102. package/dist/modules/lighting/pbr-material/pbr-scene.d.ts +40 -0
  103. package/dist/modules/lighting/pbr-material/pbr-scene.d.ts.map +1 -0
  104. package/dist/modules/lighting/pbr-material/pbr-scene.js +67 -0
  105. package/dist/modules/lighting/pbr-material/pbr-scene.js.map +1 -0
  106. package/dist/modules/lighting/phong-material/phong-material.d.ts +1 -0
  107. package/dist/modules/lighting/phong-material/phong-material.d.ts.map +1 -1
  108. package/dist/modules/lighting/phong-material/phong-material.js +4 -0
  109. package/dist/modules/lighting/phong-material/phong-material.js.map +1 -1
  110. package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts +2 -2
  111. package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts.map +1 -1
  112. package/dist/modules/lighting/phong-material/phong-shaders-glsl.js +17 -6
  113. package/dist/modules/lighting/phong-material/phong-shaders-glsl.js.map +1 -1
  114. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts +1 -40
  115. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts.map +1 -1
  116. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js +71 -76
  117. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js.map +1 -1
  118. package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts +1 -1
  119. package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts.map +1 -1
  120. package/dist/modules/math/fp64/fp64-arithmetic-glsl.js +42 -11
  121. package/dist/modules/math/fp64/fp64-arithmetic-glsl.js.map +1 -1
  122. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts +2 -0
  123. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts.map +1 -0
  124. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js +212 -0
  125. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js.map +1 -0
  126. package/dist/modules/math/fp64/fp64.d.ts +1 -0
  127. package/dist/modules/math/fp64/fp64.d.ts.map +1 -1
  128. package/dist/modules/math/fp64/fp64.js +8 -2
  129. package/dist/modules/math/fp64/fp64.js.map +1 -1
  130. package/dist/modules/math/random/random.d.ts +1 -1
  131. package/dist/modules/math/random/random.d.ts.map +1 -1
  132. package/dist/modules/math/random/random.js +2 -3
  133. package/dist/modules/math/random/random.js.map +1 -1
  134. package/package.json +4 -5
  135. package/src/index.ts +37 -6
  136. package/src/lib/preprocessor/preprocessor.ts +44 -8
  137. package/src/lib/shader-assembler.ts +25 -3
  138. package/src/lib/shader-assembly/assemble-shaders.ts +384 -12
  139. package/src/lib/shader-assembly/wgsl-binding-debug.ts +216 -0
  140. package/src/lib/shader-generator/glsl/generate-glsl.ts +11 -5
  141. package/src/lib/shader-generator/wgsl/generate-wgsl.ts +6 -0
  142. package/src/lib/shader-module/shader-module-uniform-layout.ts +346 -0
  143. package/src/lib/shader-module/shader-module.ts +17 -7
  144. package/src/lib/utils/assert.ts +3 -1
  145. package/src/lib/utils/uniform-types.ts +24 -9
  146. package/src/modules/engine/picking/picking.ts +5 -2
  147. package/src/modules/engine/project/project.ts +1 -1
  148. package/src/modules/engine/skin/skin.ts +114 -0
  149. package/src/modules/lighting/gouraud-material/gouraud-material.ts +4 -0
  150. package/src/modules/lighting/ibl/ibl.ts +44 -0
  151. package/src/modules/lighting/lambert-material/lambert-material.ts +42 -0
  152. package/src/modules/lighting/lambert-material/lambert-shaders-glsl.ts +61 -0
  153. package/src/modules/lighting/lambert-material/lambert-shaders-wgsl.ts +73 -0
  154. package/src/modules/lighting/lights/lighting-glsl.ts +44 -38
  155. package/src/modules/lighting/lights/lighting-wgsl.ts +46 -18
  156. package/src/modules/lighting/lights/lighting.ts +198 -99
  157. package/src/modules/lighting/no-material/dirlight.ts +4 -2
  158. package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +581 -28
  159. package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +850 -107
  160. package/src/modules/lighting/pbr-material/pbr-material.ts +185 -5
  161. package/src/modules/lighting/pbr-material/pbr-projection.ts +15 -2
  162. package/src/modules/lighting/pbr-material/pbr-scene.ts +91 -0
  163. package/src/modules/lighting/phong-material/phong-material.ts +5 -0
  164. package/src/modules/lighting/phong-material/phong-shaders-glsl.ts +17 -6
  165. package/src/modules/lighting/phong-material/phong-shaders-wgsl.ts +71 -77
  166. package/src/modules/math/fp64/fp64-arithmetic-glsl.ts +42 -11
  167. package/src/modules/math/fp64/fp64-arithmetic-wgsl.ts +212 -0
  168. package/src/modules/math/fp64/fp64.ts +9 -3
  169. package/src/modules/math/random/random.ts +2 -3
  170. package/dist/lib/wgsl/get-shader-layout-wgsl.d.ts +0 -8
  171. package/dist/lib/wgsl/get-shader-layout-wgsl.d.ts.map +0 -1
  172. package/dist/lib/wgsl/get-shader-layout-wgsl.js +0 -95
  173. package/dist/lib/wgsl/get-shader-layout-wgsl.js.map +0 -1
  174. package/src/lib/wgsl/get-shader-layout-wgsl.ts +0 -105
@@ -37,6 +37,42 @@ uniform pbrMaterialUniforms {
37
37
 
38
38
  bool alphaCutoffEnabled;
39
39
  float alphaCutoff; // #ifdef ALPHA_CUTOFF
40
+
41
+ vec3 specularColorFactor;
42
+ float specularIntensityFactor;
43
+ bool specularColorMapEnabled;
44
+ bool specularIntensityMapEnabled;
45
+
46
+ float ior;
47
+
48
+ float transmissionFactor;
49
+ bool transmissionMapEnabled;
50
+
51
+ float thicknessFactor;
52
+ float attenuationDistance;
53
+ vec3 attenuationColor;
54
+
55
+ float clearcoatFactor;
56
+ float clearcoatRoughnessFactor;
57
+ bool clearcoatMapEnabled;
58
+ bool clearcoatRoughnessMapEnabled;
59
+
60
+ vec3 sheenColorFactor;
61
+ float sheenRoughnessFactor;
62
+ bool sheenColorMapEnabled;
63
+ bool sheenRoughnessMapEnabled;
64
+
65
+ float iridescenceFactor;
66
+ float iridescenceIor;
67
+ vec2 iridescenceThicknessRange;
68
+ bool iridescenceMapEnabled;
69
+
70
+ float anisotropyStrength;
71
+ float anisotropyRotation;
72
+ vec2 anisotropyDirection;
73
+ bool anisotropyMapEnabled;
74
+
75
+ float emissiveStrength;
40
76
 
41
77
  // IBL
42
78
  bool IBLenabled;
@@ -65,6 +101,42 @@ uniform sampler2D u_MetallicRoughnessSampler;
65
101
  #ifdef HAS_OCCLUSIONMAP
66
102
  uniform sampler2D u_OcclusionSampler;
67
103
  #endif
104
+ #ifdef HAS_SPECULARCOLORMAP
105
+ uniform sampler2D u_SpecularColorSampler;
106
+ #endif
107
+ #ifdef HAS_SPECULARINTENSITYMAP
108
+ uniform sampler2D u_SpecularIntensitySampler;
109
+ #endif
110
+ #ifdef HAS_TRANSMISSIONMAP
111
+ uniform sampler2D u_TransmissionSampler;
112
+ #endif
113
+ #ifdef HAS_THICKNESSMAP
114
+ uniform sampler2D u_ThicknessSampler;
115
+ #endif
116
+ #ifdef HAS_CLEARCOATMAP
117
+ uniform sampler2D u_ClearcoatSampler;
118
+ #endif
119
+ #ifdef HAS_CLEARCOATROUGHNESSMAP
120
+ uniform sampler2D u_ClearcoatRoughnessSampler;
121
+ #endif
122
+ #ifdef HAS_CLEARCOATNORMALMAP
123
+ uniform sampler2D u_ClearcoatNormalSampler;
124
+ #endif
125
+ #ifdef HAS_SHEENCOLORMAP
126
+ uniform sampler2D u_SheenColorSampler;
127
+ #endif
128
+ #ifdef HAS_SHEENROUGHNESSMAP
129
+ uniform sampler2D u_SheenRoughnessSampler;
130
+ #endif
131
+ #ifdef HAS_IRIDESCENCEMAP
132
+ uniform sampler2D u_IridescenceSampler;
133
+ #endif
134
+ #ifdef HAS_IRIDESCENCETHICKNESSMAP
135
+ uniform sampler2D u_IridescenceThicknessSampler;
136
+ #endif
137
+ #ifdef HAS_ANISOTROPYMAP
138
+ uniform sampler2D u_AnisotropySampler;
139
+ #endif
68
140
  #ifdef USE_IBL
69
141
  uniform samplerCube u_DiffuseEnvSampler;
70
142
  uniform samplerCube u_SpecularEnvSampler;
@@ -77,57 +149,97 @@ export const source = /* wgsl */ `\
77
149
  struct PBRFragmentInputs {
78
150
  pbr_vPosition: vec3f,
79
151
  pbr_vUV: vec2f,
80
- pbr_vTBN: mat3f,
152
+ pbr_vTBN: mat3x3f,
81
153
  pbr_vNormal: vec3f
82
154
  };
83
155
 
84
- var fragmentInputs: PBRFragmentInputs;
156
+ var<private> fragmentInputs: PBRFragmentInputs;
85
157
 
86
158
  fn pbr_setPositionNormalTangentUV(position: vec4f, normal: vec4f, tangent: vec4f, uv: vec2f)
87
159
  {
88
160
  var pos: vec4f = pbrProjection.modelMatrix * position;
89
- pbr_vPosition = vec3(pos.xyz) / pos.w;
161
+ fragmentInputs.pbr_vPosition = pos.xyz / pos.w;
162
+ fragmentInputs.pbr_vNormal = vec3f(0.0, 0.0, 1.0);
163
+ fragmentInputs.pbr_vTBN = mat3x3f(
164
+ vec3f(1.0, 0.0, 0.0),
165
+ vec3f(0.0, 1.0, 0.0),
166
+ vec3f(0.0, 0.0, 1.0)
167
+ );
168
+ fragmentInputs.pbr_vUV = vec2f(0.0, 0.0);
90
169
 
91
170
  #ifdef HAS_NORMALS
171
+ let normalW: vec3f = normalize((pbrProjection.normalMatrix * vec4f(normal.xyz, 0.0)).xyz);
172
+ fragmentInputs.pbr_vNormal = normalW;
92
173
  #ifdef HAS_TANGENTS
93
- let normalW: vec3f = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));
94
- let tangentW: vec3f = normalize(vec3(pbrProjection.modelMatrix * vec4(tangent.xyz, 0.0)));
174
+ let tangentW: vec3f = normalize((pbrProjection.modelMatrix * vec4f(tangent.xyz, 0.0)).xyz);
95
175
  let bitangentW: vec3f = cross(normalW, tangentW) * tangent.w;
96
- fragmentInputs,pbr_vTBN = mat3(tangentW, bitangentW, normalW);
97
- #else // HAS_TANGENTS != 1
98
- fragmentInputs.pbr_vNormal = normalize(vec3(pbrProjection.modelMatrix * vec4(normal.xyz, 0.0)));
176
+ fragmentInputs.pbr_vTBN = mat3x3f(tangentW, bitangentW, normalW);
99
177
  #endif
100
178
  #endif
101
179
 
102
180
  #ifdef HAS_UV
103
- pbr_vUV = uv;
104
- #else
105
- pbr_vUV = vec2(0.,0.);
181
+ fragmentInputs.pbr_vUV = uv;
106
182
  #endif
107
183
  }
108
184
 
109
185
  struct pbrMaterialUniforms {
110
186
  // Material is unlit
111
- unlit: uint32,
187
+ unlit: u32,
112
188
 
113
189
  // Base color map
114
- baseColorMapEnabled: uint32,
190
+ baseColorMapEnabled: u32,
115
191
  baseColorFactor: vec4f,
116
192
 
117
- normalMapEnabled : uint32,
193
+ normalMapEnabled : u32,
118
194
  normalScale: f32, // #ifdef HAS_NORMALMAP
119
195
 
120
- emissiveMapEnabled: uint32,
196
+ emissiveMapEnabled: u32,
121
197
  emissiveFactor: vec3f, // #ifdef HAS_EMISSIVEMAP
122
198
 
123
199
  metallicRoughnessValues: vec2f,
124
- metallicRoughnessMapEnabled: uint32,
200
+ metallicRoughnessMapEnabled: u32,
125
201
 
126
202
  occlusionMapEnabled: i32,
127
203
  occlusionStrength: f32, // #ifdef HAS_OCCLUSIONMAP
128
204
 
129
205
  alphaCutoffEnabled: i32,
130
206
  alphaCutoff: f32, // #ifdef ALPHA_CUTOFF
207
+
208
+ specularColorFactor: vec3f,
209
+ specularIntensityFactor: f32,
210
+ specularColorMapEnabled: i32,
211
+ specularIntensityMapEnabled: i32,
212
+
213
+ ior: f32,
214
+
215
+ transmissionFactor: f32,
216
+ transmissionMapEnabled: i32,
217
+
218
+ thicknessFactor: f32,
219
+ attenuationDistance: f32,
220
+ attenuationColor: vec3f,
221
+
222
+ clearcoatFactor: f32,
223
+ clearcoatRoughnessFactor: f32,
224
+ clearcoatMapEnabled: i32,
225
+ clearcoatRoughnessMapEnabled: i32,
226
+
227
+ sheenColorFactor: vec3f,
228
+ sheenRoughnessFactor: f32,
229
+ sheenColorMapEnabled: i32,
230
+ sheenRoughnessMapEnabled: i32,
231
+
232
+ iridescenceFactor: f32,
233
+ iridescenceIor: f32,
234
+ iridescenceThicknessRange: vec2f,
235
+ iridescenceMapEnabled: i32,
236
+
237
+ anisotropyStrength: f32,
238
+ anisotropyRotation: f32,
239
+ anisotropyDirection: vec2f,
240
+ anisotropyMapEnabled: i32,
241
+
242
+ emissiveStrength: f32,
131
243
 
132
244
  // IBL
133
245
  IBLenabled: i32,
@@ -136,34 +248,81 @@ struct pbrMaterialUniforms {
136
248
  // debugging flags used for shader output of intermediate PBR variables
137
249
  // #ifdef PBR_DEBUG
138
250
  scaleDiffBaseMR: vec4f,
139
- scaleFGDSpec: vec4f
251
+ scaleFGDSpec: vec4f,
140
252
  // #endif
141
- }
142
-
143
- @binding(2) @group(0) var<uniform> material : pbrMaterialUniforms;
253
+ }
254
+
255
+ @group(3) @binding(auto) var<uniform> pbrMaterial : pbrMaterialUniforms;
144
256
 
145
257
  // Samplers
146
258
  #ifdef HAS_BASECOLORMAP
147
- uniform sampler2D pbr_baseColorSampler;
259
+ @group(3) @binding(auto) var pbr_baseColorSampler: texture_2d<f32>;
260
+ @group(3) @binding(auto) var pbr_baseColorSamplerSampler: sampler;
148
261
  #endif
149
262
  #ifdef HAS_NORMALMAP
150
- uniform sampler2D pbr_normalSampler;
263
+ @group(3) @binding(auto) var pbr_normalSampler: texture_2d<f32>;
264
+ @group(3) @binding(auto) var pbr_normalSamplerSampler: sampler;
151
265
  #endif
152
266
  #ifdef HAS_EMISSIVEMAP
153
- uniform sampler2D pbr_emissiveSampler;
267
+ @group(3) @binding(auto) var pbr_emissiveSampler: texture_2d<f32>;
268
+ @group(3) @binding(auto) var pbr_emissiveSamplerSampler: sampler;
154
269
  #endif
155
270
  #ifdef HAS_METALROUGHNESSMAP
156
- uniform sampler2D pbr_metallicRoughnessSampler;
271
+ @group(3) @binding(auto) var pbr_metallicRoughnessSampler: texture_2d<f32>;
272
+ @group(3) @binding(auto) var pbr_metallicRoughnessSamplerSampler: sampler;
157
273
  #endif
158
274
  #ifdef HAS_OCCLUSIONMAP
159
- uniform sampler2D pbr_occlusionSampler;
275
+ @group(3) @binding(auto) var pbr_occlusionSampler: texture_2d<f32>;
276
+ @group(3) @binding(auto) var pbr_occlusionSamplerSampler: sampler;
160
277
  #endif
161
- #ifdef USE_IBL
162
- uniform samplerCube pbr_diffuseEnvSampler;
163
- uniform samplerCube pbr_specularEnvSampler;
164
- uniform sampler2D pbr_brdfLUT;
278
+ #ifdef HAS_SPECULARCOLORMAP
279
+ @group(3) @binding(auto) var pbr_specularColorSampler: texture_2d<f32>;
280
+ @group(3) @binding(auto) var pbr_specularColorSamplerSampler: sampler;
281
+ #endif
282
+ #ifdef HAS_SPECULARINTENSITYMAP
283
+ @group(3) @binding(auto) var pbr_specularIntensitySampler: texture_2d<f32>;
284
+ @group(3) @binding(auto) var pbr_specularIntensitySamplerSampler: sampler;
285
+ #endif
286
+ #ifdef HAS_TRANSMISSIONMAP
287
+ @group(3) @binding(auto) var pbr_transmissionSampler: texture_2d<f32>;
288
+ @group(3) @binding(auto) var pbr_transmissionSamplerSampler: sampler;
289
+ #endif
290
+ #ifdef HAS_THICKNESSMAP
291
+ @group(3) @binding(auto) var pbr_thicknessSampler: texture_2d<f32>;
292
+ @group(3) @binding(auto) var pbr_thicknessSamplerSampler: sampler;
293
+ #endif
294
+ #ifdef HAS_CLEARCOATMAP
295
+ @group(3) @binding(auto) var pbr_clearcoatSampler: texture_2d<f32>;
296
+ @group(3) @binding(auto) var pbr_clearcoatSamplerSampler: sampler;
297
+ #endif
298
+ #ifdef HAS_CLEARCOATROUGHNESSMAP
299
+ @group(3) @binding(auto) var pbr_clearcoatRoughnessSampler: texture_2d<f32>;
300
+ @group(3) @binding(auto) var pbr_clearcoatRoughnessSamplerSampler: sampler;
301
+ #endif
302
+ #ifdef HAS_CLEARCOATNORMALMAP
303
+ @group(3) @binding(auto) var pbr_clearcoatNormalSampler: texture_2d<f32>;
304
+ @group(3) @binding(auto) var pbr_clearcoatNormalSamplerSampler: sampler;
305
+ #endif
306
+ #ifdef HAS_SHEENCOLORMAP
307
+ @group(3) @binding(auto) var pbr_sheenColorSampler: texture_2d<f32>;
308
+ @group(3) @binding(auto) var pbr_sheenColorSamplerSampler: sampler;
309
+ #endif
310
+ #ifdef HAS_SHEENROUGHNESSMAP
311
+ @group(3) @binding(auto) var pbr_sheenRoughnessSampler: texture_2d<f32>;
312
+ @group(3) @binding(auto) var pbr_sheenRoughnessSamplerSampler: sampler;
313
+ #endif
314
+ #ifdef HAS_IRIDESCENCEMAP
315
+ @group(3) @binding(auto) var pbr_iridescenceSampler: texture_2d<f32>;
316
+ @group(3) @binding(auto) var pbr_iridescenceSamplerSampler: sampler;
317
+ #endif
318
+ #ifdef HAS_IRIDESCENCETHICKNESSMAP
319
+ @group(3) @binding(auto) var pbr_iridescenceThicknessSampler: texture_2d<f32>;
320
+ @group(3) @binding(auto) var pbr_iridescenceThicknessSamplerSampler: sampler;
321
+ #endif
322
+ #ifdef HAS_ANISOTROPYMAP
323
+ @group(3) @binding(auto) var pbr_anisotropySampler: texture_2d<f32>;
324
+ @group(3) @binding(auto) var pbr_anisotropySamplerSampler: sampler;
165
325
  #endif
166
-
167
326
  // Encapsulate the various inputs used by the various functions in the shading equation
168
327
  // We store values in this struct to simplify the integration of alternative implementations
169
328
  // of the shading terms, outlined in the Readme.MD Appendix.
@@ -189,80 +348,130 @@ const c_MinRoughness = 0.04;
189
348
 
190
349
  fn SRGBtoLINEAR(srgbIn: vec4f ) -> vec4f
191
350
  {
351
+ var linOut: vec3f = srgbIn.xyz;
192
352
  #ifdef MANUAL_SRGB
353
+ let bLess: vec3f = step(vec3f(0.04045), srgbIn.xyz);
354
+ linOut = mix(
355
+ srgbIn.xyz / vec3f(12.92),
356
+ pow((srgbIn.xyz + vec3f(0.055)) / vec3f(1.055), vec3f(2.4)),
357
+ bLess
358
+ );
193
359
  #ifdef SRGB_FAST_APPROXIMATION
194
- var linOut: vec3f = pow(srgbIn.xyz,vec3(2.2));
195
- #else // SRGB_FAST_APPROXIMATION
196
- var bLess: vec3f = step(vec3(0.04045),srgbIn.xyz);
197
- var linOut: vec3f = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess );
198
- #endif //SRGB_FAST_APPROXIMATION
199
- return vec4f(linOut,srgbIn.w);;
200
- #else //MANUAL_SRGB
201
- return srgbIn;
202
- #endif //MANUAL_SRGB
360
+ linOut = pow(srgbIn.xyz, vec3f(2.2));
361
+ #endif
362
+ #endif
363
+ return vec4f(linOut, srgbIn.w);
203
364
  }
204
365
 
205
- // Find the normal for this fragment, pulling either from a predefined normal map
206
- // or from the interpolated mesh normal and tangent attributes.
207
- fn getNormal() -> vec3f
366
+ // Build the tangent basis from interpolated attributes or screen-space derivatives.
367
+ fn getTBN() -> mat3x3f
208
368
  {
209
- // Retrieve the tangent space matrix
210
- #ifndef HAS_TANGENTS
211
- var pos_dx: vec3f = dFdx(pbr_vPosition);
212
- var pos_dy: vec3f = dFdy(pbr_vPosition);
213
- var tex_dx: vec3f = dFdx(vec3(pbr_vUV, 0.0));
214
- var tex_dy: vec3f = dFdy(vec3(pbr_vUV, 0.0));
215
- var t: vec3f = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);
369
+ let pos_dx: vec3f = dpdx(fragmentInputs.pbr_vPosition);
370
+ let pos_dy: vec3f = dpdy(fragmentInputs.pbr_vPosition);
371
+ let tex_dx: vec3f = dpdx(vec3f(fragmentInputs.pbr_vUV, 0.0));
372
+ let tex_dy: vec3f = dpdy(vec3f(fragmentInputs.pbr_vUV, 0.0));
373
+ var t: vec3f = (tex_dy.y * pos_dx - tex_dx.y * pos_dy) / (tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y);
216
374
 
217
- #ifdef HAS_NORMALS
218
- var ng: vec3f = normalize(pbr_vNormal);
219
- #else
220
375
  var ng: vec3f = cross(pos_dx, pos_dy);
376
+ #ifdef HAS_NORMALS
377
+ ng = normalize(fragmentInputs.pbr_vNormal);
221
378
  #endif
222
-
223
379
  t = normalize(t - ng * dot(ng, t));
224
380
  var b: vec3f = normalize(cross(ng, t));
225
- var tbn: mat3f = mat3f(t, b, ng);
226
- #else // HAS_TANGENTS
227
- var tbn: mat3f = pbr_vTBN;
381
+ var tbn: mat3x3f = mat3x3f(t, b, ng);
382
+ #ifdef HAS_TANGENTS
383
+ tbn = fragmentInputs.pbr_vTBN;
228
384
  #endif
229
385
 
230
- #ifdef HAS_NORMALMAP
231
- vec3 n = texture(pbr_normalSampler, pbr_vUV).rgb;
232
- n = normalize(tbn * ((2.0 * n - 1.0) * vec3(pbrMaterial.normalScale, pbrMaterial.normalScale, 1.0)));
233
- #else
386
+ return tbn;
387
+ }
388
+
389
+ // Find the normal for this fragment, pulling either from a predefined normal map
390
+ // or from the interpolated mesh normal and tangent attributes.
391
+ fn getMappedNormal(
392
+ normalSampler: texture_2d<f32>,
393
+ normalSamplerBinding: sampler,
394
+ tbn: mat3x3f,
395
+ normalScale: f32
396
+ ) -> vec3f
397
+ {
398
+ let n = textureSample(normalSampler, normalSamplerBinding, fragmentInputs.pbr_vUV).rgb;
399
+ return normalize(tbn * ((2.0 * n - 1.0) * vec3f(normalScale, normalScale, 1.0)));
400
+ }
401
+
402
+ fn getNormal(tbn: mat3x3f) -> vec3f
403
+ {
234
404
  // The tbn matrix is linearly interpolated, so we need to re-normalize
235
- vec3 n = normalize(tbn[2].xyz);
405
+ var n: vec3f = normalize(tbn[2].xyz);
406
+ #ifdef HAS_NORMALMAP
407
+ n = getMappedNormal(
408
+ pbr_normalSampler,
409
+ pbr_normalSamplerSampler,
410
+ tbn,
411
+ pbrMaterial.normalScale
412
+ );
236
413
  #endif
237
414
 
238
415
  return n;
239
416
  }
240
417
 
418
+ fn getClearcoatNormal(tbn: mat3x3f, baseNormal: vec3f) -> vec3f
419
+ {
420
+ #ifdef HAS_CLEARCOATNORMALMAP
421
+ return getMappedNormal(
422
+ pbr_clearcoatNormalSampler,
423
+ pbr_clearcoatNormalSamplerSampler,
424
+ tbn,
425
+ 1.0
426
+ );
427
+ #else
428
+ return baseNormal;
429
+ #endif
430
+ }
431
+
241
432
  // Calculation of the lighting contribution from an optional Image Based Light source.
242
433
  // Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
243
434
  // See our README.md on Environment Maps [3] for additional discussion.
244
435
  #ifdef USE_IBL
245
- fn getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection) -> vec3f
436
+ fn getIBLContribution(pbrInfo: PBRInfo, n: vec3f, reflection: vec3f) -> vec3f
246
437
  {
247
- float mipCount = 9.0; // resolution of 512x512
248
- float lod = (pbrInfo.perceptualRoughness * mipCount);
438
+ let mipCount: f32 = 9.0; // resolution of 512x512
439
+ let lod: f32 = pbrInfo.perceptualRoughness * mipCount;
249
440
  // retrieve a scale and bias to F0. See [1], Figure 3
250
- vec3 brdf = SRGBtoLINEAR(texture(pbr_brdfLUT,
251
- vec2(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness))).rgb;
252
- vec3 diffuseLight = SRGBtoLINEAR(texture(pbr_diffuseEnvSampler, n)).rgb;
253
-
441
+ let brdf = SRGBtoLINEAR(
442
+ textureSampleLevel(
443
+ pbr_brdfLUT,
444
+ pbr_brdfLUTSampler,
445
+ vec2f(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness),
446
+ 0.0
447
+ )
448
+ ).rgb;
449
+ let diffuseLight =
450
+ SRGBtoLINEAR(
451
+ textureSampleLevel(pbr_diffuseEnvSampler, pbr_diffuseEnvSamplerSampler, n, 0.0)
452
+ ).rgb;
453
+ var specularLight = SRGBtoLINEAR(
454
+ textureSampleLevel(
455
+ pbr_specularEnvSampler,
456
+ pbr_specularEnvSamplerSampler,
457
+ reflection,
458
+ 0.0
459
+ )
460
+ ).rgb;
254
461
  #ifdef USE_TEX_LOD
255
- vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection, lod)).rgb;
256
- #else
257
- vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection)).rgb;
462
+ specularLight = SRGBtoLINEAR(
463
+ textureSampleLevel(
464
+ pbr_specularEnvSampler,
465
+ pbr_specularEnvSamplerSampler,
466
+ reflection,
467
+ lod
468
+ )
469
+ ).rgb;
258
470
  #endif
259
471
 
260
- vec3 diffuse = diffuseLight * pbrInfo.diffuseColor;
261
- vec3 specular = specularLight * (pbrInfo.specularColor * brdf.x + brdf.y);
262
-
263
- // For presentation, this allows us to disable IBL terms
264
- diffuse *= pbrMaterial.scaleIBLAmbient.x;
265
- specular *= pbrMaterial.scaleIBLAmbient.y;
472
+ let diffuse = diffuseLight * pbrInfo.diffuseColor * pbrMaterial.scaleIBLAmbient.x;
473
+ let specular =
474
+ specularLight * (pbrInfo.specularColor * brdf.x + brdf.y) * pbrMaterial.scaleIBLAmbient.y;
266
475
 
267
476
  return diffuse + specular;
268
477
  }
@@ -272,7 +481,7 @@ fn getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection) -> vec3f
272
481
  // Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog
273
482
  // See also [1], Equation 1
274
483
  fn diffuse(pbrInfo: PBRInfo) -> vec3<f32> {
275
- return pbrInfo.diffuseColor / PI;
484
+ return pbrInfo.diffuseColor / M_PI;
276
485
  }
277
486
 
278
487
  // The following equation models the Fresnel reflectance term of the spec equation (aka F())
@@ -306,7 +515,173 @@ fn geometricOcclusion(pbrInfo: PBRInfo) -> f32 {
306
515
  fn microfacetDistribution(pbrInfo: PBRInfo) -> f32 {
307
516
  let roughnessSq = pbrInfo.alphaRoughness * pbrInfo.alphaRoughness;
308
517
  let f = (pbrInfo.NdotH * roughnessSq - pbrInfo.NdotH) * pbrInfo.NdotH + 1.0;
309
- return roughnessSq / (PI * f * f);
518
+ return roughnessSq / (M_PI * f * f);
519
+ }
520
+
521
+ fn maxComponent(value: vec3f) -> f32 {
522
+ return max(max(value.r, value.g), value.b);
523
+ }
524
+
525
+ fn getDielectricF0(ior: f32) -> f32 {
526
+ let clampedIor = max(ior, 1.0);
527
+ let ratio = (clampedIor - 1.0) / (clampedIor + 1.0);
528
+ return ratio * ratio;
529
+ }
530
+
531
+ fn normalizeDirection(direction: vec2f) -> vec2f {
532
+ let directionLength = length(direction);
533
+ if (directionLength > 0.0001) {
534
+ return direction / directionLength;
535
+ }
536
+
537
+ return vec2f(1.0, 0.0);
538
+ }
539
+
540
+ fn rotateDirection(direction: vec2f, rotation: f32) -> vec2f {
541
+ let s = sin(rotation);
542
+ let c = cos(rotation);
543
+ return vec2f(direction.x * c - direction.y * s, direction.x * s + direction.y * c);
544
+ }
545
+
546
+ fn getIridescenceTint(iridescence: f32, thickness: f32, NdotV: f32) -> vec3f {
547
+ if (iridescence <= 0.0) {
548
+ return vec3f(1.0);
549
+ }
550
+
551
+ let phase = 0.015 * thickness * pbrMaterial.iridescenceIor + (1.0 - NdotV) * 6.0;
552
+ let thinFilmTint =
553
+ 0.5 +
554
+ 0.5 *
555
+ cos(vec3f(phase, phase + 2.0943951, phase + 4.1887902));
556
+ return mix(vec3f(1.0), thinFilmTint, iridescence);
557
+ }
558
+
559
+ fn getVolumeAttenuation(thickness: f32) -> vec3f {
560
+ if (thickness <= 0.0) {
561
+ return vec3f(1.0);
562
+ }
563
+
564
+ let attenuationCoefficient =
565
+ -log(max(pbrMaterial.attenuationColor, vec3f(0.0001))) /
566
+ max(pbrMaterial.attenuationDistance, 0.0001);
567
+ return exp(-attenuationCoefficient * thickness);
568
+ }
569
+
570
+ fn createClearcoatPBRInfo(
571
+ basePBRInfo: PBRInfo,
572
+ clearcoatNormal: vec3f,
573
+ clearcoatRoughness: f32
574
+ ) -> PBRInfo {
575
+ let perceptualRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);
576
+ let alphaRoughness = perceptualRoughness * perceptualRoughness;
577
+ let NdotV = clamp(abs(dot(clearcoatNormal, basePBRInfo.v)), 0.001, 1.0);
578
+
579
+ return PBRInfo(
580
+ basePBRInfo.NdotL,
581
+ NdotV,
582
+ basePBRInfo.NdotH,
583
+ basePBRInfo.LdotH,
584
+ basePBRInfo.VdotH,
585
+ perceptualRoughness,
586
+ 0.0,
587
+ vec3f(0.04),
588
+ vec3f(1.0),
589
+ alphaRoughness,
590
+ vec3f(0.0),
591
+ vec3f(0.04),
592
+ clearcoatNormal,
593
+ basePBRInfo.v
594
+ );
595
+ }
596
+
597
+ fn calculateClearcoatContribution(
598
+ pbrInfo: PBRInfo,
599
+ lightColor: vec3f,
600
+ clearcoatNormal: vec3f,
601
+ clearcoatFactor: f32,
602
+ clearcoatRoughness: f32
603
+ ) -> vec3f {
604
+ if (clearcoatFactor <= 0.0) {
605
+ return vec3f(0.0);
606
+ }
607
+
608
+ let clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);
609
+ return calculateFinalColor(clearcoatPBRInfo, lightColor) * clearcoatFactor;
610
+ }
611
+
612
+ #ifdef USE_IBL
613
+ fn calculateClearcoatIBLContribution(
614
+ pbrInfo: PBRInfo,
615
+ clearcoatNormal: vec3f,
616
+ reflection: vec3f,
617
+ clearcoatFactor: f32,
618
+ clearcoatRoughness: f32
619
+ ) -> vec3f {
620
+ if (clearcoatFactor <= 0.0) {
621
+ return vec3f(0.0);
622
+ }
623
+
624
+ let clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);
625
+ return getIBLContribution(clearcoatPBRInfo, clearcoatNormal, reflection) * clearcoatFactor;
626
+ }
627
+ #endif
628
+
629
+ fn calculateSheenContribution(
630
+ pbrInfo: PBRInfo,
631
+ lightColor: vec3f,
632
+ sheenColor: vec3f,
633
+ sheenRoughness: f32
634
+ ) -> vec3f {
635
+ if (maxComponent(sheenColor) <= 0.0) {
636
+ return vec3f(0.0);
637
+ }
638
+
639
+ let sheenFresnel = pow(clamp(1.0 - pbrInfo.VdotH, 0.0, 1.0), 5.0);
640
+ let sheenVisibility = mix(1.0, pbrInfo.NdotL * pbrInfo.NdotV, sheenRoughness);
641
+ return pbrInfo.NdotL *
642
+ lightColor *
643
+ sheenColor *
644
+ (0.25 + 0.75 * sheenFresnel) *
645
+ sheenVisibility *
646
+ (1.0 - pbrInfo.metalness);
647
+ }
648
+
649
+ fn calculateAnisotropyBoost(
650
+ pbrInfo: PBRInfo,
651
+ anisotropyTangent: vec3f,
652
+ anisotropyStrength: f32
653
+ ) -> f32 {
654
+ if (anisotropyStrength <= 0.0) {
655
+ return 1.0;
656
+ }
657
+
658
+ let anisotropyBitangent = normalize(cross(pbrInfo.n, anisotropyTangent));
659
+ let bitangentViewAlignment = abs(dot(pbrInfo.v, anisotropyBitangent));
660
+ return mix(1.0, 0.65 + 0.7 * bitangentViewAlignment, anisotropyStrength);
661
+ }
662
+
663
+ fn calculateMaterialLightColor(
664
+ pbrInfo: PBRInfo,
665
+ lightColor: vec3f,
666
+ clearcoatNormal: vec3f,
667
+ clearcoatFactor: f32,
668
+ clearcoatRoughness: f32,
669
+ sheenColor: vec3f,
670
+ sheenRoughness: f32,
671
+ anisotropyTangent: vec3f,
672
+ anisotropyStrength: f32
673
+ ) -> vec3f {
674
+ let anisotropyBoost = calculateAnisotropyBoost(pbrInfo, anisotropyTangent, anisotropyStrength);
675
+ var color = calculateFinalColor(pbrInfo, lightColor) * anisotropyBoost;
676
+ color += calculateClearcoatContribution(
677
+ pbrInfo,
678
+ lightColor,
679
+ clearcoatNormal,
680
+ clearcoatFactor,
681
+ clearcoatRoughness
682
+ );
683
+ color += calculateSheenContribution(pbrInfo, lightColor, sheenColor, sheenRoughness);
684
+ return color;
310
685
  }
311
686
 
312
687
  fn PBRInfo_setAmbientLight(pbrInfo: ptr<function, PBRInfo>) {
@@ -329,7 +704,12 @@ fn PBRInfo_setDirectionalLight(pbrInfo: ptr<function, PBRInfo>, lightDirection:
329
704
  }
330
705
 
331
706
  fn PBRInfo_setPointLight(pbrInfo: ptr<function, PBRInfo>, pointLight: PointLight) {
332
- let light_direction = normalize(pointLight.position - pbr_vPosition);
707
+ let light_direction = normalize(pointLight.position - fragmentInputs.pbr_vPosition);
708
+ PBRInfo_setDirectionalLight(pbrInfo, light_direction);
709
+ }
710
+
711
+ fn PBRInfo_setSpotLight(pbrInfo: ptr<function, PBRInfo>, spotLight: SpotLight) {
712
+ let light_direction = normalize(spotLight.position - fragmentInputs.pbr_vPosition);
333
713
  PBRInfo_setDirectionalLight(pbrInfo, light_direction);
334
714
  }
335
715
 
@@ -348,11 +728,11 @@ fn calculateFinalColor(pbrInfo: PBRInfo, lightColor: vec3<f32>) -> vec3<f32> {
348
728
 
349
729
  fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
350
730
  // The albedo may be defined from a base texture or a flat color
351
- var baseColor: vec4<f32>;
731
+ var baseColor: vec4<f32> = pbrMaterial.baseColorFactor;
352
732
  #ifdef HAS_BASECOLORMAP
353
- baseColor = SRGBtoLINEAR(textureSample(pbr_baseColorSampler, pbr_baseColorSampler, pbr_vUV)) * pbrMaterial.baseColorFactor;
354
- #else
355
- baseColor = pbrMaterial.baseColorFactor;
733
+ baseColor = SRGBtoLINEAR(
734
+ textureSample(pbr_baseColorSampler, pbr_baseColorSamplerSampler, fragmentInputs.pbr_vUV)
735
+ ) * pbrMaterial.baseColorFactor;
356
736
  #endif
357
737
 
358
738
  #ifdef ALPHA_CUTOFF
@@ -362,8 +742,9 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
362
742
  #endif
363
743
 
364
744
  var color = vec3<f32>(0.0, 0.0, 0.0);
745
+ var transmission = 0.0;
365
746
 
366
- if (pbrMaterial.unlit) {
747
+ if (pbrMaterial.unlit != 0u) {
367
748
  color = baseColor.rgb;
368
749
  } else {
369
750
  // Metallic and Roughness material properties are packed together
@@ -374,20 +755,318 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
374
755
  #ifdef HAS_METALROUGHNESSMAP
375
756
  // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
376
757
  // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
377
- let mrSample = textureSample(pbr_metallicRoughnessSampler, pbr_metallicRoughnessSampler, pbr_vUV);
758
+ let mrSample = textureSample(
759
+ pbr_metallicRoughnessSampler,
760
+ pbr_metallicRoughnessSamplerSampler,
761
+ fragmentInputs.pbr_vUV
762
+ );
378
763
  perceptualRoughness = mrSample.g * perceptualRoughness;
379
764
  metallic = mrSample.b * metallic;
380
765
  #endif
381
766
  perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
382
767
  metallic = clamp(metallic, 0.0, 1.0);
768
+ let tbn = getTBN();
769
+ let n = getNormal(tbn); // normal at surface point
770
+ let v = normalize(pbrProjection.camera - fragmentInputs.pbr_vPosition); // Vector from surface point to camera
771
+ let NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
772
+ var useExtendedPBR = false;
773
+ #ifdef USE_MATERIAL_EXTENSIONS
774
+ useExtendedPBR =
775
+ pbrMaterial.specularColorMapEnabled != 0 ||
776
+ pbrMaterial.specularIntensityMapEnabled != 0 ||
777
+ abs(pbrMaterial.specularIntensityFactor - 1.0) > 0.0001 ||
778
+ maxComponent(abs(pbrMaterial.specularColorFactor - vec3f(1.0))) > 0.0001 ||
779
+ abs(pbrMaterial.ior - 1.5) > 0.0001 ||
780
+ pbrMaterial.transmissionMapEnabled != 0 ||
781
+ pbrMaterial.transmissionFactor > 0.0001 ||
782
+ pbrMaterial.clearcoatMapEnabled != 0 ||
783
+ pbrMaterial.clearcoatRoughnessMapEnabled != 0 ||
784
+ pbrMaterial.clearcoatFactor > 0.0001 ||
785
+ pbrMaterial.clearcoatRoughnessFactor > 0.0001 ||
786
+ pbrMaterial.sheenColorMapEnabled != 0 ||
787
+ pbrMaterial.sheenRoughnessMapEnabled != 0 ||
788
+ maxComponent(pbrMaterial.sheenColorFactor) > 0.0001 ||
789
+ pbrMaterial.sheenRoughnessFactor > 0.0001 ||
790
+ pbrMaterial.iridescenceMapEnabled != 0 ||
791
+ pbrMaterial.iridescenceFactor > 0.0001 ||
792
+ abs(pbrMaterial.iridescenceIor - 1.3) > 0.0001 ||
793
+ abs(pbrMaterial.iridescenceThicknessRange.x - 100.0) > 0.0001 ||
794
+ abs(pbrMaterial.iridescenceThicknessRange.y - 400.0) > 0.0001 ||
795
+ pbrMaterial.anisotropyMapEnabled != 0 ||
796
+ pbrMaterial.anisotropyStrength > 0.0001 ||
797
+ abs(pbrMaterial.anisotropyRotation) > 0.0001 ||
798
+ length(pbrMaterial.anisotropyDirection - vec2f(1.0, 0.0)) > 0.0001;
799
+ #endif
800
+
801
+ if (!useExtendedPBR) {
802
+ let alphaRoughness = perceptualRoughness * perceptualRoughness;
803
+
804
+ let f0 = vec3<f32>(0.04);
805
+ var diffuseColor = baseColor.rgb * (vec3<f32>(1.0) - f0);
806
+ diffuseColor *= 1.0 - metallic;
807
+ let specularColor = mix(f0, baseColor.rgb, metallic);
808
+
809
+ let reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
810
+ let reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
811
+ let specularEnvironmentR0 = specularColor;
812
+ let specularEnvironmentR90 = vec3<f32>(1.0, 1.0, 1.0) * reflectance90;
813
+ let reflection = -normalize(reflect(v, n));
814
+
815
+ var pbrInfo = PBRInfo(
816
+ 0.0, // NdotL
817
+ NdotV,
818
+ 0.0, // NdotH
819
+ 0.0, // LdotH
820
+ 0.0, // VdotH
821
+ perceptualRoughness,
822
+ metallic,
823
+ specularEnvironmentR0,
824
+ specularEnvironmentR90,
825
+ alphaRoughness,
826
+ diffuseColor,
827
+ specularColor,
828
+ n,
829
+ v
830
+ );
831
+
832
+ #ifdef USE_LIGHTS
833
+ PBRInfo_setAmbientLight(&pbrInfo);
834
+ color += calculateFinalColor(pbrInfo, lighting.ambientColor);
835
+
836
+ for (var i = 0; i < lighting.directionalLightCount; i++) {
837
+ if (i < lighting.directionalLightCount) {
838
+ PBRInfo_setDirectionalLight(&pbrInfo, lighting_getDirectionalLight(i).direction);
839
+ color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color);
840
+ }
841
+ }
842
+
843
+ for (var i = 0; i < lighting.pointLightCount; i++) {
844
+ if (i < lighting.pointLightCount) {
845
+ PBRInfo_setPointLight(&pbrInfo, lighting_getPointLight(i));
846
+ let attenuation = getPointLightAttenuation(
847
+ lighting_getPointLight(i),
848
+ distance(lighting_getPointLight(i).position, fragmentInputs.pbr_vPosition)
849
+ );
850
+ color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation);
851
+ }
852
+ }
853
+
854
+ for (var i = 0; i < lighting.spotLightCount; i++) {
855
+ if (i < lighting.spotLightCount) {
856
+ PBRInfo_setSpotLight(&pbrInfo, lighting_getSpotLight(i));
857
+ let attenuation = getSpotLightAttenuation(
858
+ lighting_getSpotLight(i),
859
+ fragmentInputs.pbr_vPosition
860
+ );
861
+ color += calculateFinalColor(pbrInfo, lighting_getSpotLight(i).color / attenuation);
862
+ }
863
+ }
864
+ #endif
865
+
866
+ #ifdef USE_IBL
867
+ if (pbrMaterial.IBLenabled != 0) {
868
+ color += getIBLContribution(pbrInfo, n, reflection);
869
+ }
870
+ #endif
871
+
872
+ #ifdef HAS_OCCLUSIONMAP
873
+ if (pbrMaterial.occlusionMapEnabled != 0) {
874
+ let ao =
875
+ textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, fragmentInputs.pbr_vUV).r;
876
+ color = mix(color, color * ao, pbrMaterial.occlusionStrength);
877
+ }
878
+ #endif
879
+
880
+ var emissive = pbrMaterial.emissiveFactor;
881
+ #ifdef HAS_EMISSIVEMAP
882
+ if (pbrMaterial.emissiveMapEnabled != 0u) {
883
+ emissive *= SRGBtoLINEAR(
884
+ textureSample(pbr_emissiveSampler, pbr_emissiveSamplerSampler, fragmentInputs.pbr_vUV)
885
+ ).rgb;
886
+ }
887
+ #endif
888
+ color += emissive * pbrMaterial.emissiveStrength;
889
+
890
+ #ifdef PBR_DEBUG
891
+ color = mix(color, baseColor.rgb, pbrMaterial.scaleDiffBaseMR.y);
892
+ color = mix(color, vec3<f32>(metallic), pbrMaterial.scaleDiffBaseMR.z);
893
+ color = mix(color, vec3<f32>(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w);
894
+ #endif
895
+
896
+ return vec4<f32>(pow(color, vec3<f32>(1.0 / 2.2)), baseColor.a);
897
+ }
898
+
899
+ var specularIntensity = pbrMaterial.specularIntensityFactor;
900
+ #ifdef HAS_SPECULARINTENSITYMAP
901
+ if (pbrMaterial.specularIntensityMapEnabled != 0) {
902
+ specularIntensity *= textureSample(
903
+ pbr_specularIntensitySampler,
904
+ pbr_specularIntensitySamplerSampler,
905
+ fragmentInputs.pbr_vUV
906
+ ).a;
907
+ }
908
+ #endif
909
+
910
+ var specularFactor = pbrMaterial.specularColorFactor;
911
+ #ifdef HAS_SPECULARCOLORMAP
912
+ if (pbrMaterial.specularColorMapEnabled != 0) {
913
+ specularFactor *= SRGBtoLINEAR(
914
+ textureSample(
915
+ pbr_specularColorSampler,
916
+ pbr_specularColorSamplerSampler,
917
+ fragmentInputs.pbr_vUV
918
+ )
919
+ ).rgb;
920
+ }
921
+ #endif
922
+
923
+ transmission = pbrMaterial.transmissionFactor;
924
+ #ifdef HAS_TRANSMISSIONMAP
925
+ if (pbrMaterial.transmissionMapEnabled != 0) {
926
+ transmission *= textureSample(
927
+ pbr_transmissionSampler,
928
+ pbr_transmissionSamplerSampler,
929
+ fragmentInputs.pbr_vUV
930
+ ).r;
931
+ }
932
+ #endif
933
+ transmission = clamp(transmission * (1.0 - metallic), 0.0, 1.0);
934
+ var thickness = max(pbrMaterial.thicknessFactor, 0.0);
935
+ #ifdef HAS_THICKNESSMAP
936
+ thickness *= textureSample(
937
+ pbr_thicknessSampler,
938
+ pbr_thicknessSamplerSampler,
939
+ fragmentInputs.pbr_vUV
940
+ ).g;
941
+ #endif
942
+
943
+ var clearcoatFactor = pbrMaterial.clearcoatFactor;
944
+ var clearcoatRoughness = pbrMaterial.clearcoatRoughnessFactor;
945
+ #ifdef HAS_CLEARCOATMAP
946
+ if (pbrMaterial.clearcoatMapEnabled != 0) {
947
+ clearcoatFactor *= textureSample(
948
+ pbr_clearcoatSampler,
949
+ pbr_clearcoatSamplerSampler,
950
+ fragmentInputs.pbr_vUV
951
+ ).r;
952
+ }
953
+ #endif
954
+ #ifdef HAS_CLEARCOATROUGHNESSMAP
955
+ if (pbrMaterial.clearcoatRoughnessMapEnabled != 0) {
956
+ clearcoatRoughness *= textureSample(
957
+ pbr_clearcoatRoughnessSampler,
958
+ pbr_clearcoatRoughnessSamplerSampler,
959
+ fragmentInputs.pbr_vUV
960
+ ).g;
961
+ }
962
+ #endif
963
+ clearcoatFactor = clamp(clearcoatFactor, 0.0, 1.0);
964
+ clearcoatRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);
965
+ let clearcoatNormal = getClearcoatNormal(tbn, n);
966
+
967
+ var sheenColor = pbrMaterial.sheenColorFactor;
968
+ var sheenRoughness = pbrMaterial.sheenRoughnessFactor;
969
+ #ifdef HAS_SHEENCOLORMAP
970
+ if (pbrMaterial.sheenColorMapEnabled != 0) {
971
+ sheenColor *= SRGBtoLINEAR(
972
+ textureSample(
973
+ pbr_sheenColorSampler,
974
+ pbr_sheenColorSamplerSampler,
975
+ fragmentInputs.pbr_vUV
976
+ )
977
+ ).rgb;
978
+ }
979
+ #endif
980
+ #ifdef HAS_SHEENROUGHNESSMAP
981
+ if (pbrMaterial.sheenRoughnessMapEnabled != 0) {
982
+ sheenRoughness *= textureSample(
983
+ pbr_sheenRoughnessSampler,
984
+ pbr_sheenRoughnessSamplerSampler,
985
+ fragmentInputs.pbr_vUV
986
+ ).a;
987
+ }
988
+ #endif
989
+ sheenRoughness = clamp(sheenRoughness, c_MinRoughness, 1.0);
990
+
991
+ var iridescence = pbrMaterial.iridescenceFactor;
992
+ #ifdef HAS_IRIDESCENCEMAP
993
+ if (pbrMaterial.iridescenceMapEnabled != 0) {
994
+ iridescence *= textureSample(
995
+ pbr_iridescenceSampler,
996
+ pbr_iridescenceSamplerSampler,
997
+ fragmentInputs.pbr_vUV
998
+ ).r;
999
+ }
1000
+ #endif
1001
+ iridescence = clamp(iridescence, 0.0, 1.0);
1002
+ var iridescenceThickness = mix(
1003
+ pbrMaterial.iridescenceThicknessRange.x,
1004
+ pbrMaterial.iridescenceThicknessRange.y,
1005
+ 0.5
1006
+ );
1007
+ #ifdef HAS_IRIDESCENCETHICKNESSMAP
1008
+ iridescenceThickness = mix(
1009
+ pbrMaterial.iridescenceThicknessRange.x,
1010
+ pbrMaterial.iridescenceThicknessRange.y,
1011
+ textureSample(
1012
+ pbr_iridescenceThicknessSampler,
1013
+ pbr_iridescenceThicknessSamplerSampler,
1014
+ fragmentInputs.pbr_vUV
1015
+ ).g
1016
+ );
1017
+ #endif
1018
+
1019
+ var anisotropyStrength = clamp(pbrMaterial.anisotropyStrength, 0.0, 1.0);
1020
+ var anisotropyDirection = normalizeDirection(pbrMaterial.anisotropyDirection);
1021
+ #ifdef HAS_ANISOTROPYMAP
1022
+ if (pbrMaterial.anisotropyMapEnabled != 0) {
1023
+ let anisotropySample = textureSample(
1024
+ pbr_anisotropySampler,
1025
+ pbr_anisotropySamplerSampler,
1026
+ fragmentInputs.pbr_vUV
1027
+ ).rgb;
1028
+ anisotropyStrength *= anisotropySample.b;
1029
+ let mappedDirection = anisotropySample.rg * 2.0 - 1.0;
1030
+ if (length(mappedDirection) > 0.0001) {
1031
+ anisotropyDirection = normalize(mappedDirection);
1032
+ }
1033
+ }
1034
+ #endif
1035
+ anisotropyDirection = rotateDirection(anisotropyDirection, pbrMaterial.anisotropyRotation);
1036
+ var anisotropyTangent =
1037
+ normalize(tbn[0] * anisotropyDirection.x + tbn[1] * anisotropyDirection.y);
1038
+ if (length(anisotropyTangent) < 0.0001) {
1039
+ anisotropyTangent = normalize(tbn[0]);
1040
+ }
1041
+ let anisotropyViewAlignment = abs(dot(v, anisotropyTangent));
1042
+ perceptualRoughness = mix(
1043
+ perceptualRoughness,
1044
+ clamp(perceptualRoughness * (1.0 - 0.6 * anisotropyViewAlignment), c_MinRoughness, 1.0),
1045
+ anisotropyStrength
1046
+ );
1047
+
383
1048
  // Roughness is authored as perceptual roughness; as is convention,
384
1049
  // convert to material roughness by squaring the perceptual roughness [2].
385
1050
  let alphaRoughness = perceptualRoughness * perceptualRoughness;
386
1051
 
387
- let f0 = vec3<f32>(0.04);
388
- var diffuseColor = baseColor.rgb * (vec3<f32>(1.0) - f0);
389
- diffuseColor *= 1.0 - metallic;
390
- let specularColor = mix(f0, baseColor.rgb, metallic);
1052
+ let dielectricF0 = getDielectricF0(pbrMaterial.ior);
1053
+ var dielectricSpecularF0 = min(
1054
+ vec3f(dielectricF0) * specularFactor * specularIntensity,
1055
+ vec3f(1.0)
1056
+ );
1057
+ let iridescenceTint = getIridescenceTint(iridescence, iridescenceThickness, NdotV);
1058
+ dielectricSpecularF0 = mix(
1059
+ dielectricSpecularF0,
1060
+ dielectricSpecularF0 * iridescenceTint,
1061
+ iridescence
1062
+ );
1063
+ var diffuseColor = baseColor.rgb * (vec3f(1.0) - dielectricSpecularF0);
1064
+ diffuseColor *= (1.0 - metallic) * (1.0 - transmission);
1065
+ var specularColor = mix(dielectricSpecularF0, baseColor.rgb, metallic);
1066
+
1067
+ let baseLayerEnergy = 1.0 - clearcoatFactor * 0.25;
1068
+ diffuseColor *= baseLayerEnergy;
1069
+ specularColor *= baseLayerEnergy;
391
1070
 
392
1071
  // Compute reflectance.
393
1072
  let reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
@@ -399,11 +1078,6 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
399
1078
  let reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
400
1079
  let specularEnvironmentR0 = specularColor;
401
1080
  let specularEnvironmentR90 = vec3<f32>(1.0, 1.0, 1.0) * reflectance90;
402
-
403
- let n = getNormal(); // normal at surface point
404
- let v = normalize(pbrProjection.camera - pbr_vPosition); // Vector from surface point to camera
405
-
406
- let NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
407
1081
  let reflection = -normalize(reflect(v, n));
408
1082
 
409
1083
  var pbrInfo = PBRInfo(
@@ -426,13 +1100,33 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
426
1100
  #ifdef USE_LIGHTS
427
1101
  // Apply ambient light
428
1102
  PBRInfo_setAmbientLight(&pbrInfo);
429
- color += calculateFinalColor(pbrInfo, lighting.ambientColor);
1103
+ color += calculateMaterialLightColor(
1104
+ pbrInfo,
1105
+ lighting.ambientColor,
1106
+ clearcoatNormal,
1107
+ clearcoatFactor,
1108
+ clearcoatRoughness,
1109
+ sheenColor,
1110
+ sheenRoughness,
1111
+ anisotropyTangent,
1112
+ anisotropyStrength
1113
+ );
430
1114
 
431
1115
  // Apply directional light
432
1116
  for (var i = 0; i < lighting.directionalLightCount; i++) {
433
1117
  if (i < lighting.directionalLightCount) {
434
1118
  PBRInfo_setDirectionalLight(&pbrInfo, lighting_getDirectionalLight(i).direction);
435
- color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color);
1119
+ color += calculateMaterialLightColor(
1120
+ pbrInfo,
1121
+ lighting_getDirectionalLight(i).color,
1122
+ clearcoatNormal,
1123
+ clearcoatFactor,
1124
+ clearcoatRoughness,
1125
+ sheenColor,
1126
+ sheenRoughness,
1127
+ anisotropyTangent,
1128
+ anisotropyStrength
1129
+ );
436
1130
  }
437
1131
  }
438
1132
 
@@ -440,33 +1134,81 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
440
1134
  for (var i = 0; i < lighting.pointLightCount; i++) {
441
1135
  if (i < lighting.pointLightCount) {
442
1136
  PBRInfo_setPointLight(&pbrInfo, lighting_getPointLight(i));
443
- let attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition));
444
- color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation);
1137
+ let attenuation = getPointLightAttenuation(
1138
+ lighting_getPointLight(i),
1139
+ distance(lighting_getPointLight(i).position, fragmentInputs.pbr_vPosition)
1140
+ );
1141
+ color += calculateMaterialLightColor(
1142
+ pbrInfo,
1143
+ lighting_getPointLight(i).color / attenuation,
1144
+ clearcoatNormal,
1145
+ clearcoatFactor,
1146
+ clearcoatRoughness,
1147
+ sheenColor,
1148
+ sheenRoughness,
1149
+ anisotropyTangent,
1150
+ anisotropyStrength
1151
+ );
1152
+ }
1153
+ }
1154
+
1155
+ for (var i = 0; i < lighting.spotLightCount; i++) {
1156
+ if (i < lighting.spotLightCount) {
1157
+ PBRInfo_setSpotLight(&pbrInfo, lighting_getSpotLight(i));
1158
+ let attenuation = getSpotLightAttenuation(lighting_getSpotLight(i), fragmentInputs.pbr_vPosition);
1159
+ color += calculateMaterialLightColor(
1160
+ pbrInfo,
1161
+ lighting_getSpotLight(i).color / attenuation,
1162
+ clearcoatNormal,
1163
+ clearcoatFactor,
1164
+ clearcoatRoughness,
1165
+ sheenColor,
1166
+ sheenRoughness,
1167
+ anisotropyTangent,
1168
+ anisotropyStrength
1169
+ );
445
1170
  }
446
1171
  }
447
1172
  #endif
448
1173
 
449
1174
  // Calculate lighting contribution from image based lighting source (IBL)
450
1175
  #ifdef USE_IBL
451
- if (pbrMaterial.IBLenabled) {
452
- color += getIBLContribution(pbrInfo, n, reflection);
1176
+ if (pbrMaterial.IBLenabled != 0) {
1177
+ color += getIBLContribution(pbrInfo, n, reflection) *
1178
+ calculateAnisotropyBoost(pbrInfo, anisotropyTangent, anisotropyStrength);
1179
+ color += calculateClearcoatIBLContribution(
1180
+ pbrInfo,
1181
+ clearcoatNormal,
1182
+ -normalize(reflect(v, clearcoatNormal)),
1183
+ clearcoatFactor,
1184
+ clearcoatRoughness
1185
+ );
1186
+ color += sheenColor * pbrMaterial.scaleIBLAmbient.x * (1.0 - sheenRoughness) * 0.25;
453
1187
  }
454
1188
  #endif
455
1189
 
456
1190
  // Apply optional PBR terms for additional (optional) shading
457
1191
  #ifdef HAS_OCCLUSIONMAP
458
- if (pbrMaterial.occlusionMapEnabled) {
459
- let ao = textureSample(pbr_occlusionSampler, pbr_occlusionSampler, pbr_vUV).r;
1192
+ if (pbrMaterial.occlusionMapEnabled != 0) {
1193
+ let ao =
1194
+ textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, fragmentInputs.pbr_vUV).r;
460
1195
  color = mix(color, color * ao, pbrMaterial.occlusionStrength);
461
1196
  }
462
1197
  #endif
463
1198
 
1199
+ var emissive = pbrMaterial.emissiveFactor;
464
1200
  #ifdef HAS_EMISSIVEMAP
465
- if (pbrMaterial.emissiveMapEnabled) {
466
- let emissive = SRGBtoLINEAR(textureSample(pbr_emissiveSampler, pbr_emissiveSampler, pbr_vUV)).rgb * pbrMaterial.emissiveFactor;
467
- color += emissive;
1201
+ if (pbrMaterial.emissiveMapEnabled != 0u) {
1202
+ emissive *= SRGBtoLINEAR(
1203
+ textureSample(pbr_emissiveSampler, pbr_emissiveSamplerSampler, fragmentInputs.pbr_vUV)
1204
+ ).rgb;
468
1205
  }
469
1206
  #endif
1207
+ color += emissive * pbrMaterial.emissiveStrength;
1208
+
1209
+ if (transmission > 0.0) {
1210
+ color = mix(color, color * getVolumeAttenuation(thickness), transmission);
1211
+ }
470
1212
 
471
1213
  // This section uses mix to override final color for reference app visualization
472
1214
  // of various parameters in the lighting equation.
@@ -485,6 +1227,7 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
485
1227
  #endif
486
1228
  }
487
1229
 
488
- return vec4<f32>(pow(color, vec3<f32>(1.0 / 2.2)), baseColor.a);
1230
+ let alpha = clamp(baseColor.a * (1.0 - transmission), 0.0, 1.0);
1231
+ return vec4<f32>(pow(color, vec3<f32>(1.0 / 2.2)), alpha);
489
1232
  }
490
1233
  `;