@luma.gl/shadertools 9.3.0-alpha.2 → 9.3.0-alpha.6

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 (66) hide show
  1. package/dist/dist.dev.js +2114 -198
  2. package/dist/dist.min.js +315 -184
  3. package/dist/index.cjs +463 -199
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -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 +33 -7
  11. package/dist/lib/preprocessor/preprocessor.js.map +1 -1
  12. package/dist/lib/shader-assembler.d.ts.map +1 -1
  13. package/dist/lib/shader-assembler.js +8 -1
  14. package/dist/lib/shader-assembler.js.map +1 -1
  15. package/dist/lib/shader-module/shader-module.d.ts +1 -1
  16. package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
  17. package/dist/lib/utils/assert.d.ts.map +1 -1
  18. package/dist/lib/utils/assert.js +3 -1
  19. package/dist/lib/utils/assert.js.map +1 -1
  20. package/dist/modules/engine/skin/skin.d.ts +29 -0
  21. package/dist/modules/engine/skin/skin.d.ts.map +1 -0
  22. package/dist/modules/engine/skin/skin.js +88 -0
  23. package/dist/modules/engine/skin/skin.js.map +1 -0
  24. package/dist/modules/lighting/lights/lighting-glsl.d.ts +1 -1
  25. package/dist/modules/lighting/lights/lighting-glsl.d.ts.map +1 -1
  26. package/dist/modules/lighting/lights/lighting-glsl.js +20 -2
  27. package/dist/modules/lighting/lights/lighting-glsl.js.map +1 -1
  28. package/dist/modules/lighting/lights/lighting-wgsl.d.ts +1 -1
  29. package/dist/modules/lighting/lights/lighting-wgsl.d.ts.map +1 -1
  30. package/dist/modules/lighting/lights/lighting-wgsl.js +63 -13
  31. package/dist/modules/lighting/lights/lighting-wgsl.js.map +1 -1
  32. package/dist/modules/lighting/lights/lighting.d.ts +27 -3
  33. package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
  34. package/dist/modules/lighting/lights/lighting.js +32 -6
  35. package/dist/modules/lighting/lights/lighting.js.map +1 -1
  36. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +1 -1
  37. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
  38. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +106 -79
  39. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
  40. package/dist/modules/lighting/pbr-material/pbr-material.d.ts +20 -4
  41. package/dist/modules/lighting/pbr-material/pbr-material.d.ts.map +1 -1
  42. package/dist/modules/lighting/pbr-material/pbr-projection.d.ts.map +1 -1
  43. package/dist/modules/lighting/pbr-material/pbr-projection.js +12 -1
  44. package/dist/modules/lighting/pbr-material/pbr-projection.js.map +1 -1
  45. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts +1 -40
  46. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts.map +1 -1
  47. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js +40 -76
  48. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js.map +1 -1
  49. package/dist/modules/math/random/random.d.ts +1 -1
  50. package/dist/modules/math/random/random.d.ts.map +1 -1
  51. package/dist/modules/math/random/random.js +2 -3
  52. package/dist/modules/math/random/random.js.map +1 -1
  53. package/package.json +2 -2
  54. package/src/index.ts +1 -0
  55. package/src/lib/preprocessor/preprocessor.ts +40 -7
  56. package/src/lib/shader-assembler.ts +8 -1
  57. package/src/lib/shader-module/shader-module.ts +1 -1
  58. package/src/lib/utils/assert.ts +3 -1
  59. package/src/modules/engine/skin/skin.ts +116 -0
  60. package/src/modules/lighting/lights/lighting-glsl.ts +20 -2
  61. package/src/modules/lighting/lights/lighting-wgsl.ts +63 -13
  62. package/src/modules/lighting/lights/lighting.ts +45 -9
  63. package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +106 -79
  64. package/src/modules/lighting/pbr-material/pbr-projection.ts +13 -1
  65. package/src/modules/lighting/phong-material/phong-shaders-wgsl.ts +40 -77
  66. package/src/modules/math/random/random.ts +2 -3
