@luma.gl/shadertools 9.3.0-alpha.4 → 9.3.0-alpha.8

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 (157) hide show
  1. package/dist/dist.dev.js +4657 -523
  2. package/dist/dist.min.js +1952 -301
  3. package/dist/index.cjs +2804 -406
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +10 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +4 -0
  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 +211 -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 +3 -0
  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 +22 -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 +112 -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/uniform-types.d.ts +11 -7
  37. package/dist/lib/utils/uniform-types.d.ts.map +1 -1
  38. package/dist/modules/engine/picking/picking.d.ts +3 -0
  39. package/dist/modules/engine/picking/picking.d.ts.map +1 -1
  40. package/dist/modules/engine/picking/picking.js +3 -0
  41. package/dist/modules/engine/picking/picking.js.map +1 -1
  42. package/dist/modules/engine/skin/skin.d.ts +30 -0
  43. package/dist/modules/engine/skin/skin.d.ts.map +1 -0
  44. package/dist/modules/engine/skin/skin.js +86 -0
  45. package/dist/modules/engine/skin/skin.js.map +1 -0
  46. package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts +1 -0
  47. package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts.map +1 -1
  48. package/dist/modules/lighting/gouraud-material/gouraud-material.js +3 -0
  49. package/dist/modules/lighting/gouraud-material/gouraud-material.js.map +1 -1
  50. package/dist/modules/lighting/ibl/ibl.d.ts +26 -0
  51. package/dist/modules/lighting/ibl/ibl.d.ts.map +1 -0
  52. package/dist/modules/lighting/ibl/ibl.js +33 -0
  53. package/dist/modules/lighting/ibl/ibl.js.map +1 -0
  54. package/dist/modules/lighting/lambert-material/lambert-material.d.ts +10 -0
  55. package/dist/modules/lighting/lambert-material/lambert-material.d.ts.map +1 -0
  56. package/dist/modules/lighting/lambert-material/lambert-material.js +33 -0
  57. package/dist/modules/lighting/lambert-material/lambert-material.js.map +1 -0
  58. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts +3 -0
  59. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts.map +1 -0
  60. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js +60 -0
  61. package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js.map +1 -0
  62. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.d.ts +2 -0
  63. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.d.ts.map +1 -0
  64. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.js +73 -0
  65. package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.js.map +1 -0
  66. package/dist/modules/lighting/lights/lighting-glsl.d.ts +1 -1
  67. package/dist/modules/lighting/lights/lighting-glsl.d.ts.map +1 -1
  68. package/dist/modules/lighting/lights/lighting-glsl.js +43 -37
  69. package/dist/modules/lighting/lights/lighting-glsl.js.map +1 -1
  70. package/dist/modules/lighting/lights/lighting-wgsl.d.ts +1 -1
  71. package/dist/modules/lighting/lights/lighting-wgsl.d.ts.map +1 -1
  72. package/dist/modules/lighting/lights/lighting-wgsl.js +46 -18
  73. package/dist/modules/lighting/lights/lighting-wgsl.js.map +1 -1
  74. package/dist/modules/lighting/lights/lighting.d.ts +104 -62
  75. package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
  76. package/dist/modules/lighting/lights/lighting.js +107 -68
  77. package/dist/modules/lighting/lights/lighting.js.map +1 -1
  78. package/dist/modules/lighting/no-material/dirlight.d.ts +7 -2
  79. package/dist/modules/lighting/no-material/dirlight.d.ts.map +1 -1
  80. package/dist/modules/lighting/no-material/dirlight.js +3 -1
  81. package/dist/modules/lighting/no-material/dirlight.js.map +1 -1
  82. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +1 -1
  83. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
  84. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +524 -28
  85. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js.map +1 -1
  86. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +2 -2
  87. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
  88. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +784 -101
  89. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
  90. package/dist/modules/lighting/pbr-material/pbr-material.d.ts +110 -45
  91. package/dist/modules/lighting/pbr-material/pbr-material.d.ts.map +1 -1
  92. package/dist/modules/lighting/pbr-material/pbr-material.js +85 -9
  93. package/dist/modules/lighting/pbr-material/pbr-material.js.map +1 -1
  94. package/dist/modules/lighting/pbr-material/pbr-projection.d.ts.map +1 -1
  95. package/dist/modules/lighting/pbr-material/pbr-projection.js +13 -1
  96. package/dist/modules/lighting/pbr-material/pbr-projection.js.map +1 -1
  97. package/dist/modules/lighting/phong-material/phong-material.d.ts +1 -0
  98. package/dist/modules/lighting/phong-material/phong-material.d.ts.map +1 -1
  99. package/dist/modules/lighting/phong-material/phong-material.js +4 -0
  100. package/dist/modules/lighting/phong-material/phong-material.js.map +1 -1
  101. package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts +2 -2
  102. package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts.map +1 -1
  103. package/dist/modules/lighting/phong-material/phong-shaders-glsl.js +15 -4
  104. package/dist/modules/lighting/phong-material/phong-shaders-glsl.js.map +1 -1
  105. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts +1 -40
  106. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts.map +1 -1
  107. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js +71 -76
  108. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js.map +1 -1
  109. package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts +1 -1
  110. package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts.map +1 -1
  111. package/dist/modules/math/fp64/fp64-arithmetic-glsl.js +41 -10
  112. package/dist/modules/math/fp64/fp64-arithmetic-glsl.js.map +1 -1
  113. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts +2 -0
  114. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts.map +1 -0
  115. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js +212 -0
  116. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js.map +1 -0
  117. package/dist/modules/math/fp64/fp64.d.ts +1 -0
  118. package/dist/modules/math/fp64/fp64.d.ts.map +1 -1
  119. package/dist/modules/math/fp64/fp64.js +8 -2
  120. package/dist/modules/math/fp64/fp64.js.map +1 -1
  121. package/dist/modules/math/random/random.d.ts +1 -1
  122. package/dist/modules/math/random/random.d.ts.map +1 -1
  123. package/dist/modules/math/random/random.js +2 -3
  124. package/dist/modules/math/random/random.js.map +1 -1
  125. package/package.json +3 -3
  126. package/src/index.ts +20 -2
  127. package/src/lib/preprocessor/preprocessor.ts +44 -8
  128. package/src/lib/shader-assembler.ts +25 -3
  129. package/src/lib/shader-assembly/assemble-shaders.ts +377 -12
  130. package/src/lib/shader-assembly/wgsl-binding-debug.ts +216 -0
  131. package/src/lib/shader-generator/glsl/generate-glsl.ts +7 -1
  132. package/src/lib/shader-generator/wgsl/generate-wgsl.ts +6 -0
  133. package/src/lib/shader-module/shader-module-uniform-layout.ts +194 -0
  134. package/src/lib/shader-module/shader-module.ts +17 -7
  135. package/src/lib/utils/uniform-types.ts +24 -9
  136. package/src/modules/engine/picking/picking.ts +3 -0
  137. package/src/modules/engine/skin/skin.ts +114 -0
  138. package/src/modules/lighting/gouraud-material/gouraud-material.ts +4 -0
  139. package/src/modules/lighting/ibl/ibl.ts +44 -0
  140. package/src/modules/lighting/lambert-material/lambert-material.ts +42 -0
  141. package/src/modules/lighting/lambert-material/lambert-shaders-glsl.ts +61 -0
  142. package/src/modules/lighting/lambert-material/lambert-shaders-wgsl.ts +73 -0
  143. package/src/modules/lighting/lights/lighting-glsl.ts +43 -37
  144. package/src/modules/lighting/lights/lighting-wgsl.ts +46 -18
  145. package/src/modules/lighting/lights/lighting.ts +198 -99
  146. package/src/modules/lighting/no-material/dirlight.ts +3 -1
  147. package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +524 -28
  148. package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +784 -101
  149. package/src/modules/lighting/pbr-material/pbr-material.ts +111 -18
  150. package/src/modules/lighting/pbr-material/pbr-projection.ts +14 -1
  151. package/src/modules/lighting/phong-material/phong-material.ts +5 -0
  152. package/src/modules/lighting/phong-material/phong-shaders-glsl.ts +15 -4
  153. package/src/modules/lighting/phong-material/phong-shaders-wgsl.ts +71 -77
  154. package/src/modules/math/fp64/fp64-arithmetic-glsl.ts +41 -10
  155. package/src/modules/math/fp64/fp64-arithmetic-wgsl.ts +212 -0
  156. package/src/modules/math/fp64/fp64.ts +9 -3
  157. package/src/modules/math/random/random.ts +2 -3