package/dist/index.cjs CHANGED
@@ -57,6 +57,7 @@ __export(dist_exports, {
57
57
  picking: () => picking,
58
58
  preprocess: () => preprocess,
59
59
  random: () => random,
60
+ skin: () => skin,
60
61
  toHalfFloat: () => toHalfFloat,
61
62
  typeToChannelCount: () => typeToChannelCount,
62
63
  typeToChannelSuffix: () => typeToChannelSuffix
@@ -65,8 +66,11 @@ module.exports = __toCommonJS(dist_exports);
65
66
 
66
67
  // dist/lib/utils/assert.js
67
68
  function assert(condition, message) {
69
+ var _a;
68
70
  if (!condition) {
69
- throw new Error(message || "shadertools: assertion failed.");
71
+ const error = new Error(message || "shadertools: assertion failed.");
72
+ (_a = Error.captureStackTrace) == null ? void 0 : _a.call(Error, error, assert);
73
+ throw error;
70
74
  }
71
75
  }
72
76
 
@@ -201,7 +205,7 @@ function getHookStage(hook) {
201
205
  throw new Error(type);
202
206
  }
203
207
  }
204
- function injectShader(source3, stage, inject, injectStandardStubs = false) {
208
+ function injectShader(source4, stage, inject, injectStandardStubs = false) {
205
209
  const isVertex = stage === "vertex";
206
210
  for (const key in inject) {
207
211
  const fragmentData = inject[key];
@@ -215,43 +219,43 @@ function injectShader(source3, stage, inject, injectStandardStubs = false) {
215
219
  switch (key) {
216
220
  case "vs:#decl":
217
221
  if (isVertex) {
218
- source3 = source3.replace(DECLARATION_INJECT_MARKER, fragmentString);
222
+ source4 = source4.replace(DECLARATION_INJECT_MARKER, fragmentString);
219
223
  }
220
224
  break;
221
225
  case "vs:#main-start":
222
226
  if (isVertex) {
223
- source3 = source3.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
227
+ source4 = source4.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
224
228
  }
225
229
  break;
226
230
  case "vs:#main-end":
227
231
  if (isVertex) {
228
- source3 = source3.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
232
+ source4 = source4.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
229
233
  }
230
234
  break;
231
235
  case "fs:#decl":
232
236
  if (!isVertex) {
233
- source3 = source3.replace(DECLARATION_INJECT_MARKER, fragmentString);
237
+ source4 = source4.replace(DECLARATION_INJECT_MARKER, fragmentString);
234
238
  }
235
239
  break;
236
240
  case "fs:#main-start":
237
241
  if (!isVertex) {
238
- source3 = source3.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
242
+ source4 = source4.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
239
243
  }
240
244
  break;
241
245
  case "fs:#main-end":
242
246
  if (!isVertex) {
243
- source3 = source3.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
247
+ source4 = source4.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
244
248
  }
245
249
  break;
246
250
  default:
247
- source3 = source3.replace(key, (match) => match + fragmentString);
251
+ source4 = source4.replace(key, (match) => match + fragmentString);
248
252
  }
249
253
  }
250
- source3 = source3.replace(DECLARATION_INJECT_MARKER, "");
254
+ source4 = source4.replace(DECLARATION_INJECT_MARKER, "");
251
255
  if (injectStandardStubs) {
252
- source3 = source3.replace(/\}\s*$/, (match) => match + MODULE_INJECTORS[stage]);
256
+ source4 = source4.replace(/\}\s*$/, (match) => match + MODULE_INJECTORS[stage]);
253
257
  }
254
- return source3;
258
+ return source4;
255
259
  }
256
260
  function combineInjects(injects) {
257
261
  const result = {};
@@ -431,19 +435,19 @@ function getPlatformShaderDefines(platformInfo) {
431
435
  }
432
436
 
433
437
  // dist/lib/shader-transpiler/transpile-glsl-shader.js
434
- function transpileGLSLShader(source3, stage) {
438
+ function transpileGLSLShader(source4, stage) {
435
439
  var _a;
436
- const sourceGLSLVersion = Number(((_a = source3.match(/^#version[ \t]+(\d+)/m)) == null ? void 0 : _a[1]) || 100);
440
+ const sourceGLSLVersion = Number(((_a = source4.match(/^#version[ \t]+(\d+)/m)) == null ? void 0 : _a[1]) || 100);
437
441
  if (sourceGLSLVersion !== 300) {
438
442
  throw new Error("luma.gl v9 only supports GLSL 3.00 shader sources");
439
443
  }
440
444
  switch (stage) {
441
445
  case "vertex":
442
- source3 = convertShader(source3, ES300_VERTEX_REPLACEMENTS);
443
- return source3;
446
+ source4 = convertShader(source4, ES300_VERTEX_REPLACEMENTS);
447
+ return source4;
444
448
  case "fragment":
445
- source3 = convertShader(source3, ES300_FRAGMENT_REPLACEMENTS);
446
- return source3;
449
+ source4 = convertShader(source4, ES300_FRAGMENT_REPLACEMENTS);
450
+ return source4;
447
451
  default:
448
452
  throw new Error(stage);
449
453
  }
@@ -467,11 +471,11 @@ var ES300_FRAGMENT_REPLACEMENTS = [
467
471
  // `varying` keyword replaced with `in`
468
472
  [makeVariableTextRegExp("varying"), "in $1"]
469
473
  ];
470
- function convertShader(source3, replacements) {
474
+ function convertShader(source4, replacements) {
471
475
  for (const [pattern, replacement] of replacements) {
472
- source3 = source3.replace(pattern, replacement);
476
+ source4 = source4.replace(pattern, replacement);
473
477
  }
474
- return source3;
478
+ return source4;
475
479
  }
476
480
  function makeVariableTextRegExp(qualifier) {
477
481
  return new RegExp(`\\b${qualifier}[ \\t]+(\\w+[ \\t]+\\w+(\\[\\w+\\])?;)`, "g");
@@ -533,11 +537,11 @@ function normalizeShaderHooks(hookFunctions) {
533
537
  }
534
538
 
535
539
  // dist/lib/glsl-utils/get-shader-info.js
536
- function getShaderInfo(source3, defaultName) {
540
+ function getShaderInfo(source4, defaultName) {
537
541
  return {
538
- name: getShaderName(source3, defaultName),
542
+ name: getShaderName(source4, defaultName),
539
543
  language: "glsl",
540
- version: getShaderVersion(source3)
544
+ version: getShaderVersion(source4)
541
545
  };
542
546
  }
543
547
  function getShaderName(shader, defaultName = "unnamed") {
@@ -545,9 +549,9 @@ function getShaderName(shader, defaultName = "unnamed") {
545
549
  const match = SHADER_NAME_REGEXP.exec(shader);
546
550
  return match ? match[1] : defaultName;
547
551
  }
548
- function getShaderVersion(source3) {
552
+ function getShaderVersion(source4) {
549
553
  let version = 100;
550
- const words = source3.match(/[^\s]+/g);
554
+ const words = source4.match(/[^\s]+/g);
551
555
  if (words && words.length >= 2 && words[0] === "#version") {
552
556
  const parsedVersion = parseInt(words[1], 10);
553
557
  if (Number.isFinite(parsedVersion)) {
@@ -583,19 +587,19 @@ function assembleWGSLShader(options) {
583
587
  };
584
588
  }
585
589
  function assembleGLSLShaderPair(options) {
586
- const { vs: vs3, fs: fs4 } = options;
590
+ const { vs: vs4, fs: fs5 } = options;
587
591
  const modules = getShaderModuleDependencies(options.modules || []);
588
592
  return {
589
593
  vs: assembleShaderGLSL(options.platformInfo, {
590
594
  ...options,
591
- source: vs3,
595
+ source: vs4,
592
596
  stage: "vertex",
593
597
  modules
594
598
  }),
595
599
  fs: assembleShaderGLSL(options.platformInfo, {
596
600
  ...options,
597
601
  // @ts-expect-error
598
- source: fs4,
602
+ source: fs5,
599
603
  stage: "fragment",
600
604
  modules
601
605
  }),
@@ -606,7 +610,7 @@ function assembleShaderWGSL(platformInfo, options) {
606
610
  var _a;
607
611
  const {
608
612
  // id,
609
- source: source3,
613
+ source: source4,
610
614
  stage,
611
615
  modules,
612
616
  // defines = {},
@@ -614,8 +618,8 @@ function assembleShaderWGSL(platformInfo, options) {
614
618
  inject = {},
615
619
  log: log2
616
620
  } = options;
617
- assert(typeof source3 === "string", "shader source must be a string");
618
- const coreSource = source3;
621
+ assert(typeof source4 === "string", "shader source must be a string");
622
+ const coreSource = source4;
619
623
  let assembledSource = "";
620
624
  const hookFunctionMap = normalizeShaderHooks(hookFunctions);
621
625
  const hookInjections = {};
@@ -670,12 +674,12 @@ function assembleShaderWGSL(platformInfo, options) {
670
674
  }
671
675
  function assembleShaderGLSL(platformInfo, options) {
672
676
  var _a;
673
- const { source: source3, stage, language = "glsl", modules, defines = {}, hookFunctions = [], inject = {}, prologue = true, log: log2 } = options;
674
- assert(typeof source3 === "string", "shader source must be a string");
675
- const sourceVersion = language === "glsl" ? getShaderInfo(source3).version : -1;
677
+ const { source: source4, stage, language = "glsl", modules, defines = {}, hookFunctions = [], inject = {}, prologue = true, log: log2 } = options;
678
+ assert(typeof source4 === "string", "shader source must be a string");
679
+ const sourceVersion = language === "glsl" ? getShaderInfo(source4).version : -1;
676
680
  const targetVersion = platformInfo.shaderLanguageVersion;
677
681
  const sourceVersionDirective = sourceVersion === 100 ? "#version 100" : "#version 300 es";
678
- const sourceLines = source3.split("\n");
682
+ const sourceLines = source4.split("\n");
679
683
  const coreSource = sourceLines.slice(1).join("\n");
680
684
  const allDefines = {};
681
685
  modules.forEach((module2) => {
@@ -798,39 +802,61 @@ function getShaderModuleSource(module2, stage) {
798
802
  throw new Error("Shader module must have a name");
799
803
  }
800
804
  const moduleName = module2.name.toUpperCase().replace(/[^0-9a-z]/gi, "_");
801
- let source3 = `// ----- MODULE ${module2.name} ---------------
805
+ let source4 = `// ----- MODULE ${module2.name} ---------------
802
806
 
803
807
  `;
804
808
  if (stage !== "wgsl") {
805
- source3 += `#define MODULE_${moduleName}
809
+ source4 += `#define MODULE_${moduleName}
806
810
  `;
807
811
  }
808
- source3 += `${moduleSource}
812
+ source4 += `${moduleSource}
809
813
  `;
810
- return source3;
814
+ return source4;
811
815
  }
812
816
 
813
817
  // dist/lib/preprocessor/preprocessor.js
814
818
  var IFDEF_REGEXP = /^\s*\#\s*ifdef\s*([a-zA-Z_]+)\s*$/;
819
+ var IFNDEF_REGEXP = /^\s*\#\s*ifndef\s*([a-zA-Z_]+)\s*(?:\/\/.*)?$/;
820
+ var ELSE_REGEXP = /^\s*\#\s*else\s*(?:\/\/.*)?$/;
815
821
  var ENDIF_REGEXP = /^\s*\#\s*endif\s*$/;
816
- function preprocess(source3, options) {
817
- var _a;
818
- const lines = source3.split("\n");
822
+ var IFDEF_WITH_COMMENT_REGEXP = /^\s*\#\s*ifdef\s*([a-zA-Z_]+)\s*(?:\/\/.*)?$/;
823
+ var ENDIF_WITH_COMMENT_REGEXP = /^\s*\#\s*endif\s*(?:\/\/.*)?$/;
824
+ function preprocess(source4, options) {
825
+ var _a, _b;
826
+ const lines = source4.split("\n");
819
827
  const output = [];
828
+ const conditionalStack = [];
820
829
  let conditional = true;
821
- let currentDefine = null;
822
830
  for (const line of lines) {
823
- const matchIf = line.match(IFDEF_REGEXP);
824
- const matchEnd = line.match(ENDIF_REGEXP);
825
- if (matchIf) {
826
- currentDefine = matchIf[1];
827
- conditional = Boolean((_a = options == null ? void 0 : options.defines) == null ? void 0 : _a[currentDefine]);
831
+ const matchIf = line.match(IFDEF_WITH_COMMENT_REGEXP) || line.match(IFDEF_REGEXP);
832
+ const matchIfNot = line.match(IFNDEF_REGEXP);
833
+ const matchElse = line.match(ELSE_REGEXP);
834
+ const matchEnd = line.match(ENDIF_WITH_COMMENT_REGEXP) || line.match(ENDIF_REGEXP);
835
+ if (matchIf || matchIfNot) {
836
+ const defineName = (_a = matchIf || matchIfNot) == null ? void 0 : _a[1];
837
+ const defineValue = Boolean((_b = options == null ? void 0 : options.defines) == null ? void 0 : _b[defineName]);
838
+ const branchTaken = matchIf ? defineValue : !defineValue;
839
+ const active = conditional && branchTaken;
840
+ conditionalStack.push({ parentActive: conditional, branchTaken, active });
841
+ conditional = active;
842
+ } else if (matchElse) {
843
+ const currentConditional = conditionalStack[conditionalStack.length - 1];
844
+ if (!currentConditional) {
845
+ throw new Error("Encountered #else without matching #ifdef or #ifndef");
846
+ }
847
+ currentConditional.active = currentConditional.parentActive && !currentConditional.branchTaken;
848
+ currentConditional.branchTaken = true;
849
+ conditional = currentConditional.active;
828
850
  } else if (matchEnd) {
829
- conditional = true;
851
+ conditionalStack.pop();
852
+ conditional = conditionalStack.length ? conditionalStack[conditionalStack.length - 1].active : true;
830
853
  } else if (conditional) {
831
854
  output.push(line);
832
855
  }
833
856
  }
857
+ if (conditionalStack.length > 0) {
858
+ throw new Error("Unterminated conditional block in shader source");
859
+ }
834
860
  return output.join("\n");
835
861
  }
836
862
 
@@ -883,14 +909,21 @@ var _ShaderAssembler = class {
883
909
  assembleWGSLShader(props) {
884
910
  const modules = this._getModuleList(props.modules);
885
911
  const hookFunctions = this._hookFunctions;
886
- const { source: source3, getUniforms: getUniforms4 } = assembleWGSLShader({
912
+ const { source: source4, getUniforms: getUniforms4 } = assembleWGSLShader({
887
913
  ...props,
888
914
  // @ts-expect-error
889
915
  source: props.source,
890
916
  modules,
891
917
  hookFunctions
892
918
  });
893
- const preprocessedSource = props.platformInfo.shaderLanguage === "wgsl" ? preprocess(source3) : source3;
919
+ const defines = {
920
+ ...modules.reduce((accumulator, module2) => {
921
+ Object.assign(accumulator, module2.defines);
922
+ return accumulator;
923
+ }, {}),
924
+ ...props.defines
925
+ };
926
+ const preprocessedSource = props.platformInfo.shaderLanguage === "wgsl" ? preprocess(source4, { defines }) : source4;
894
927
  return { source: preprocessedSource, getUniforms: getUniforms4, modules };
895
928
  }
896
929
  /**
@@ -1245,9 +1278,8 @@ function fp64ifyMatrix4(matrix) {
1245
1278
  // dist/modules/math/random/random.js
1246
1279
  var source = (
1247
1280
  /* wgsl */
1248
- `fn random(scale: vec3f, seed: float) -> f32 {
1249
- /* use the fragment position for a different seed per-pixel */
1250
- return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
1281
+ `fn random(scale: vec3f, seed: f32) -> f32 {
1282
+ return fract(sin(dot(scale + vec3f(seed), vec3f(12.9898, 78.233, 151.7182))) * 43758.5453 + seed);
1251
1283
  }
1252
1284
  `
1253
1285
  );
@@ -2487,8 +2519,102 @@ function getUniforms(opts = {}, prevUniforms) {
2487
2519
  return uniforms;
2488
2520
  }
2489
2521
 
2522
+ // dist/modules/engine/skin/skin.js
2523
+ var import_core2 = require("@math.gl/core");
2524
+ var SKIN_MAX_JOINTS = 20;
2525
+ var source2 = (
2526
+ /* wgsl */
2527
+ `
2528
+ struct skinUniforms {
2529
+ jointMatrix: array<mat4x4<f32>, ${SKIN_MAX_JOINTS}>,
2530
+ };
2531
+
2532
+ @binding(19) @group(0) var<uniform> skin: skinUniforms;
2533
+
2534
+ fn getSkinMatrix(weights: vec4f, joints: vec4u) -> mat4x4<f32> {
2535
+ return (weights.x * skin.jointMatrix[joints.x])
2536
+ + (weights.y * skin.jointMatrix[joints.y])
2537
+ + (weights.z * skin.jointMatrix[joints.z])
2538
+ + (weights.w * skin.jointMatrix[joints.w]);
2539
+ }
2540
+ `
2541
+ );
2542
+ var vs2 = (
2543
+ /* glsl */
2544
+ `
2545
+ uniform skinUniforms {
2546
+ mat4 jointMatrix[SKIN_MAX_JOINTS];
2547
+ } skin;
2548
+
2549
+ mat4 getSkinMatrix(vec4 weights, uvec4 joints) {
2550
+ return (weights.x * skin.jointMatrix[joints.x])
2551
+ + (weights.y * skin.jointMatrix[joints.y])
2552
+ + (weights.z * skin.jointMatrix[joints.z])
2553
+ + (weights.w * skin.jointMatrix[joints.w]);
2554
+ }
2555
+
2556
+ `
2557
+ );
2558
+ var fs3 = (
2559
+ /* glsl */
2560
+ ``
2561
+ );
2562
+ var skin = {
2563
+ props: {},
2564
+ uniforms: {},
2565
+ name: "skin",
2566
+ dependencies: [],
2567
+ source: source2,
2568
+ vs: vs2,
2569
+ fs: fs3,
2570
+ defines: {
2571
+ SKIN_MAX_JOINTS
2572
+ },
2573
+ getUniforms: (props = {}, prevUniforms) => {
2574
+ var _a, _b;
2575
+ const { scenegraphsFromGLTF } = props;
2576
+ if (!((_b = (_a = scenegraphsFromGLTF == null ? void 0 : scenegraphsFromGLTF.gltf) == null ? void 0 : _a.skins) == null ? void 0 : _b[0])) {
2577
+ return { jointMatrix: [] };
2578
+ }
2579
+ const { inverseBindMatrices, joints, skeleton } = scenegraphsFromGLTF.gltf.skins[0];
2580
+ const matsib = [];
2581
+ const countib = inverseBindMatrices.value.length / 16;
2582
+ for (let i = 0; i < countib; i++) {
2583
+ const slice = inverseBindMatrices.value.subarray(i * 16, i * 16 + 16);
2584
+ matsib.push(new import_core2.Matrix4(Array.from(slice)));
2585
+ }
2586
+ const top = scenegraphsFromGLTF.gltfNodeIndexToNodeMap.get(skeleton);
2587
+ const matrices = {};
2588
+ top.preorderTraversal((node, { worldMatrix }) => {
2589
+ matrices[node.id] = worldMatrix;
2590
+ });
2591
+ const mats = new Float32Array(SKIN_MAX_JOINTS * 16);
2592
+ for (let i = 0; i < SKIN_MAX_JOINTS; ++i) {
2593
+ const nodeIndex = joints[i];
2594
+ if (nodeIndex === void 0)
2595
+ break;
2596
+ const worldMat = matrices[scenegraphsFromGLTF.gltfNodeIndexToNodeMap.get(nodeIndex).id];
2597
+ const invBindMat = matsib[i];
2598
+ const Z = new import_core2.Matrix4().copy(worldMat).multiplyRight(invBindMat);
2599
+ const off = i * 16;
2600
+ for (let j = 0; j < 16; j++) {
2601
+ mats[off + j] = Z[j];
2602
+ }
2603
+ }
2604
+ return {
2605
+ jointMatrix: mats
2606
+ };
2607
+ },
2608
+ uniformTypes: {
2609
+ jointMatrix: "mat4x4<f32>"
2610
+ },
2611
+ uniformSizes: {
2612
+ jointMatrix: SKIN_MAX_JOINTS
2613
+ }
2614
+ };
2615
+
2490
2616
  // dist/modules/lighting/lights/lighting.js
2491
- var import_core2 = require("@luma.gl/core");
2617
+ var import_core3 = require("@luma.gl/core");
2492
2618
 
2493
2619
  // dist/modules/lighting/lights/lighting-glsl.js
2494
2620
  var lightingUniformsGLSL = (
@@ -2534,6 +2660,16 @@ uniform lightingUniforms {
2534
2660
  vec3 lightPosition2;
2535
2661
  vec3 lightDirection2;
2536
2662
  vec3 lightAttenuation2;
2663
+
2664
+ vec3 lightColor3;
2665
+ vec3 lightPosition3;
2666
+ vec3 lightDirection3;
2667
+ vec3 lightAttenuation3;
2668
+
2669
+ vec3 lightColor4;
2670
+ vec3 lightPosition4;
2671
+ vec3 lightDirection4;
2672
+ vec3 lightAttenuation4;
2537
2673
  } lighting;
2538
2674
 
2539
2675
  PointLight lighting_getPointLight(int index) {
@@ -2543,8 +2679,12 @@ PointLight lighting_getPointLight(int index) {
2543
2679
  case 1:
2544
2680
  return PointLight(lighting.lightColor1, lighting.lightPosition1, lighting.lightAttenuation1);
2545
2681
  case 2:
2546
- default:
2547
2682
  return PointLight(lighting.lightColor2, lighting.lightPosition2, lighting.lightAttenuation2);
2683
+ case 3:
2684
+ return PointLight(lighting.lightColor3, lighting.lightPosition3, lighting.lightAttenuation3);
2685
+ case 4:
2686
+ default:
2687
+ return PointLight(lighting.lightColor4, lighting.lightPosition4, lighting.lightAttenuation4);
2548
2688
  }
2549
2689
  }
2550
2690
 
@@ -2555,8 +2695,12 @@ DirectionalLight lighting_getDirectionalLight(int index) {
2555
2695
  case 1:
2556
2696
  return DirectionalLight(lighting.lightColor1, lighting.lightDirection1);
2557
2697
  case 2:
2558
- default:
2559
2698
  return DirectionalLight(lighting.lightColor2, lighting.lightDirection2);
2699
+ case 3:
2700
+ return DirectionalLight(lighting.lightColor3, lighting.lightDirection3);
2701
+ case 4:
2702
+ default:
2703
+ return DirectionalLight(lighting.lightColor4, lighting.lightDirection4);
2560
2704
  }
2561
2705
  }
2562
2706
 
@@ -2574,6 +2718,8 @@ float getPointLightAttenuation(PointLight pointLight, float distance) {
2574
2718
  var lightingUniformsWGSL = (
2575
2719
  /* wgsl */
2576
2720
  `// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))
2721
+ const MAX_LIGHTS: i32 = 5;
2722
+
2577
2723
  struct AmbientLight {
2578
2724
  color: vec3<f32>,
2579
2725
  };
@@ -2591,32 +2737,80 @@ struct DirectionalLight {
2591
2737
 
2592
2738
  struct lightingUniforms {
2593
2739
  enabled: i32,
2594
- pointLightCount: i32,
2740
+ lightType: i32,
2741
+
2595
2742
  directionalLightCount: i32,
2743
+ pointLightCount: i32,
2596
2744
 
2597
2745
  ambientColor: vec3<f32>,
2598
2746
 
2599
- // TODO - support multiple lights by uncommenting arrays below
2600
- lightType: i32,
2601
- lightColor: vec3<f32>,
2602
- lightDirection: vec3<f32>,
2603
- lightPosition: vec3<f32>,
2604
- lightAttenuation: vec3<f32>,
2605
-
2606
- // AmbientLight ambientLight;
2607
- // PointLight pointLight[MAX_LIGHTS];
2608
- // DirectionalLight directionalLight[MAX_LIGHTS];
2747
+ lightColor0: vec3<f32>,
2748
+ lightPosition0: vec3<f32>,
2749
+ lightDirection0: vec3<f32>,
2750
+ lightAttenuation0: vec3<f32>,
2751
+
2752
+ lightColor1: vec3<f32>,
2753
+ lightPosition1: vec3<f32>,
2754
+ lightDirection1: vec3<f32>,
2755
+ lightAttenuation1: vec3<f32>,
2756
+
2757
+ lightColor2: vec3<f32>,
2758
+ lightPosition2: vec3<f32>,
2759
+ lightDirection2: vec3<f32>,
2760
+ lightAttenuation2: vec3<f32>,
2761
+
2762
+ lightColor3: vec3<f32>,
2763
+ lightPosition3: vec3<f32>,
2764
+ lightDirection3: vec3<f32>,
2765
+ lightAttenuation3: vec3<f32>,
2766
+
2767
+ lightColor4: vec3<f32>,
2768
+ lightPosition4: vec3<f32>,
2769
+ lightDirection4: vec3<f32>,
2770
+ lightAttenuation4: vec3<f32>,
2609
2771
  };
2610
2772
 
2611
2773
  // Binding 0:1 is reserved for lighting (Note: could go into separate bind group as it is stable across draw calls)
2612
2774
  @binding(1) @group(0) var<uniform> lighting : lightingUniforms;
2613
2775
 
2614
2776
  fn lighting_getPointLight(index: i32) -> PointLight {
2615
- return PointLight(lighting.lightColor, lighting.lightPosition, lighting.lightAttenuation);
2777
+ switch (index) {
2778
+ case 0: {
2779
+ return PointLight(lighting.lightColor0, lighting.lightPosition0, lighting.lightAttenuation0);
2780
+ }
2781
+ case 1: {
2782
+ return PointLight(lighting.lightColor1, lighting.lightPosition1, lighting.lightAttenuation1);
2783
+ }
2784
+ case 2: {
2785
+ return PointLight(lighting.lightColor2, lighting.lightPosition2, lighting.lightAttenuation2);
2786
+ }
2787
+ case 3: {
2788
+ return PointLight(lighting.lightColor3, lighting.lightPosition3, lighting.lightAttenuation3);
2789
+ }
2790
+ case 4, default: {
2791
+ return PointLight(lighting.lightColor4, lighting.lightPosition4, lighting.lightAttenuation4);
2792
+ }
2793
+ }
2616
2794
  }
2617
2795
 
2618
2796
  fn lighting_getDirectionalLight(index: i32) -> DirectionalLight {
2619
- return DirectionalLight(lighting.lightColor, lighting.lightDirection);
2797
+ switch (index) {
2798
+ case 0: {
2799
+ return DirectionalLight(lighting.lightColor0, lighting.lightDirection0);
2800
+ }
2801
+ case 1: {
2802
+ return DirectionalLight(lighting.lightColor1, lighting.lightDirection1);
2803
+ }
2804
+ case 2: {
2805
+ return DirectionalLight(lighting.lightColor2, lighting.lightDirection2);
2806
+ }
2807
+ case 3: {
2808
+ return DirectionalLight(lighting.lightColor3, lighting.lightDirection3);
2809
+ }
2810
+ case 4, default: {
2811
+ return DirectionalLight(lighting.lightColor4, lighting.lightDirection4);
2812
+ }
2813
+ }
2620
2814
  }
2621
2815
 
2622
2816
  fn getPointLightAttenuation(pointLight: PointLight, distance: f32) -> f32 {
@@ -2661,7 +2855,15 @@ var lighting = {
2661
2855
  lightColor2: "vec3<f32>",
2662
2856
  lightPosition2: "vec3<f32>",
2663
2857
  lightDirection2: "vec3<f32>",
2664
- lightAttenuation2: "vec3<f32>"
2858
+ lightAttenuation2: "vec3<f32>",
2859
+ lightColor3: "vec3<f32>",
2860
+ lightPosition3: "vec3<f32>",
2861
+ lightDirection3: "vec3<f32>",
2862
+ lightAttenuation3: "vec3<f32>",
2863
+ lightColor4: "vec3<f32>",
2864
+ lightPosition4: "vec3<f32>",
2865
+ lightDirection4: "vec3<f32>",
2866
+ lightAttenuation4: "vec3<f32>"
2665
2867
  },
2666
2868
  defaultUniforms: {
2667
2869
  enabled: 1,
@@ -2681,7 +2883,15 @@ var lighting = {
2681
2883
  lightColor2: [1, 1, 1],
2682
2884
  lightPosition2: [1, 1, 2],
2683
2885
  lightDirection2: [1, 1, 1],
2684
- lightAttenuation2: [1, 0, 0]
2886
+ lightAttenuation2: [1, 0, 0],
2887
+ lightColor3: [1, 1, 1],
2888
+ lightPosition3: [1, 1, 2],
2889
+ lightDirection3: [1, 1, 1],
2890
+ lightAttenuation3: [1, 0, 0],
2891
+ lightColor4: [1, 1, 1],
2892
+ lightPosition4: [1, 1, 2],
2893
+ lightDirection4: [1, 1, 1],
2894
+ lightAttenuation4: [1, 0, 0]
2685
2895
  },
2686
2896
  source: lightingUniformsWGSL,
2687
2897
  vs: lightingUniformsGLSL,
@@ -2715,26 +2925,36 @@ function getLightSourceUniforms({ ambientLight, pointLights = [], directionalLig
2715
2925
  const lightSourceUniforms = {};
2716
2926
  lightSourceUniforms.ambientColor = convertColor(ambientLight);
2717
2927
  let currentLight = 0;
2928
+ let pointLightCount = 0;
2929
+ let directionalLightCount = 0;
2718
2930
  for (const pointLight of pointLights) {
2931
+ if (currentLight >= MAX_LIGHTS) {
2932
+ break;
2933
+ }
2719
2934
  lightSourceUniforms.lightType = LIGHT_TYPE.POINT;
2720
2935
  const i = currentLight;
2721
2936
  lightSourceUniforms[`lightColor${i}`] = convertColor(pointLight);
2722
2937
  lightSourceUniforms[`lightPosition${i}`] = pointLight.position;
2723
2938
  lightSourceUniforms[`lightAttenuation${i}`] = pointLight.attenuation || [1, 0, 0];
2724
2939
  currentLight++;
2940
+ pointLightCount++;
2725
2941
  }
2726
2942
  for (const directionalLight of directionalLights) {
2943
+ if (currentLight >= MAX_LIGHTS) {
2944
+ break;
2945
+ }
2727
2946
  lightSourceUniforms.lightType = LIGHT_TYPE.DIRECTIONAL;
2728
2947
  const i = currentLight;
2729
2948
  lightSourceUniforms[`lightColor${i}`] = convertColor(directionalLight);
2730
2949
  lightSourceUniforms[`lightDirection${i}`] = directionalLight.direction;
2731
2950
  currentLight++;
2951
+ directionalLightCount++;
2732
2952
  }
2733
- if (currentLight > MAX_LIGHTS) {
2734
- import_core2.log.warn("MAX_LIGHTS exceeded")();
2953
+ if (pointLights.length + directionalLights.length > MAX_LIGHTS) {
2954
+ import_core3.log.warn(`MAX_LIGHTS exceeded, truncating to ${MAX_LIGHTS}`)();
2735
2955
  }
2736
- lightSourceUniforms.directionalLightCount = directionalLights.length;
2737
- lightSourceUniforms.pointLightCount = pointLights.length;
2956
+ lightSourceUniforms.directionalLightCount = directionalLightCount;
2957
+ lightSourceUniforms.pointLightCount = pointLightCount;
2738
2958
  return lightSourceUniforms;
2739
2959
  }
2740
2960
  function extractLightTypes(lights) {
@@ -2943,56 +3163,60 @@ fn lighting_getLightColor2(surfaceColor: vec3<f32>, cameraPosition: vec3<f32>, p
2943
3163
  let view_direction: vec3<f32> = normalize(cameraPosition - position_worldspace);
2944
3164
  lightColor = phongMaterial.ambient * surfaceColor * lighting.ambientColor;
2945
3165
 
2946
- if (lighting.lightType == 0) {
2947
- let pointLight: PointLight = lighting_getPointLight(0);
3166
+ for (var i: i32 = 0; i < lighting.pointLightCount; i++) {
3167
+ let pointLight: PointLight = lighting_getPointLight(i);
2948
3168
  let light_position_worldspace: vec3<f32> = pointLight.position;
2949
3169
  let light_direction: vec3<f32> = normalize(light_position_worldspace - position_worldspace);
2950
- lightColor += lighting_getLightColor(surfaceColor, light_direction, view_direction, normal_worldspace, pointLight.color);
2951
- } else if (lighting.lightType == 1) {
2952
- var directionalLight: DirectionalLight = lighting_getDirectionalLight(0);
2953
- lightColor += lighting_getLightColor(surfaceColor, -directionalLight.direction, view_direction, normal_worldspace, directionalLight.color);
2954
- }
2955
-
2956
- return lightColor;
2957
- /*
2958
- for (int i = 0; i < MAX_LIGHTS; i++) {
2959
- if (i >= lighting.pointLightCount) {
2960
- break;
2961
- }
2962
- PointLight pointLight = lighting.pointLight[i];
2963
- vec3 light_position_worldspace = pointLight.position;
2964
- vec3 light_direction = normalize(light_position_worldspace - position_worldspace);
2965
- lightColor += lighting_getLightColor(surfaceColor, light_direction, view_direction, normal_worldspace, pointLight.color);
3170
+ let light_attenuation = getPointLightAttenuation(
3171
+ pointLight,
3172
+ distance(light_position_worldspace, position_worldspace)
3173
+ );
3174
+ lightColor += lighting_getLightColor(
3175
+ surfaceColor,
3176
+ light_direction,
3177
+ view_direction,
3178
+ normal_worldspace,
3179
+ pointLight.color / light_attenuation
3180
+ );
2966
3181
  }
2967
3182
 
2968
- for (int i = 0; i < MAX_LIGHTS; i++) {
2969
- if (i >= lighting.directionalLightCount) {
2970
- break;
2971
- }
2972
- DirectionalLight directionalLight = lighting.directionalLight[i];
3183
+ let totalLights = min(MAX_LIGHTS, lighting.pointLightCount + lighting.directionalLightCount);
3184
+ for (var i: i32 = lighting.pointLightCount; i < totalLights; i++) {
3185
+ let directionalLight: DirectionalLight = lighting_getDirectionalLight(i);
2973
3186
  lightColor += lighting_getLightColor(surfaceColor, -directionalLight.direction, view_direction, normal_worldspace, directionalLight.color);
2974
- }
2975
- */
3187
+ }
3188
+
3189
+ return lightColor;
2976
3190
  }
2977
3191
 
2978
3192
  fn lighting_getSpecularLightColor(cameraPosition: vec3<f32>, position_worldspace: vec3<f32>, normal_worldspace: vec3<f32>) -> vec3<f32>{
2979
3193
  var lightColor = vec3<f32>(0, 0, 0);
2980
3194
  let surfaceColor = vec3<f32>(0, 0, 0);
2981
3195
 
2982
- if (lighting.enabled == 0) {
3196
+ if (lighting.enabled != 0) {
2983
3197
  let view_direction = normalize(cameraPosition - position_worldspace);
2984
3198
 
2985
- switch (lighting.lightType) {
2986
- case 0, default: {
2987
- let pointLight: PointLight = lighting_getPointLight(0);
2988
- let light_position_worldspace: vec3<f32> = pointLight.position;
2989
- let light_direction: vec3<f32> = normalize(light_position_worldspace - position_worldspace);
2990
- lightColor += lighting_getLightColor(surfaceColor, light_direction, view_direction, normal_worldspace, pointLight.color);
2991
- }
2992
- case 1: {
2993
- let directionalLight: DirectionalLight = lighting_getDirectionalLight(0);
3199
+ for (var i: i32 = 0; i < lighting.pointLightCount; i++) {
3200
+ let pointLight: PointLight = lighting_getPointLight(i);
3201
+ let light_position_worldspace: vec3<f32> = pointLight.position;
3202
+ let light_direction: vec3<f32> = normalize(light_position_worldspace - position_worldspace);
3203
+ let light_attenuation = getPointLightAttenuation(
3204
+ pointLight,
3205
+ distance(light_position_worldspace, position_worldspace)
3206
+ );
3207
+ lightColor += lighting_getLightColor(
3208
+ surfaceColor,
3209
+ light_direction,
3210
+ view_direction,
3211
+ normal_worldspace,
3212
+ pointLight.color / light_attenuation
3213
+ );
3214
+ }
3215
+
3216
+ let totalLights = min(MAX_LIGHTS, lighting.pointLightCount + lighting.directionalLightCount);
3217
+ for (var i: i32 = lighting.pointLightCount; i < totalLights; i++) {
3218
+ let directionalLight: DirectionalLight = lighting_getDirectionalLight(i);
2994
3219
  lightColor += lighting_getLightColor(surfaceColor, -directionalLight.direction, view_direction, normal_worldspace, directionalLight.color);
2995
- }
2996
3220
  }
2997
3221
  }
2998
3222
  return lightColor;
@@ -3066,7 +3290,7 @@ var phongMaterial = {
3066
3290
  };
3067
3291
 
3068
3292
  // dist/modules/lighting/pbr-material/pbr-material-glsl.js
3069
- var vs2 = (
3293
+ var vs3 = (
3070
3294
  /* glsl */
3071
3295
  `out vec3 pbr_vPosition;
3072
3296
  out vec2 pbr_vUV;
@@ -3103,7 +3327,7 @@ void pbr_setPositionNormalTangentUV(vec4 position, vec4 normal, vec4 tangent, ve
3103
3327
  }
3104
3328
  `
3105
3329
  );
3106
- var fs3 = (
3330
+ var fs4 = (
3107
3331
  /* glsl */
3108
3332
  `precision highp float;
3109
3333
 
@@ -3567,56 +3791,60 @@ vec4 pbr_filterColor(vec4 colorUnused)
3567
3791
  );
3568
3792
 
3569
3793
  // dist/modules/lighting/pbr-material/pbr-material-wgsl.js
3570
- var source2 = (
3794
+ var source3 = (
3571
3795
  /* wgsl */
3572
3796
  `struct PBRFragmentInputs {
3573
3797
  pbr_vPosition: vec3f,
3574
3798
  pbr_vUV: vec2f,
3575
- pbr_vTBN: mat3f,
3799
+ pbr_vTBN: mat3x3f,
3576
3800
  pbr_vNormal: vec3f
3577
3801
  };
3578
3802
 
3579
- var fragmentInputs: PBRFragmentInputs;
3803
+ var<private> fragmentInputs: PBRFragmentInputs;
3580
3804
 
3581
3805
  fn pbr_setPositionNormalTangentUV(position: vec4f, normal: vec4f, tangent: vec4f, uv: vec2f)
3582
3806
  {
3583
3807
  var pos: vec4f = pbrProjection.modelMatrix * position;
3584
- fragmentInputs.pbr_vPosition = vec3(pos.xyz) / pos.w;
3808
+ fragmentInputs.pbr_vPosition = pos.xyz / pos.w;
3809
+ fragmentInputs.pbr_vNormal = vec3f(0.0, 0.0, 1.0);
3810
+ fragmentInputs.pbr_vTBN = mat3x3f(
3811
+ vec3f(1.0, 0.0, 0.0),
3812
+ vec3f(0.0, 1.0, 0.0),
3813
+ vec3f(0.0, 0.0, 1.0)
3814
+ );
3815
+ fragmentInputs.pbr_vUV = vec2f(0.0, 0.0);
3585
3816
 
3586
3817
  #ifdef HAS_NORMALS
3818
+ let normalW: vec3f = normalize((pbrProjection.normalMatrix * vec4f(normal.xyz, 0.0)).xyz);
3819
+ fragmentInputs.pbr_vNormal = normalW;
3587
3820
  #ifdef HAS_TANGENTS
3588
- let normalW: vec3f = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));
3589
- let tangentW: vec3f = normalize(vec3(pbrProjection.modelMatrix * vec4(tangent.xyz, 0.0)));
3821
+ let tangentW: vec3f = normalize((pbrProjection.modelMatrix * vec4f(tangent.xyz, 0.0)).xyz);
3590
3822
  let bitangentW: vec3f = cross(normalW, tangentW) * tangent.w;
3591
- fragmentInputs.pbr_vTBN = mat3(tangentW, bitangentW, normalW);
3592
- #else // HAS_TANGENTS != 1
3593
- fragmentInputs.pbr_vNormal = normalize(vec3(pbrProjection.modelMatrix * vec4(normal.xyz, 0.0)));
3823
+ fragmentInputs.pbr_vTBN = mat3x3f(tangentW, bitangentW, normalW);
3594
3824
  #endif
3595
3825
  #endif
3596
3826
 
3597
3827
  #ifdef HAS_UV
3598
3828
  fragmentInputs.pbr_vUV = uv;
3599
- #else
3600
- fragmentInputs.pbr_vUV = vec2(0.,0.);
3601
3829
  #endif
3602
3830
  }
3603
3831
 
3604
3832
  struct pbrMaterialUniforms {
3605
3833
  // Material is unlit
3606
- unlit: uint32,
3834
+ unlit: u32,
3607
3835
 
3608
3836
  // Base color map
3609
- baseColorMapEnabled: uint32,
3837
+ baseColorMapEnabled: u32,
3610
3838
  baseColorFactor: vec4f,
3611
3839
 
3612
- normalMapEnabled : uint32,
3840
+ normalMapEnabled : u32,
3613
3841
  normalScale: f32, // #ifdef HAS_NORMALMAP
3614
3842
 
3615
- emissiveMapEnabled: uint32,
3843
+ emissiveMapEnabled: u32,
3616
3844
  emissiveFactor: vec3f, // #ifdef HAS_EMISSIVEMAP
3617
3845
 
3618
3846
  metallicRoughnessValues: vec2f,
3619
- metallicRoughnessMapEnabled: uint32,
3847
+ metallicRoughnessMapEnabled: u32,
3620
3848
 
3621
3849
  occlusionMapEnabled: i32,
3622
3850
  occlusionStrength: f32, // #ifdef HAS_OCCLUSIONMAP
@@ -3631,7 +3859,7 @@ struct pbrMaterialUniforms {
3631
3859
  // debugging flags used for shader output of intermediate PBR variables
3632
3860
  // #ifdef PBR_DEBUG
3633
3861
  scaleDiffBaseMR: vec4f,
3634
- scaleFGDSpec: vec4f
3862
+ scaleFGDSpec: vec4f,
3635
3863
  // #endif
3636
3864
  }
3637
3865
 
@@ -3639,24 +3867,32 @@ struct pbrMaterialUniforms {
3639
3867
 
3640
3868
  // Samplers
3641
3869
  #ifdef HAS_BASECOLORMAP
3642
- uniform sampler2D pbr_baseColorSampler;
3870
+ @binding(3) @group(0) var pbr_baseColorSampler: texture_2d<f32>;
3871
+ @binding(4) @group(0) var pbr_baseColorSamplerSampler: sampler;
3643
3872
  #endif
3644
3873
  #ifdef HAS_NORMALMAP
3645
- uniform sampler2D pbr_normalSampler;
3874
+ @binding(5) @group(0) var pbr_normalSampler: texture_2d<f32>;
3875
+ @binding(6) @group(0) var pbr_normalSamplerSampler: sampler;
3646
3876
  #endif
3647
3877
  #ifdef HAS_EMISSIVEMAP
3648
- uniform sampler2D pbr_emissiveSampler;
3878
+ @binding(7) @group(0) var pbr_emissiveSampler: texture_2d<f32>;
3879
+ @binding(8) @group(0) var pbr_emissiveSamplerSampler: sampler;
3649
3880
  #endif
3650
3881
  #ifdef HAS_METALROUGHNESSMAP
3651
- uniform sampler2D pbr_metallicRoughnessSampler;
3882
+ @binding(9) @group(0) var pbr_metallicRoughnessSampler: texture_2d<f32>;
3883
+ @binding(10) @group(0) var pbr_metallicRoughnessSamplerSampler: sampler;
3652
3884
  #endif
3653
3885
  #ifdef HAS_OCCLUSIONMAP
3654
- uniform sampler2D pbr_occlusionSampler;
3886
+ @binding(11) @group(0) var pbr_occlusionSampler: texture_2d<f32>;
3887
+ @binding(12) @group(0) var pbr_occlusionSamplerSampler: sampler;
3655
3888
  #endif
3656
3889
  #ifdef USE_IBL
3657
- uniform samplerCube pbr_diffuseEnvSampler;
3658
- uniform samplerCube pbr_specularEnvSampler;
3659
- uniform sampler2D pbr_brdfLUT;
3890
+ @binding(13) @group(0) var pbr_diffuseEnvSampler: texture_cube<f32>;
3891
+ @binding(14) @group(0) var pbr_diffuseEnvSamplerSampler: sampler;
3892
+ @binding(15) @group(0) var pbr_specularEnvSampler: texture_cube<f32>;
3893
+ @binding(16) @group(0) var pbr_specularEnvSamplerSampler: sampler;
3894
+ @binding(17) @group(0) var pbr_BrdfLUT: texture_2d<f32>;
3895
+ @binding(18) @group(0) var pbr_BrdfLUTSampler: sampler;
3660
3896
  #endif
3661
3897
 
3662
3898
  // Encapsulate the various inputs used by the various functions in the shading equation
@@ -3684,17 +3920,19 @@ const c_MinRoughness = 0.04;
3684
3920
 
3685
3921
  fn SRGBtoLINEAR(srgbIn: vec4f ) -> vec4f
3686
3922
  {
3923
+ var linOut: vec3f = srgbIn.xyz;
3687
3924
  #ifdef MANUAL_SRGB
3925
+ let bLess: vec3f = step(vec3f(0.04045), srgbIn.xyz);
3926
+ linOut = mix(
3927
+ srgbIn.xyz / vec3f(12.92),
3928
+ pow((srgbIn.xyz + vec3f(0.055)) / vec3f(1.055), vec3f(2.4)),
3929
+ bLess
3930
+ );
3688
3931
  #ifdef SRGB_FAST_APPROXIMATION
3689
- var linOut: vec3f = pow(srgbIn.xyz,vec3(2.2));
3690
- #else // SRGB_FAST_APPROXIMATION
3691
- var bLess: vec3f = step(vec3(0.04045),srgbIn.xyz);
3692
- var linOut: vec3f = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess );
3693
- #endif //SRGB_FAST_APPROXIMATION
3694
- return vec4f(linOut,srgbIn.w);;
3695
- #else //MANUAL_SRGB
3696
- return srgbIn;
3697
- #endif //MANUAL_SRGB
3932
+ linOut = pow(srgbIn.xyz, vec3f(2.2));
3933
+ #endif
3934
+ #endif
3935
+ return vec4f(linOut, srgbIn.w);
3698
3936
  }
3699
3937
 
3700
3938
  // Find the normal for this fragment, pulling either from a predefined normal map
@@ -3702,32 +3940,28 @@ fn SRGBtoLINEAR(srgbIn: vec4f ) -> vec4f
3702
3940
  fn getNormal() -> vec3f
3703
3941
  {
3704
3942
  // Retrieve the tangent space matrix
3705
- #ifndef HAS_TANGENTS
3706
- var pos_dx: vec3f = dFdx(fragmentInputs.pbr_vPosition);
3707
- var pos_dy: vec3f = dFdy(fragmentInputs.pbr_vPosition);
3708
- var tex_dx: vec3f = dFdx(vec3(fragmentInputs.pbr_vUV, 0.0));
3709
- var tex_dy: vec3f = dFdy(vec3(fragmentInputs.pbr_vUV, 0.0));
3710
- 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);
3943
+ let pos_dx: vec3f = dpdx(fragmentInputs.pbr_vPosition);
3944
+ let pos_dy: vec3f = dpdy(fragmentInputs.pbr_vPosition);
3945
+ let tex_dx: vec3f = dpdx(vec3f(fragmentInputs.pbr_vUV, 0.0));
3946
+ let tex_dy: vec3f = dpdy(vec3f(fragmentInputs.pbr_vUV, 0.0));
3947
+ 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);
3711
3948
 
3712
- #ifdef HAS_NORMALS
3713
- var ng: vec3f = normalize(fragmentInputs.pbr_vNormal);
3714
- #else
3715
3949
  var ng: vec3f = cross(pos_dx, pos_dy);
3950
+ #ifdef HAS_NORMALS
3951
+ ng = normalize(fragmentInputs.pbr_vNormal);
3716
3952
  #endif
3717
-
3718
3953
  t = normalize(t - ng * dot(ng, t));
3719
3954
  var b: vec3f = normalize(cross(ng, t));
3720
- var tbn: mat3f = mat3f(t, b, ng);
3721
- #else // HAS_TANGENTS
3722
- var tbn: mat3f = fragmentInputs.pbr_vTBN;
3955
+ var tbn: mat3x3f = mat3x3f(t, b, ng);
3956
+ #ifdef HAS_TANGENTS
3957
+ tbn = fragmentInputs.pbr_vTBN;
3723
3958
  #endif
3724
3959
 
3725
- #ifdef HAS_NORMALMAP
3726
- vec3 n = texture(pbr_normalSampler, fragmentInputs.pbr_vUV).rgb;
3727
- n = normalize(tbn * ((2.0 * n - 1.0) * vec3(pbrMaterial.normalScale, pbrMaterial.normalScale, 1.0)));
3728
- #else
3729
3960
  // The tbn matrix is linearly interpolated, so we need to re-normalize
3730
- vec3 n = normalize(tbn[2].xyz);
3961
+ var n: vec3f = normalize(tbn[2].xyz);
3962
+ #ifdef HAS_NORMALMAP
3963
+ n = textureSample(pbr_normalSampler, pbr_normalSamplerSampler, fragmentInputs.pbr_vUV).rgb;
3964
+ n = normalize(tbn * ((2.0 * n - 1.0) * vec3f(pbrMaterial.normalScale, pbrMaterial.normalScale, 1.0)));
3731
3965
  #endif
3732
3966
 
3733
3967
  return n;
@@ -3737,27 +3971,37 @@ fn getNormal() -> vec3f
3737
3971
  // Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
3738
3972
  // See our README.md on Environment Maps [3] for additional discussion.
3739
3973
  #ifdef USE_IBL
3740
- fn getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection) -> vec3f
3974
+ fn getIBLContribution(pbrInfo: PBRInfo, n: vec3f, reflection: vec3f) -> vec3f
3741
3975
  {
3742
- float mipCount = 9.0; // resolution of 512x512
3743
- float lod = (pbrInfo.perceptualRoughness * mipCount);
3976
+ let mipCount: f32 = 9.0; // resolution of 512x512
3977
+ let lod: f32 = pbrInfo.perceptualRoughness * mipCount;
3744
3978
  // retrieve a scale and bias to F0. See [1], Figure 3
3745
- vec3 brdf = SRGBtoLINEAR(texture(pbr_brdfLUT,
3746
- vec2(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness))).rgb;
3747
- vec3 diffuseLight = SRGBtoLINEAR(texture(pbr_diffuseEnvSampler, n)).rgb;
3748
-
3979
+ let brdf = SRGBtoLINEAR(
3980
+ textureSample(
3981
+ pbr_BrdfLUT,
3982
+ pbr_BrdfLUTSampler,
3983
+ vec2f(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness)
3984
+ )
3985
+ ).rgb;
3986
+ let diffuseLight =
3987
+ SRGBtoLINEAR(textureSample(pbr_diffuseEnvSampler, pbr_diffuseEnvSamplerSampler, n)).rgb;
3988
+ let specularLightDefault =
3989
+ SRGBtoLINEAR(textureSample(pbr_specularEnvSampler, pbr_specularEnvSamplerSampler, reflection)).rgb;
3990
+ var specularLight = specularLightDefault;
3749
3991
  #ifdef USE_TEX_LOD
3750
- vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection, lod)).rgb;
3751
- #else
3752
- vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection)).rgb;
3992
+ specularLight = SRGBtoLINEAR(
3993
+ textureSampleLevel(
3994
+ pbr_specularEnvSampler,
3995
+ pbr_specularEnvSamplerSampler,
3996
+ reflection,
3997
+ lod
3998
+ )
3999
+ ).rgb;
3753
4000
  #endif
3754
4001
 
3755
- vec3 diffuse = diffuseLight * pbrInfo.diffuseColor;
3756
- vec3 specular = specularLight * (pbrInfo.specularColor * brdf.x + brdf.y);
3757
-
3758
- // For presentation, this allows us to disable IBL terms
3759
- diffuse *= pbrMaterial.scaleIBLAmbient.x;
3760
- specular *= pbrMaterial.scaleIBLAmbient.y;
4002
+ let diffuse = diffuseLight * pbrInfo.diffuseColor * pbrMaterial.scaleIBLAmbient.x;
4003
+ let specular =
4004
+ specularLight * (pbrInfo.specularColor * brdf.x + brdf.y) * pbrMaterial.scaleIBLAmbient.y;
3761
4005
 
3762
4006
  return diffuse + specular;
3763
4007
  }
@@ -3801,7 +4045,7 @@ fn geometricOcclusion(pbrInfo: PBRInfo) -> f32 {
3801
4045
  fn microfacetDistribution(pbrInfo: PBRInfo) -> f32 {
3802
4046
  let roughnessSq = pbrInfo.alphaRoughness * pbrInfo.alphaRoughness;
3803
4047
  let f = (pbrInfo.NdotH * roughnessSq - pbrInfo.NdotH) * pbrInfo.NdotH + 1.0;
3804
- return roughnessSq / (PI * f * f);
4048
+ return roughnessSq / (M_PI * f * f);
3805
4049
  }
3806
4050
 
3807
4051
  fn PBRInfo_setAmbientLight(pbrInfo: ptr<function, PBRInfo>) {
@@ -3843,11 +4087,11 @@ fn calculateFinalColor(pbrInfo: PBRInfo, lightColor: vec3<f32>) -> vec3<f32> {
3843
4087
 
3844
4088
  fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3845
4089
  // The albedo may be defined from a base texture or a flat color
3846
- var baseColor: vec4<f32>;
4090
+ var baseColor: vec4<f32> = pbrMaterial.baseColorFactor;
3847
4091
  #ifdef HAS_BASECOLORMAP
3848
- baseColor = SRGBtoLINEAR(textureSample(pbr_baseColorSampler, pbr_baseColorSampler, fragmentInputs.pbr_vUV)) * pbrMaterial.baseColorFactor;
3849
- #else
3850
- baseColor = pbrMaterial.baseColorFactor;
4092
+ baseColor = SRGBtoLINEAR(
4093
+ textureSample(pbr_baseColorSampler, pbr_baseColorSamplerSampler, fragmentInputs.pbr_vUV)
4094
+ ) * pbrMaterial.baseColorFactor;
3851
4095
  #endif
3852
4096
 
3853
4097
  #ifdef ALPHA_CUTOFF
@@ -3858,7 +4102,7 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3858
4102
 
3859
4103
  var color = vec3<f32>(0.0, 0.0, 0.0);
3860
4104
 
3861
- if (pbrMaterial.unlit) {
4105
+ if (pbrMaterial.unlit != 0u) {
3862
4106
  color = baseColor.rgb;
3863
4107
  } else {
3864
4108
  // Metallic and Roughness material properties are packed together
@@ -3869,7 +4113,11 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3869
4113
  #ifdef HAS_METALROUGHNESSMAP
3870
4114
  // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
3871
4115
  // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
3872
- let mrSample = textureSample(pbr_metallicRoughnessSampler, pbr_metallicRoughnessSampler, fragmentInputs.pbr_vUV);
4116
+ let mrSample = textureSample(
4117
+ pbr_metallicRoughnessSampler,
4118
+ pbr_metallicRoughnessSamplerSampler,
4119
+ fragmentInputs.pbr_vUV
4120
+ );
3873
4121
  perceptualRoughness = mrSample.g * perceptualRoughness;
3874
4122
  metallic = mrSample.b * metallic;
3875
4123
  #endif
@@ -3946,22 +4194,25 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3946
4194
 
3947
4195
  // Calculate lighting contribution from image based lighting source (IBL)
3948
4196
  #ifdef USE_IBL
3949
- if (pbrMaterial.IBLenabled) {
4197
+ if (pbrMaterial.IBLenabled != 0) {
3950
4198
  color += getIBLContribution(pbrInfo, n, reflection);
3951
4199
  }
3952
4200
  #endif
3953
4201
 
3954
4202
  // Apply optional PBR terms for additional (optional) shading
3955
4203
  #ifdef HAS_OCCLUSIONMAP
3956
- if (pbrMaterial.occlusionMapEnabled) {
3957
- let ao = textureSample(pbr_occlusionSampler, pbr_occlusionSampler, fragmentInputs.pbr_vUV).r;
4204
+ if (pbrMaterial.occlusionMapEnabled != 0) {
4205
+ let ao =
4206
+ textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, fragmentInputs.pbr_vUV).r;
3958
4207
  color = mix(color, color * ao, pbrMaterial.occlusionStrength);
3959
4208
  }
3960
4209
  #endif
3961
4210
 
3962
4211
  #ifdef HAS_EMISSIVEMAP
3963
- if (pbrMaterial.emissiveMapEnabled) {
3964
- let emissive = SRGBtoLINEAR(textureSample(pbr_emissiveSampler, pbr_emissiveSampler, fragmentInputs.pbr_vUV)).rgb * pbrMaterial.emissiveFactor;
4212
+ if (pbrMaterial.emissiveMapEnabled != 0u) {
4213
+ let emissive = SRGBtoLINEAR(
4214
+ textureSample(pbr_emissiveSampler, pbr_emissiveSamplerSampler, fragmentInputs.pbr_vUV)
4215
+ ).rgb * pbrMaterial.emissiveFactor;
3965
4216
  color += emissive;
3966
4217
  }
3967
4218
  #endif
@@ -3999,8 +4250,21 @@ var uniformBlock = (
3999
4250
  } pbrProjection;
4000
4251
  `
4001
4252
  );
4253
+ var wgslUniformBlock = (
4254
+ /* wgsl */
4255
+ `struct pbrProjectionUniforms {
4256
+ modelViewProjectionMatrix: mat4x4<f32>,
4257
+ modelMatrix: mat4x4<f32>,
4258
+ normalMatrix: mat4x4<f32>,
4259
+ camera: vec3<f32>
4260
+ };
4261
+
4262
+ @binding(0) @group(0) var<uniform> pbrProjection: pbrProjectionUniforms;
4263
+ `
4264
+ );
4002
4265
  var pbrProjection = {
4003
4266
  name: "pbrProjection",
4267
+ source: wgslUniformBlock,
4004
4268
  vs: uniformBlock,
4005
4269
  fs: uniformBlock,
4006
4270
  // TODO why is this needed?
@@ -4009,7 +4273,7 @@ var pbrProjection = {
4009
4273
  modelViewProjectionMatrix: "mat4x4<f32>",
4010
4274
  modelMatrix: "mat4x4<f32>",
4011
4275
  normalMatrix: "mat4x4<f32>",
4012
- camera: "vec3<i32>"
4276
+ camera: "vec3<f32>"
4013
4277
  }
4014
4278
  };
4015
4279
 
@@ -4019,9 +4283,9 @@ var pbrMaterial = {
4019
4283
  uniforms: {},
4020
4284
  name: "pbrMaterial",
4021
4285
  dependencies: [lighting, pbrProjection],
4022
- source: source2,
4023
- vs: vs2,
4024
- fs: fs3,
4286
+ source: source3,
4287
+ vs: vs3,
4288
+ fs: fs4,
4025
4289
  defines: {
4026
4290
  LIGHTING_FRAGMENT: true,
4027
4291
  HAS_NORMALMAP: false,