@@ -55,10 +55,12 @@ uniform pbrMaterialUniforms {
55
55
  float clearcoatFactor;
56
56
  float clearcoatRoughnessFactor;
57
57
  bool clearcoatMapEnabled;
58
+ bool clearcoatRoughnessMapEnabled;
58
59
 
59
60
  vec3 sheenColorFactor;
60
61
  float sheenRoughnessFactor;
61
62
  bool sheenColorMapEnabled;
63
+ bool sheenRoughnessMapEnabled;
62
64
 
63
65
  float iridescenceFactor;
64
66
  float iridescenceIor;
@@ -108,17 +110,30 @@ uniform sampler2D u_SpecularIntensitySampler;
108
110
  #ifdef HAS_TRANSMISSIONMAP
109
111
  uniform sampler2D u_TransmissionSampler;
110
112
  #endif
113
+ #ifdef HAS_THICKNESSMAP
114
+ uniform sampler2D u_ThicknessSampler;
115
+ #endif
111
116
  #ifdef HAS_CLEARCOATMAP
112
117
  uniform sampler2D u_ClearcoatSampler;
118
+ #endif
119
+ #ifdef HAS_CLEARCOATROUGHNESSMAP
113
120
  uniform sampler2D u_ClearcoatRoughnessSampler;
114
121
  #endif
122
+ #ifdef HAS_CLEARCOATNORMALMAP
123
+ uniform sampler2D u_ClearcoatNormalSampler;
124
+ #endif
115
125
  #ifdef HAS_SHEENCOLORMAP
116
126
  uniform sampler2D u_SheenColorSampler;
127
+ #endif
128
+ #ifdef HAS_SHEENROUGHNESSMAP
117
129
  uniform sampler2D u_SheenRoughnessSampler;
118
130
  #endif
119
131
  #ifdef HAS_IRIDESCENCEMAP
120
132
  uniform sampler2D u_IridescenceSampler;
121
133
  #endif
134
+ #ifdef HAS_IRIDESCENCETHICKNESSMAP
135
+ uniform sampler2D u_IridescenceThicknessSampler;
136
+ #endif
122
137
  #ifdef HAS_ANISOTROPYMAP
123
138
  uniform sampler2D u_AnisotropySampler;
124
139
  #endif
@@ -134,57 +149,97 @@ export const source = /* wgsl */ `\
134
149
  struct PBRFragmentInputs {
135
150
  pbr_vPosition: vec3f,
136
151
  pbr_vUV: vec2f,
137
- pbr_vTBN: mat3f,
152
+ pbr_vTBN: mat3x3f,
138
153
  pbr_vNormal: vec3f
139
154
  };
140
155
 
141
- var fragmentInputs: PBRFragmentInputs;
156
+ var<private> fragmentInputs: PBRFragmentInputs;
142
157
 
143
158
  fn pbr_setPositionNormalTangentUV(position: vec4f, normal: vec4f, tangent: vec4f, uv: vec2f)
144
159
  {
145
160
  var pos: vec4f = pbrProjection.modelMatrix * position;
146
- fragmentInputs.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);
147
169
 
148
170
  #ifdef HAS_NORMALS
171
+ let normalW: vec3f = normalize((pbrProjection.normalMatrix * vec4f(normal.xyz, 0.0)).xyz);
172
+ fragmentInputs.pbr_vNormal = normalW;
149
173
  #ifdef HAS_TANGENTS
150
- let normalW: vec3f = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));
151
- 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);
152
175
  let bitangentW: vec3f = cross(normalW, tangentW) * tangent.w;
153
- fragmentInputs.pbr_vTBN = mat3(tangentW, bitangentW, normalW);
154
- #else // HAS_TANGENTS != 1
155
- fragmentInputs.pbr_vNormal = normalize(vec3(pbrProjection.modelMatrix * vec4(normal.xyz, 0.0)));
176
+ fragmentInputs.pbr_vTBN = mat3x3f(tangentW, bitangentW, normalW);
156
177
  #endif
157
178
  #endif
158
179
 
159
180
  #ifdef HAS_UV
160
181
  fragmentInputs.pbr_vUV = uv;
161
- #else
162
- fragmentInputs.pbr_vUV = vec2(0.,0.);
163
182
  #endif
164
183
  }
165
184
 
166
185
  struct pbrMaterialUniforms {
167
186
  // Material is unlit
168
- unlit: uint32,
187
+ unlit: u32,
169
188
 
170
189
  // Base color map
171
- baseColorMapEnabled: uint32,
190
+ baseColorMapEnabled: u32,
172
191
  baseColorFactor: vec4f,
173
192
 
174
- normalMapEnabled : uint32,
193
+ normalMapEnabled : u32,
175
194
  normalScale: f32, // #ifdef HAS_NORMALMAP
176
195
 
177
- emissiveMapEnabled: uint32,
196
+ emissiveMapEnabled: u32,
178
197
  emissiveFactor: vec3f, // #ifdef HAS_EMISSIVEMAP
179
198
 
180
199
  metallicRoughnessValues: vec2f,
181
- metallicRoughnessMapEnabled: uint32,
200
+ metallicRoughnessMapEnabled: u32,
182
201
 
183
202
  occlusionMapEnabled: i32,
184
203
  occlusionStrength: f32, // #ifdef HAS_OCCLUSIONMAP
185
204
 
186
205
  alphaCutoffEnabled: i32,
187
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,
188
243
 
189
244
  // IBL
190
245
  IBLenabled: i32,
@@ -193,34 +248,81 @@ struct pbrMaterialUniforms {
193
248
  // debugging flags used for shader output of intermediate PBR variables
194
249
  // #ifdef PBR_DEBUG
195
250
  scaleDiffBaseMR: vec4f,
196
- scaleFGDSpec: vec4f
251
+ scaleFGDSpec: vec4f,
197
252
  // #endif
198
253
  }
199
254
 
200
- @binding(2) @group(0) var<uniform> pbrMaterial : pbrMaterialUniforms;
255
+ @group(3) @binding(auto) var<uniform> pbrMaterial : pbrMaterialUniforms;
201
256
 
202
257
  // Samplers
203
258
  #ifdef HAS_BASECOLORMAP
204
- uniform sampler2D pbr_baseColorSampler;
259
+ @group(3) @binding(auto) var pbr_baseColorSampler: texture_2d<f32>;
260
+ @group(3) @binding(auto) var pbr_baseColorSamplerSampler: sampler;
205
261
  #endif
206
262
  #ifdef HAS_NORMALMAP
207
- uniform sampler2D pbr_normalSampler;
263
+ @group(3) @binding(auto) var pbr_normalSampler: texture_2d<f32>;
264
+ @group(3) @binding(auto) var pbr_normalSamplerSampler: sampler;
208
265
  #endif
209
266
  #ifdef HAS_EMISSIVEMAP
210
- uniform sampler2D pbr_emissiveSampler;
267
+ @group(3) @binding(auto) var pbr_emissiveSampler: texture_2d<f32>;
268
+ @group(3) @binding(auto) var pbr_emissiveSamplerSampler: sampler;
211
269
  #endif
212
270
  #ifdef HAS_METALROUGHNESSMAP
213
- uniform sampler2D pbr_metallicRoughnessSampler;
271
+ @group(3) @binding(auto) var pbr_metallicRoughnessSampler: texture_2d<f32>;
272
+ @group(3) @binding(auto) var pbr_metallicRoughnessSamplerSampler: sampler;
214
273
  #endif
215
274
  #ifdef HAS_OCCLUSIONMAP
216
- uniform sampler2D pbr_occlusionSampler;
275
+ @group(3) @binding(auto) var pbr_occlusionSampler: texture_2d<f32>;
276
+ @group(3) @binding(auto) var pbr_occlusionSamplerSampler: sampler;
217
277
  #endif
218
- #ifdef USE_IBL
219
- uniform samplerCube pbr_diffuseEnvSampler;
220
- uniform samplerCube pbr_specularEnvSampler;
221
- 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;
222
325
  #endif
223
-
224
326
  // Encapsulate the various inputs used by the various functions in the shading equation
225
327
  // We store values in this struct to simplify the integration of alternative implementations
226
328
  // of the shading terms, outlined in the Readme.MD Appendix.
@@ -246,80 +348,130 @@ const c_MinRoughness = 0.04;
246
348
 
247
349
  fn SRGBtoLINEAR(srgbIn: vec4f ) -> vec4f
248
350
  {
351
+ var linOut: vec3f = srgbIn.xyz;
249
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
+ );
250
359
  #ifdef SRGB_FAST_APPROXIMATION
251
- var linOut: vec3f = pow(srgbIn.xyz,vec3(2.2));
252
- #else // SRGB_FAST_APPROXIMATION
253
- var bLess: vec3f = step(vec3(0.04045),srgbIn.xyz);
254
- var linOut: vec3f = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess );
255
- #endif //SRGB_FAST_APPROXIMATION
256
- return vec4f(linOut,srgbIn.w);;
257
- #else //MANUAL_SRGB
258
- return srgbIn;
259
- #endif //MANUAL_SRGB
360
+ linOut = pow(srgbIn.xyz, vec3f(2.2));
361
+ #endif
362
+ #endif
363
+ return vec4f(linOut, srgbIn.w);
260
364
  }
261
365
 
262
- // Find the normal for this fragment, pulling either from a predefined normal map
263
- // or from the interpolated mesh normal and tangent attributes.
264
- fn getNormal() -> vec3f
366
+ // Build the tangent basis from interpolated attributes or screen-space derivatives.
367
+ fn getTBN() -> mat3x3f
265
368
  {
266
- // Retrieve the tangent space matrix
267
- #ifndef HAS_TANGENTS
268
- var pos_dx: vec3f = dFdx(fragmentInputs.pbr_vPosition);
269
- var pos_dy: vec3f = dFdy(fragmentInputs.pbr_vPosition);
270
- var tex_dx: vec3f = dFdx(vec3(fragmentInputs.pbr_vUV, 0.0));
271
- var tex_dy: vec3f = dFdy(vec3(fragmentInputs.pbr_vUV, 0.0));
272
- 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);
273
374
 
274
- #ifdef HAS_NORMALS
275
- var ng: vec3f = normalize(fragmentInputs.pbr_vNormal);
276
- #else
277
375
  var ng: vec3f = cross(pos_dx, pos_dy);
376
+ #ifdef HAS_NORMALS
377
+ ng = normalize(fragmentInputs.pbr_vNormal);
278
378
  #endif
279
-
280
379
  t = normalize(t - ng * dot(ng, t));
281
380
  var b: vec3f = normalize(cross(ng, t));
282
- var tbn: mat3f = mat3f(t, b, ng);
283
- #else // HAS_TANGENTS
284
- var tbn: mat3f = fragmentInputs.pbr_vTBN;
381
+ var tbn: mat3x3f = mat3x3f(t, b, ng);
382
+ #ifdef HAS_TANGENTS
383
+ tbn = fragmentInputs.pbr_vTBN;
285
384
  #endif
286
385
 
287
- #ifdef HAS_NORMALMAP
288
- vec3 n = texture(pbr_normalSampler, fragmentInputs.pbr_vUV).rgb;
289
- n = normalize(tbn * ((2.0 * n - 1.0) * vec3(pbrMaterial.normalScale, pbrMaterial.normalScale, 1.0)));
290
- #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
+ {
291
404
  // The tbn matrix is linearly interpolated, so we need to re-normalize
292
- 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
+ );
293
413
  #endif
294
414
 
295
415
  return n;
296
416
  }
297
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
+
298
432
  // Calculation of the lighting contribution from an optional Image Based Light source.
299
433
  // Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
300
434
  // See our README.md on Environment Maps [3] for additional discussion.
301
435
  #ifdef USE_IBL
302
- fn getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection) -> vec3f
436
+ fn getIBLContribution(pbrInfo: PBRInfo, n: vec3f, reflection: vec3f) -> vec3f
303
437
  {
304
- float mipCount = 9.0; // resolution of 512x512
305
- float lod = (pbrInfo.perceptualRoughness * mipCount);
438
+ let mipCount: f32 = 9.0; // resolution of 512x512
439
+ let lod: f32 = pbrInfo.perceptualRoughness * mipCount;
306
440
  // retrieve a scale and bias to F0. See [1], Figure 3
307
- vec3 brdf = SRGBtoLINEAR(texture(pbr_brdfLUT,
308
- vec2(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness))).rgb;
309
- vec3 diffuseLight = SRGBtoLINEAR(texture(pbr_diffuseEnvSampler, n)).rgb;
310
-
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;
311
461
  #ifdef USE_TEX_LOD
312
- vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection, lod)).rgb;
313
- #else
314
- 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;
315
470
  #endif
316
471
 
317
- vec3 diffuse = diffuseLight * pbrInfo.diffuseColor;
318
- vec3 specular = specularLight * (pbrInfo.specularColor * brdf.x + brdf.y);
319
-
320
- // For presentation, this allows us to disable IBL terms
321
- diffuse *= pbrMaterial.scaleIBLAmbient.x;
322
- 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;
323
475
 
324
476
  return diffuse + specular;
325
477
  }
@@ -363,7 +515,173 @@ fn geometricOcclusion(pbrInfo: PBRInfo) -> f32 {
363
515
  fn microfacetDistribution(pbrInfo: PBRInfo) -> f32 {
364
516
  let roughnessSq = pbrInfo.alphaRoughness * pbrInfo.alphaRoughness;
365
517
  let f = (pbrInfo.NdotH * roughnessSq - pbrInfo.NdotH) * pbrInfo.NdotH + 1.0;
366
- 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;
367
685
  }
368
686
 
369
687
  fn PBRInfo_setAmbientLight(pbrInfo: ptr<function, PBRInfo>) {
@@ -390,6 +708,11 @@ fn PBRInfo_setPointLight(pbrInfo: ptr<function, PBRInfo>, pointLight: PointLight
390
708
  PBRInfo_setDirectionalLight(pbrInfo, light_direction);
391
709
  }
392
710
 
711
+ fn PBRInfo_setSpotLight(pbrInfo: ptr<function, PBRInfo>, spotLight: SpotLight) {
712
+ let light_direction = normalize(spotLight.position - fragmentInputs.pbr_vPosition);
713
+ PBRInfo_setDirectionalLight(pbrInfo, light_direction);
714
+ }
715
+
393
716
  fn calculateFinalColor(pbrInfo: PBRInfo, lightColor: vec3<f32>) -> vec3<f32> {
394
717
  // Calculate the shading terms for the microfacet specular shading model
395
718
  let F = specularReflection(pbrInfo);
@@ -405,11 +728,11 @@ fn calculateFinalColor(pbrInfo: PBRInfo, lightColor: vec3<f32>) -> vec3<f32> {
405
728
 
406
729
  fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
407
730
  // The albedo may be defined from a base texture or a flat color
408
- var baseColor: vec4<f32>;
731
+ var baseColor: vec4<f32> = pbrMaterial.baseColorFactor;
409
732
  #ifdef HAS_BASECOLORMAP
410
- baseColor = SRGBtoLINEAR(textureSample(pbr_baseColorSampler, pbr_baseColorSampler, fragmentInputs.pbr_vUV)) * pbrMaterial.baseColorFactor;
411
- #else
412
- baseColor = pbrMaterial.baseColorFactor;
733
+ baseColor = SRGBtoLINEAR(
734
+ textureSample(pbr_baseColorSampler, pbr_baseColorSamplerSampler, fragmentInputs.pbr_vUV)
735
+ ) * pbrMaterial.baseColorFactor;
413
736
  #endif
414
737
 
415
738
  #ifdef ALPHA_CUTOFF
@@ -419,8 +742,9 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
419
742
  #endif
420
743
 
421
744
  var color = vec3<f32>(0.0, 0.0, 0.0);
745
+ var transmission = 0.0;
422
746
 
423
- if (pbrMaterial.unlit) {
747
+ if (pbrMaterial.unlit != 0u) {
424
748
  color = baseColor.rgb;
425
749
  } else {
426
750
  // Metallic and Roughness material properties are packed together
@@ -431,20 +755,318 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
431
755
  #ifdef HAS_METALROUGHNESSMAP
432
756
  // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
433
757
  // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
434
- let mrSample = textureSample(pbr_metallicRoughnessSampler, pbr_metallicRoughnessSampler, fragmentInputs.pbr_vUV);
758
+ let mrSample = textureSample(
759
+ pbr_metallicRoughnessSampler,
760
+ pbr_metallicRoughnessSamplerSampler,
761
+ fragmentInputs.pbr_vUV
762
+ );
435
763
  perceptualRoughness = mrSample.g * perceptualRoughness;
436
764
  metallic = mrSample.b * metallic;
437
765
  #endif
438
766
  perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
439
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
+
440
1048
  // Roughness is authored as perceptual roughness; as is convention,
441
1049
  // convert to material roughness by squaring the perceptual roughness [2].
442
1050
  let alphaRoughness = perceptualRoughness * perceptualRoughness;
443
1051
 
444
- let f0 = vec3<f32>(0.04);
445
- var diffuseColor = baseColor.rgb * (vec3<f32>(1.0) - f0);
446
- diffuseColor *= 1.0 - metallic;
447
- 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;
448
1070
 
449
1071
  // Compute reflectance.
450
1072
  let reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
@@ -456,11 +1078,6 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
456
1078
  let reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
457
1079
  let specularEnvironmentR0 = specularColor;
458
1080
  let specularEnvironmentR90 = vec3<f32>(1.0, 1.0, 1.0) * reflectance90;
459
-
460
- let n = getNormal(); // normal at surface point
461
- let v = normalize(pbrProjection.camera - fragmentInputs.pbr_vPosition); // Vector from surface point to camera
462
-
463
- let NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
464
1081
  let reflection = -normalize(reflect(v, n));
465
1082
 
466
1083
  var pbrInfo = PBRInfo(
@@ -483,13 +1100,33 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
483
1100
  #ifdef USE_LIGHTS
484
1101
  // Apply ambient light
485
1102
  PBRInfo_setAmbientLight(&pbrInfo);
486
- 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
+ );
487
1114
 
488
1115
  // Apply directional light
489
1116
  for (var i = 0; i < lighting.directionalLightCount; i++) {
490
1117
  if (i < lighting.directionalLightCount) {
491
1118
  PBRInfo_setDirectionalLight(&pbrInfo, lighting_getDirectionalLight(i).direction);
492
- 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
+ );
493
1130
  }
494
1131
  }
495
1132
 
@@ -501,32 +1138,77 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
501
1138
  lighting_getPointLight(i),
502
1139
  distance(lighting_getPointLight(i).position, fragmentInputs.pbr_vPosition)
503
1140
  );
504
- color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation);
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
+ );
505
1170
  }
506
1171
  }
507
1172
  #endif
508
1173
 
509
1174
  // Calculate lighting contribution from image based lighting source (IBL)
510
1175
  #ifdef USE_IBL
511
- if (pbrMaterial.IBLenabled) {
512
- 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;
513
1187
  }
514
1188
  #endif
515
1189
 
516
1190
  // Apply optional PBR terms for additional (optional) shading
517
1191
  #ifdef HAS_OCCLUSIONMAP
518
- if (pbrMaterial.occlusionMapEnabled) {
519
- let ao = textureSample(pbr_occlusionSampler, pbr_occlusionSampler, fragmentInputs.pbr_vUV).r;
1192
+ if (pbrMaterial.occlusionMapEnabled != 0) {
1193
+ let ao =
1194
+ textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, fragmentInputs.pbr_vUV).r;
520
1195
  color = mix(color, color * ao, pbrMaterial.occlusionStrength);
521
1196
  }
522
1197
  #endif
523
1198
 
1199
+ var emissive = pbrMaterial.emissiveFactor;
524
1200
  #ifdef HAS_EMISSIVEMAP
525
- if (pbrMaterial.emissiveMapEnabled) {
526
- let emissive = SRGBtoLINEAR(textureSample(pbr_emissiveSampler, pbr_emissiveSampler, fragmentInputs.pbr_vUV)).rgb * pbrMaterial.emissiveFactor;
527
- color += emissive;
1201
+ if (pbrMaterial.emissiveMapEnabled != 0u) {
1202
+ emissive *= SRGBtoLINEAR(
1203
+ textureSample(pbr_emissiveSampler, pbr_emissiveSamplerSampler, fragmentInputs.pbr_vUV)
1204
+ ).rgb;
528
1205
  }
529
1206
  #endif
1207
+ color += emissive * pbrMaterial.emissiveStrength;
1208
+
1209
+ if (transmission > 0.0) {
1210
+ color = mix(color, color * getVolumeAttenuation(thickness), transmission);
1211
+ }
530
1212
 
531
1213
  // This section uses mix to override final color for reference app visualization
532
1214
  // of various parameters in the lighting equation.
@@ -545,6 +1227,7 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
545
1227
  #endif
546
1228
  }
547
1229
 
548
- 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);
549
1232
  }
550
1233
  `;