@luma.gl/shadertools 9.3.0-alpha.4 → 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 (62) hide show
  1. package/dist/dist.dev.js +2111 -197
  2. package/dist/dist.min.js +315 -184
  3. package/dist/index.cjs +459 -198
  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/modules/engine/skin/skin.d.ts +29 -0
  18. package/dist/modules/engine/skin/skin.d.ts.map +1 -0
  19. package/dist/modules/engine/skin/skin.js +88 -0
  20. package/dist/modules/engine/skin/skin.js.map +1 -0
  21. package/dist/modules/lighting/lights/lighting-glsl.d.ts +1 -1
  22. package/dist/modules/lighting/lights/lighting-glsl.d.ts.map +1 -1
  23. package/dist/modules/lighting/lights/lighting-glsl.js +20 -2
  24. package/dist/modules/lighting/lights/lighting-glsl.js.map +1 -1
  25. package/dist/modules/lighting/lights/lighting-wgsl.d.ts +1 -1
  26. package/dist/modules/lighting/lights/lighting-wgsl.d.ts.map +1 -1
  27. package/dist/modules/lighting/lights/lighting-wgsl.js +63 -13
  28. package/dist/modules/lighting/lights/lighting-wgsl.js.map +1 -1
  29. package/dist/modules/lighting/lights/lighting.d.ts +27 -3
  30. package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
  31. package/dist/modules/lighting/lights/lighting.js +32 -6
  32. package/dist/modules/lighting/lights/lighting.js.map +1 -1
  33. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +1 -1
  34. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
  35. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +106 -79
  36. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
  37. package/dist/modules/lighting/pbr-material/pbr-material.d.ts +20 -4
  38. package/dist/modules/lighting/pbr-material/pbr-material.d.ts.map +1 -1
  39. package/dist/modules/lighting/pbr-material/pbr-projection.d.ts.map +1 -1
  40. package/dist/modules/lighting/pbr-material/pbr-projection.js +12 -1
  41. package/dist/modules/lighting/pbr-material/pbr-projection.js.map +1 -1
  42. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts +1 -40
  43. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts.map +1 -1
  44. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js +40 -76
  45. package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js.map +1 -1
  46. package/dist/modules/math/random/random.d.ts +1 -1
  47. package/dist/modules/math/random/random.d.ts.map +1 -1
  48. package/dist/modules/math/random/random.js +2 -3
  49. package/dist/modules/math/random/random.js.map +1 -1
  50. package/package.json +2 -2
  51. package/src/index.ts +1 -0
  52. package/src/lib/preprocessor/preprocessor.ts +40 -7
  53. package/src/lib/shader-assembler.ts +8 -1
  54. package/src/lib/shader-module/shader-module.ts +1 -1
  55. package/src/modules/engine/skin/skin.ts +116 -0
  56. package/src/modules/lighting/lights/lighting-glsl.ts +20 -2
  57. package/src/modules/lighting/lights/lighting-wgsl.ts +63 -13
  58. package/src/modules/lighting/lights/lighting.ts +45 -9
  59. package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +106 -79
  60. package/src/modules/lighting/pbr-material/pbr-projection.ts +13 -1
  61. package/src/modules/lighting/phong-material/phong-shaders-wgsl.ts +40 -77
  62. 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
@@ -204,7 +205,7 @@ function getHookStage(hook) {
204
205
  throw new Error(type);
205
206
  }
206
207
  }
207
- function injectShader(source3, stage, inject, injectStandardStubs = false) {
208
+ function injectShader(source4, stage, inject, injectStandardStubs = false) {
208
209
  const isVertex = stage === "vertex";
209
210
  for (const key in inject) {
210
211
  const fragmentData = inject[key];
@@ -218,43 +219,43 @@ function injectShader(source3, stage, inject, injectStandardStubs = false) {
218
219
  switch (key) {
219
220
  case "vs:#decl":
220
221
  if (isVertex) {
221
- source3 = source3.replace(DECLARATION_INJECT_MARKER, fragmentString);
222
+ source4 = source4.replace(DECLARATION_INJECT_MARKER, fragmentString);
222
223
  }
223
224
  break;
224
225
  case "vs:#main-start":
225
226
  if (isVertex) {
226
- source3 = source3.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
227
+ source4 = source4.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
227
228
  }
228
229
  break;
229
230
  case "vs:#main-end":
230
231
  if (isVertex) {
231
- source3 = source3.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
232
+ source4 = source4.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
232
233
  }
233
234
  break;
234
235
  case "fs:#decl":
235
236
  if (!isVertex) {
236
- source3 = source3.replace(DECLARATION_INJECT_MARKER, fragmentString);
237
+ source4 = source4.replace(DECLARATION_INJECT_MARKER, fragmentString);
237
238
  }
238
239
  break;
239
240
  case "fs:#main-start":
240
241
  if (!isVertex) {
241
- source3 = source3.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
242
+ source4 = source4.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
242
243
  }
243
244
  break;
244
245
  case "fs:#main-end":
245
246
  if (!isVertex) {
246
- source3 = source3.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
247
+ source4 = source4.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
247
248
  }
248
249
  break;
249
250
  default:
250
- source3 = source3.replace(key, (match) => match + fragmentString);
251
+ source4 = source4.replace(key, (match) => match + fragmentString);
251
252
  }
252
253
  }
253
- source3 = source3.replace(DECLARATION_INJECT_MARKER, "");
254
+ source4 = source4.replace(DECLARATION_INJECT_MARKER, "");
254
255
  if (injectStandardStubs) {
255
- source3 = source3.replace(/\}\s*$/, (match) => match + MODULE_INJECTORS[stage]);
256
+ source4 = source4.replace(/\}\s*$/, (match) => match + MODULE_INJECTORS[stage]);
256
257
  }
257
- return source3;
258
+ return source4;
258
259
  }
259
260
  function combineInjects(injects) {
260
261
  const result = {};
@@ -434,19 +435,19 @@ function getPlatformShaderDefines(platformInfo) {
434
435
  }
435
436
 
436
437
  // dist/lib/shader-transpiler/transpile-glsl-shader.js
437
- function transpileGLSLShader(source3, stage) {
438
+ function transpileGLSLShader(source4, stage) {
438
439
  var _a;
439
- 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);
440
441
  if (sourceGLSLVersion !== 300) {
441
442
  throw new Error("luma.gl v9 only supports GLSL 3.00 shader sources");
442
443
  }
443
444
  switch (stage) {
444
445
  case "vertex":
445
- source3 = convertShader(source3, ES300_VERTEX_REPLACEMENTS);
446
- return source3;
446
+ source4 = convertShader(source4, ES300_VERTEX_REPLACEMENTS);
447
+ return source4;
447
448
  case "fragment":
448
- source3 = convertShader(source3, ES300_FRAGMENT_REPLACEMENTS);
449
- return source3;
449
+ source4 = convertShader(source4, ES300_FRAGMENT_REPLACEMENTS);
450
+ return source4;
450
451
  default:
451
452
  throw new Error(stage);
452
453
  }
@@ -470,11 +471,11 @@ var ES300_FRAGMENT_REPLACEMENTS = [
470
471
  // `varying` keyword replaced with `in`
471
472
  [makeVariableTextRegExp("varying"), "in $1"]
472
473
  ];
473
- function convertShader(source3, replacements) {
474
+ function convertShader(source4, replacements) {
474
475
  for (const [pattern, replacement] of replacements) {
475
- source3 = source3.replace(pattern, replacement);
476
+ source4 = source4.replace(pattern, replacement);
476
477
  }
477
- return source3;
478
+ return source4;
478
479
  }
479
480
  function makeVariableTextRegExp(qualifier) {
480
481
  return new RegExp(`\\b${qualifier}[ \\t]+(\\w+[ \\t]+\\w+(\\[\\w+\\])?;)`, "g");
@@ -536,11 +537,11 @@ function normalizeShaderHooks(hookFunctions) {
536
537
  }
537
538
 
538
539
  // dist/lib/glsl-utils/get-shader-info.js
539
- function getShaderInfo(source3, defaultName) {
540
+ function getShaderInfo(source4, defaultName) {
540
541
  return {
541
- name: getShaderName(source3, defaultName),
542
+ name: getShaderName(source4, defaultName),
542
543
  language: "glsl",
543
- version: getShaderVersion(source3)
544
+ version: getShaderVersion(source4)
544
545
  };
545
546
  }
546
547
  function getShaderName(shader, defaultName = "unnamed") {
@@ -548,9 +549,9 @@ function getShaderName(shader, defaultName = "unnamed") {
548
549
  const match = SHADER_NAME_REGEXP.exec(shader);
549
550
  return match ? match[1] : defaultName;
550
551
  }
551
- function getShaderVersion(source3) {
552
+ function getShaderVersion(source4) {
552
553
  let version = 100;
553
- const words = source3.match(/[^\s]+/g);
554
+ const words = source4.match(/[^\s]+/g);
554
555
  if (words && words.length >= 2 && words[0] === "#version") {
555
556
  const parsedVersion = parseInt(words[1], 10);
556
557
  if (Number.isFinite(parsedVersion)) {
@@ -586,19 +587,19 @@ function assembleWGSLShader(options) {
586
587
  };
587
588
  }
588
589
  function assembleGLSLShaderPair(options) {
589
- const { vs: vs3, fs: fs4 } = options;
590
+ const { vs: vs4, fs: fs5 } = options;
590
591
  const modules = getShaderModuleDependencies(options.modules || []);
591
592
  return {
592
593
  vs: assembleShaderGLSL(options.platformInfo, {
593
594
  ...options,
594
- source: vs3,
595
+ source: vs4,
595
596
  stage: "vertex",
596
597
  modules
597
598
  }),
598
599
  fs: assembleShaderGLSL(options.platformInfo, {
599
600
  ...options,
600
601
  // @ts-expect-error
601
- source: fs4,
602
+ source: fs5,
602
603
  stage: "fragment",
603
604
  modules
604
605
  }),
@@ -609,7 +610,7 @@ function assembleShaderWGSL(platformInfo, options) {
609
610
  var _a;
610
611
  const {
611
612
  // id,
612
- source: source3,
613
+ source: source4,
613
614
  stage,
614
615
  modules,
615
616
  // defines = {},
@@ -617,8 +618,8 @@ function assembleShaderWGSL(platformInfo, options) {
617
618
  inject = {},
618
619
  log: log2
619
620
  } = options;
620
- assert(typeof source3 === "string", "shader source must be a string");
621
- const coreSource = source3;
621
+ assert(typeof source4 === "string", "shader source must be a string");
622
+ const coreSource = source4;
622
623
  let assembledSource = "";
623
624
  const hookFunctionMap = normalizeShaderHooks(hookFunctions);
624
625
  const hookInjections = {};
@@ -673,12 +674,12 @@ function assembleShaderWGSL(platformInfo, options) {
673
674
  }
674
675
  function assembleShaderGLSL(platformInfo, options) {
675
676
  var _a;
676
- const { source: source3, stage, language = "glsl", modules, defines = {}, hookFunctions = [], inject = {}, prologue = true, log: log2 } = options;
677
- assert(typeof source3 === "string", "shader source must be a string");
678
- 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;
679
680
  const targetVersion = platformInfo.shaderLanguageVersion;
680
681
  const sourceVersionDirective = sourceVersion === 100 ? "#version 100" : "#version 300 es";
681
- const sourceLines = source3.split("\n");
682
+ const sourceLines = source4.split("\n");
682
683
  const coreSource = sourceLines.slice(1).join("\n");
683
684
  const allDefines = {};
684
685
  modules.forEach((module2) => {
@@ -801,39 +802,61 @@ function getShaderModuleSource(module2, stage) {
801
802
  throw new Error("Shader module must have a name");
802
803
  }
803
804
  const moduleName = module2.name.toUpperCase().replace(/[^0-9a-z]/gi, "_");
804
- let source3 = `// ----- MODULE ${module2.name} ---------------
805
+ let source4 = `// ----- MODULE ${module2.name} ---------------
805
806
 
806
807
  `;
807
808
  if (stage !== "wgsl") {
808
- source3 += `#define MODULE_${moduleName}
809
+ source4 += `#define MODULE_${moduleName}
809
810
  `;
810
811
  }
811
- source3 += `${moduleSource}
812
+ source4 += `${moduleSource}
812
813
  `;
813
- return source3;
814
+ return source4;
814
815
  }
815
816
 
816
817
  // dist/lib/preprocessor/preprocessor.js
817
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*(?:\/\/.*)?$/;
818
821
  var ENDIF_REGEXP = /^\s*\#\s*endif\s*$/;
819
- function preprocess(source3, options) {
820
- var _a;
821
- 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");
822
827
  const output = [];
828
+ const conditionalStack = [];
823
829
  let conditional = true;
824
- let currentDefine = null;
825
830
  for (const line of lines) {
826
- const matchIf = line.match(IFDEF_REGEXP);
827
- const matchEnd = line.match(ENDIF_REGEXP);
828
- if (matchIf) {
829
- currentDefine = matchIf[1];
830
- 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;
831
850
  } else if (matchEnd) {
832
- conditional = true;
851
+ conditionalStack.pop();
852
+ conditional = conditionalStack.length ? conditionalStack[conditionalStack.length - 1].active : true;
833
853
  } else if (conditional) {
834
854
  output.push(line);
835
855
  }
836
856
  }
857
+ if (conditionalStack.length > 0) {
858
+ throw new Error("Unterminated conditional block in shader source");
859
+ }
837
860
  return output.join("\n");
838
861
  }
839
862
 
@@ -886,14 +909,21 @@ var _ShaderAssembler = class {
886
909
  assembleWGSLShader(props) {
887
910
  const modules = this._getModuleList(props.modules);
888
911
  const hookFunctions = this._hookFunctions;
889
- const { source: source3, getUniforms: getUniforms4 } = assembleWGSLShader({
912
+ const { source: source4, getUniforms: getUniforms4 } = assembleWGSLShader({
890
913
  ...props,
891
914
  // @ts-expect-error
892
915
  source: props.source,
893
916
  modules,
894
917
  hookFunctions
895
918
  });
896
- 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;
897
927
  return { source: preprocessedSource, getUniforms: getUniforms4, modules };
898
928
  }
899
929
  /**
@@ -1248,9 +1278,8 @@ function fp64ifyMatrix4(matrix) {
1248
1278
  // dist/modules/math/random/random.js
1249
1279
  var source = (
1250
1280
  /* wgsl */
1251
- `fn random(scale: vec3f, seed: float) -> f32 {
1252
- /* use the fragment position for a different seed per-pixel */
1253
- 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);
1254
1283
  }
1255
1284
  `
1256
1285
  );
@@ -2490,8 +2519,102 @@ function getUniforms(opts = {}, prevUniforms) {
2490
2519
  return uniforms;
2491
2520
  }
2492
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
+
2493
2616
  // dist/modules/lighting/lights/lighting.js
2494
- var import_core2 = require("@luma.gl/core");
2617
+ var import_core3 = require("@luma.gl/core");
2495
2618
 
2496
2619
  // dist/modules/lighting/lights/lighting-glsl.js
2497
2620
  var lightingUniformsGLSL = (
@@ -2537,6 +2660,16 @@ uniform lightingUniforms {
2537
2660
  vec3 lightPosition2;
2538
2661
  vec3 lightDirection2;
2539
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;
2540
2673
  } lighting;
2541
2674
 
2542
2675
  PointLight lighting_getPointLight(int index) {
@@ -2546,8 +2679,12 @@ PointLight lighting_getPointLight(int index) {
2546
2679
  case 1:
2547
2680
  return PointLight(lighting.lightColor1, lighting.lightPosition1, lighting.lightAttenuation1);
2548
2681
  case 2:
2549
- default:
2550
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);
2551
2688
  }
2552
2689
  }
2553
2690
 
@@ -2558,8 +2695,12 @@ DirectionalLight lighting_getDirectionalLight(int index) {
2558
2695
  case 1:
2559
2696
  return DirectionalLight(lighting.lightColor1, lighting.lightDirection1);
2560
2697
  case 2:
2561
- default:
2562
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);
2563
2704
  }
2564
2705
  }
2565
2706
 
@@ -2577,6 +2718,8 @@ float getPointLightAttenuation(PointLight pointLight, float distance) {
2577
2718
  var lightingUniformsWGSL = (
2578
2719
  /* wgsl */
2579
2720
  `// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))
2721
+ const MAX_LIGHTS: i32 = 5;
2722
+
2580
2723
  struct AmbientLight {
2581
2724
  color: vec3<f32>,
2582
2725
  };
@@ -2594,32 +2737,80 @@ struct DirectionalLight {
2594
2737
 
2595
2738
  struct lightingUniforms {
2596
2739
  enabled: i32,
2597
- pointLightCount: i32,
2740
+ lightType: i32,
2741
+
2598
2742
  directionalLightCount: i32,
2743
+ pointLightCount: i32,
2599
2744
 
2600
2745
  ambientColor: vec3<f32>,
2601
2746
 
2602
- // TODO - support multiple lights by uncommenting arrays below
2603
- lightType: i32,
2604
- lightColor: vec3<f32>,
2605
- lightDirection: vec3<f32>,
2606
- lightPosition: vec3<f32>,
2607
- lightAttenuation: vec3<f32>,
2608
-
2609
- // AmbientLight ambientLight;
2610
- // PointLight pointLight[MAX_LIGHTS];
2611
- // 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>,
2612
2771
  };
2613
2772
 
2614
2773
  // Binding 0:1 is reserved for lighting (Note: could go into separate bind group as it is stable across draw calls)
2615
2774
  @binding(1) @group(0) var<uniform> lighting : lightingUniforms;
2616
2775
 
2617
2776
  fn lighting_getPointLight(index: i32) -> PointLight {
2618
- 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
+ }
2619
2794
  }
2620
2795
 
2621
2796
  fn lighting_getDirectionalLight(index: i32) -> DirectionalLight {
2622
- 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
+ }
2623
2814
  }
2624
2815
 
2625
2816
  fn getPointLightAttenuation(pointLight: PointLight, distance: f32) -> f32 {
@@ -2664,7 +2855,15 @@ var lighting = {
2664
2855
  lightColor2: "vec3<f32>",
2665
2856
  lightPosition2: "vec3<f32>",
2666
2857
  lightDirection2: "vec3<f32>",
2667
- 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>"
2668
2867
  },
2669
2868
  defaultUniforms: {
2670
2869
  enabled: 1,
@@ -2684,7 +2883,15 @@ var lighting = {
2684
2883
  lightColor2: [1, 1, 1],
2685
2884
  lightPosition2: [1, 1, 2],
2686
2885
  lightDirection2: [1, 1, 1],
2687
- 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]
2688
2895
  },
2689
2896
  source: lightingUniformsWGSL,
2690
2897
  vs: lightingUniformsGLSL,
@@ -2718,26 +2925,36 @@ function getLightSourceUniforms({ ambientLight, pointLights = [], directionalLig
2718
2925
  const lightSourceUniforms = {};
2719
2926
  lightSourceUniforms.ambientColor = convertColor(ambientLight);
2720
2927
  let currentLight = 0;
2928
+ let pointLightCount = 0;
2929
+ let directionalLightCount = 0;
2721
2930
  for (const pointLight of pointLights) {
2931
+ if (currentLight >= MAX_LIGHTS) {
2932
+ break;
2933
+ }
2722
2934
  lightSourceUniforms.lightType = LIGHT_TYPE.POINT;
2723
2935
  const i = currentLight;
2724
2936
  lightSourceUniforms[`lightColor${i}`] = convertColor(pointLight);
2725
2937
  lightSourceUniforms[`lightPosition${i}`] = pointLight.position;
2726
2938
  lightSourceUniforms[`lightAttenuation${i}`] = pointLight.attenuation || [1, 0, 0];
2727
2939
  currentLight++;
2940
+ pointLightCount++;
2728
2941
  }
2729
2942
  for (const directionalLight of directionalLights) {
2943
+ if (currentLight >= MAX_LIGHTS) {
2944
+ break;
2945
+ }
2730
2946
  lightSourceUniforms.lightType = LIGHT_TYPE.DIRECTIONAL;
2731
2947
  const i = currentLight;
2732
2948
  lightSourceUniforms[`lightColor${i}`] = convertColor(directionalLight);
2733
2949
  lightSourceUniforms[`lightDirection${i}`] = directionalLight.direction;
2734
2950
  currentLight++;
2951
+ directionalLightCount++;
2735
2952
  }
2736
- if (currentLight > MAX_LIGHTS) {
2737
- 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}`)();
2738
2955
  }
2739
- lightSourceUniforms.directionalLightCount = directionalLights.length;
2740
- lightSourceUniforms.pointLightCount = pointLights.length;
2956
+ lightSourceUniforms.directionalLightCount = directionalLightCount;
2957
+ lightSourceUniforms.pointLightCount = pointLightCount;
2741
2958
  return lightSourceUniforms;
2742
2959
  }
2743
2960
  function extractLightTypes(lights) {
@@ -2946,56 +3163,60 @@ fn lighting_getLightColor2(surfaceColor: vec3<f32>, cameraPosition: vec3<f32>, p
2946
3163
  let view_direction: vec3<f32> = normalize(cameraPosition - position_worldspace);
2947
3164
  lightColor = phongMaterial.ambient * surfaceColor * lighting.ambientColor;
2948
3165
 
2949
- if (lighting.lightType == 0) {
2950
- let pointLight: PointLight = lighting_getPointLight(0);
3166
+ for (var i: i32 = 0; i < lighting.pointLightCount; i++) {
3167
+ let pointLight: PointLight = lighting_getPointLight(i);
2951
3168
  let light_position_worldspace: vec3<f32> = pointLight.position;
2952
3169
  let light_direction: vec3<f32> = normalize(light_position_worldspace - position_worldspace);
2953
- lightColor += lighting_getLightColor(surfaceColor, light_direction, view_direction, normal_worldspace, pointLight.color);
2954
- } else if (lighting.lightType == 1) {
2955
- var directionalLight: DirectionalLight = lighting_getDirectionalLight(0);
2956
- lightColor += lighting_getLightColor(surfaceColor, -directionalLight.direction, view_direction, normal_worldspace, directionalLight.color);
2957
- }
2958
-
2959
- return lightColor;
2960
- /*
2961
- for (int i = 0; i < MAX_LIGHTS; i++) {
2962
- if (i >= lighting.pointLightCount) {
2963
- break;
2964
- }
2965
- PointLight pointLight = lighting.pointLight[i];
2966
- vec3 light_position_worldspace = pointLight.position;
2967
- vec3 light_direction = normalize(light_position_worldspace - position_worldspace);
2968
- 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
+ );
2969
3181
  }
2970
3182
 
2971
- for (int i = 0; i < MAX_LIGHTS; i++) {
2972
- if (i >= lighting.directionalLightCount) {
2973
- break;
2974
- }
2975
- 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);
2976
3186
  lightColor += lighting_getLightColor(surfaceColor, -directionalLight.direction, view_direction, normal_worldspace, directionalLight.color);
2977
- }
2978
- */
3187
+ }
3188
+
3189
+ return lightColor;
2979
3190
  }
2980
3191
 
2981
3192
  fn lighting_getSpecularLightColor(cameraPosition: vec3<f32>, position_worldspace: vec3<f32>, normal_worldspace: vec3<f32>) -> vec3<f32>{
2982
3193
  var lightColor = vec3<f32>(0, 0, 0);
2983
3194
  let surfaceColor = vec3<f32>(0, 0, 0);
2984
3195
 
2985
- if (lighting.enabled == 0) {
3196
+ if (lighting.enabled != 0) {
2986
3197
  let view_direction = normalize(cameraPosition - position_worldspace);
2987
3198
 
2988
- switch (lighting.lightType) {
2989
- case 0, default: {
2990
- let pointLight: PointLight = lighting_getPointLight(0);
2991
- let light_position_worldspace: vec3<f32> = pointLight.position;
2992
- let light_direction: vec3<f32> = normalize(light_position_worldspace - position_worldspace);
2993
- lightColor += lighting_getLightColor(surfaceColor, light_direction, view_direction, normal_worldspace, pointLight.color);
2994
- }
2995
- case 1: {
2996
- 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);
2997
3219
  lightColor += lighting_getLightColor(surfaceColor, -directionalLight.direction, view_direction, normal_worldspace, directionalLight.color);
2998
- }
2999
3220
  }
3000
3221
  }
3001
3222
  return lightColor;
@@ -3069,7 +3290,7 @@ var phongMaterial = {
3069
3290
  };
3070
3291
 
3071
3292
  // dist/modules/lighting/pbr-material/pbr-material-glsl.js
3072
- var vs2 = (
3293
+ var vs3 = (
3073
3294
  /* glsl */
3074
3295
  `out vec3 pbr_vPosition;
3075
3296
  out vec2 pbr_vUV;
@@ -3106,7 +3327,7 @@ void pbr_setPositionNormalTangentUV(vec4 position, vec4 normal, vec4 tangent, ve
3106
3327
  }
3107
3328
  `
3108
3329
  );
3109
- var fs3 = (
3330
+ var fs4 = (
3110
3331
  /* glsl */
3111
3332
  `precision highp float;
3112
3333
 
@@ -3570,56 +3791,60 @@ vec4 pbr_filterColor(vec4 colorUnused)
3570
3791
  );
3571
3792
 
3572
3793
  // dist/modules/lighting/pbr-material/pbr-material-wgsl.js
3573
- var source2 = (
3794
+ var source3 = (
3574
3795
  /* wgsl */
3575
3796
  `struct PBRFragmentInputs {
3576
3797
  pbr_vPosition: vec3f,
3577
3798
  pbr_vUV: vec2f,
3578
- pbr_vTBN: mat3f,
3799
+ pbr_vTBN: mat3x3f,
3579
3800
  pbr_vNormal: vec3f
3580
3801
  };
3581
3802
 
3582
- var fragmentInputs: PBRFragmentInputs;
3803
+ var<private> fragmentInputs: PBRFragmentInputs;
3583
3804
 
3584
3805
  fn pbr_setPositionNormalTangentUV(position: vec4f, normal: vec4f, tangent: vec4f, uv: vec2f)
3585
3806
  {
3586
3807
  var pos: vec4f = pbrProjection.modelMatrix * position;
3587
- 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);
3588
3816
 
3589
3817
  #ifdef HAS_NORMALS
3818
+ let normalW: vec3f = normalize((pbrProjection.normalMatrix * vec4f(normal.xyz, 0.0)).xyz);
3819
+ fragmentInputs.pbr_vNormal = normalW;
3590
3820
  #ifdef HAS_TANGENTS
3591
- let normalW: vec3f = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));
3592
- 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);
3593
3822
  let bitangentW: vec3f = cross(normalW, tangentW) * tangent.w;
3594
- fragmentInputs.pbr_vTBN = mat3(tangentW, bitangentW, normalW);
3595
- #else // HAS_TANGENTS != 1
3596
- fragmentInputs.pbr_vNormal = normalize(vec3(pbrProjection.modelMatrix * vec4(normal.xyz, 0.0)));
3823
+ fragmentInputs.pbr_vTBN = mat3x3f(tangentW, bitangentW, normalW);
3597
3824
  #endif
3598
3825
  #endif
3599
3826
 
3600
3827
  #ifdef HAS_UV
3601
3828
  fragmentInputs.pbr_vUV = uv;
3602
- #else
3603
- fragmentInputs.pbr_vUV = vec2(0.,0.);
3604
3829
  #endif
3605
3830
  }
3606
3831
 
3607
3832
  struct pbrMaterialUniforms {
3608
3833
  // Material is unlit
3609
- unlit: uint32,
3834
+ unlit: u32,
3610
3835
 
3611
3836
  // Base color map
3612
- baseColorMapEnabled: uint32,
3837
+ baseColorMapEnabled: u32,
3613
3838
  baseColorFactor: vec4f,
3614
3839
 
3615
- normalMapEnabled : uint32,
3840
+ normalMapEnabled : u32,
3616
3841
  normalScale: f32, // #ifdef HAS_NORMALMAP
3617
3842
 
3618
- emissiveMapEnabled: uint32,
3843
+ emissiveMapEnabled: u32,
3619
3844
  emissiveFactor: vec3f, // #ifdef HAS_EMISSIVEMAP
3620
3845
 
3621
3846
  metallicRoughnessValues: vec2f,
3622
- metallicRoughnessMapEnabled: uint32,
3847
+ metallicRoughnessMapEnabled: u32,
3623
3848
 
3624
3849
  occlusionMapEnabled: i32,
3625
3850
  occlusionStrength: f32, // #ifdef HAS_OCCLUSIONMAP
@@ -3634,7 +3859,7 @@ struct pbrMaterialUniforms {
3634
3859
  // debugging flags used for shader output of intermediate PBR variables
3635
3860
  // #ifdef PBR_DEBUG
3636
3861
  scaleDiffBaseMR: vec4f,
3637
- scaleFGDSpec: vec4f
3862
+ scaleFGDSpec: vec4f,
3638
3863
  // #endif
3639
3864
  }
3640
3865
 
@@ -3642,24 +3867,32 @@ struct pbrMaterialUniforms {
3642
3867
 
3643
3868
  // Samplers
3644
3869
  #ifdef HAS_BASECOLORMAP
3645
- uniform sampler2D pbr_baseColorSampler;
3870
+ @binding(3) @group(0) var pbr_baseColorSampler: texture_2d<f32>;
3871
+ @binding(4) @group(0) var pbr_baseColorSamplerSampler: sampler;
3646
3872
  #endif
3647
3873
  #ifdef HAS_NORMALMAP
3648
- uniform sampler2D pbr_normalSampler;
3874
+ @binding(5) @group(0) var pbr_normalSampler: texture_2d<f32>;
3875
+ @binding(6) @group(0) var pbr_normalSamplerSampler: sampler;
3649
3876
  #endif
3650
3877
  #ifdef HAS_EMISSIVEMAP
3651
- uniform sampler2D pbr_emissiveSampler;
3878
+ @binding(7) @group(0) var pbr_emissiveSampler: texture_2d<f32>;
3879
+ @binding(8) @group(0) var pbr_emissiveSamplerSampler: sampler;
3652
3880
  #endif
3653
3881
  #ifdef HAS_METALROUGHNESSMAP
3654
- uniform sampler2D pbr_metallicRoughnessSampler;
3882
+ @binding(9) @group(0) var pbr_metallicRoughnessSampler: texture_2d<f32>;
3883
+ @binding(10) @group(0) var pbr_metallicRoughnessSamplerSampler: sampler;
3655
3884
  #endif
3656
3885
  #ifdef HAS_OCCLUSIONMAP
3657
- uniform sampler2D pbr_occlusionSampler;
3886
+ @binding(11) @group(0) var pbr_occlusionSampler: texture_2d<f32>;
3887
+ @binding(12) @group(0) var pbr_occlusionSamplerSampler: sampler;
3658
3888
  #endif
3659
3889
  #ifdef USE_IBL
3660
- uniform samplerCube pbr_diffuseEnvSampler;
3661
- uniform samplerCube pbr_specularEnvSampler;
3662
- 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;
3663
3896
  #endif
3664
3897
 
3665
3898
  // Encapsulate the various inputs used by the various functions in the shading equation
@@ -3687,17 +3920,19 @@ const c_MinRoughness = 0.04;
3687
3920
 
3688
3921
  fn SRGBtoLINEAR(srgbIn: vec4f ) -> vec4f
3689
3922
  {
3923
+ var linOut: vec3f = srgbIn.xyz;
3690
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
+ );
3691
3931
  #ifdef SRGB_FAST_APPROXIMATION
3692
- var linOut: vec3f = pow(srgbIn.xyz,vec3(2.2));
3693
- #else // SRGB_FAST_APPROXIMATION
3694
- var bLess: vec3f = step(vec3(0.04045),srgbIn.xyz);
3695
- var linOut: vec3f = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess );
3696
- #endif //SRGB_FAST_APPROXIMATION
3697
- return vec4f(linOut,srgbIn.w);;
3698
- #else //MANUAL_SRGB
3699
- return srgbIn;
3700
- #endif //MANUAL_SRGB
3932
+ linOut = pow(srgbIn.xyz, vec3f(2.2));
3933
+ #endif
3934
+ #endif
3935
+ return vec4f(linOut, srgbIn.w);
3701
3936
  }
3702
3937
 
3703
3938
  // Find the normal for this fragment, pulling either from a predefined normal map
@@ -3705,32 +3940,28 @@ fn SRGBtoLINEAR(srgbIn: vec4f ) -> vec4f
3705
3940
  fn getNormal() -> vec3f
3706
3941
  {
3707
3942
  // Retrieve the tangent space matrix
3708
- #ifndef HAS_TANGENTS
3709
- var pos_dx: vec3f = dFdx(fragmentInputs.pbr_vPosition);
3710
- var pos_dy: vec3f = dFdy(fragmentInputs.pbr_vPosition);
3711
- var tex_dx: vec3f = dFdx(vec3(fragmentInputs.pbr_vUV, 0.0));
3712
- var tex_dy: vec3f = dFdy(vec3(fragmentInputs.pbr_vUV, 0.0));
3713
- 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);
3714
3948
 
3715
- #ifdef HAS_NORMALS
3716
- var ng: vec3f = normalize(fragmentInputs.pbr_vNormal);
3717
- #else
3718
3949
  var ng: vec3f = cross(pos_dx, pos_dy);
3950
+ #ifdef HAS_NORMALS
3951
+ ng = normalize(fragmentInputs.pbr_vNormal);
3719
3952
  #endif
3720
-
3721
3953
  t = normalize(t - ng * dot(ng, t));
3722
3954
  var b: vec3f = normalize(cross(ng, t));
3723
- var tbn: mat3f = mat3f(t, b, ng);
3724
- #else // HAS_TANGENTS
3725
- var tbn: mat3f = fragmentInputs.pbr_vTBN;
3955
+ var tbn: mat3x3f = mat3x3f(t, b, ng);
3956
+ #ifdef HAS_TANGENTS
3957
+ tbn = fragmentInputs.pbr_vTBN;
3726
3958
  #endif
3727
3959
 
3728
- #ifdef HAS_NORMALMAP
3729
- vec3 n = texture(pbr_normalSampler, fragmentInputs.pbr_vUV).rgb;
3730
- n = normalize(tbn * ((2.0 * n - 1.0) * vec3(pbrMaterial.normalScale, pbrMaterial.normalScale, 1.0)));
3731
- #else
3732
3960
  // The tbn matrix is linearly interpolated, so we need to re-normalize
3733
- 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)));
3734
3965
  #endif
3735
3966
 
3736
3967
  return n;
@@ -3740,27 +3971,37 @@ fn getNormal() -> vec3f
3740
3971
  // Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
3741
3972
  // See our README.md on Environment Maps [3] for additional discussion.
3742
3973
  #ifdef USE_IBL
3743
- fn getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection) -> vec3f
3974
+ fn getIBLContribution(pbrInfo: PBRInfo, n: vec3f, reflection: vec3f) -> vec3f
3744
3975
  {
3745
- float mipCount = 9.0; // resolution of 512x512
3746
- float lod = (pbrInfo.perceptualRoughness * mipCount);
3976
+ let mipCount: f32 = 9.0; // resolution of 512x512
3977
+ let lod: f32 = pbrInfo.perceptualRoughness * mipCount;
3747
3978
  // retrieve a scale and bias to F0. See [1], Figure 3
3748
- vec3 brdf = SRGBtoLINEAR(texture(pbr_brdfLUT,
3749
- vec2(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness))).rgb;
3750
- vec3 diffuseLight = SRGBtoLINEAR(texture(pbr_diffuseEnvSampler, n)).rgb;
3751
-
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;
3752
3991
  #ifdef USE_TEX_LOD
3753
- vec3 specularLight = SRGBtoLINEAR(texture(pbr_specularEnvSampler, reflection, lod)).rgb;
3754
- #else
3755
- 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;
3756
4000
  #endif
3757
4001
 
3758
- vec3 diffuse = diffuseLight * pbrInfo.diffuseColor;
3759
- vec3 specular = specularLight * (pbrInfo.specularColor * brdf.x + brdf.y);
3760
-
3761
- // For presentation, this allows us to disable IBL terms
3762
- diffuse *= pbrMaterial.scaleIBLAmbient.x;
3763
- 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;
3764
4005
 
3765
4006
  return diffuse + specular;
3766
4007
  }
@@ -3804,7 +4045,7 @@ fn geometricOcclusion(pbrInfo: PBRInfo) -> f32 {
3804
4045
  fn microfacetDistribution(pbrInfo: PBRInfo) -> f32 {
3805
4046
  let roughnessSq = pbrInfo.alphaRoughness * pbrInfo.alphaRoughness;
3806
4047
  let f = (pbrInfo.NdotH * roughnessSq - pbrInfo.NdotH) * pbrInfo.NdotH + 1.0;
3807
- return roughnessSq / (PI * f * f);
4048
+ return roughnessSq / (M_PI * f * f);
3808
4049
  }
3809
4050
 
3810
4051
  fn PBRInfo_setAmbientLight(pbrInfo: ptr<function, PBRInfo>) {
@@ -3846,11 +4087,11 @@ fn calculateFinalColor(pbrInfo: PBRInfo, lightColor: vec3<f32>) -> vec3<f32> {
3846
4087
 
3847
4088
  fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3848
4089
  // The albedo may be defined from a base texture or a flat color
3849
- var baseColor: vec4<f32>;
4090
+ var baseColor: vec4<f32> = pbrMaterial.baseColorFactor;
3850
4091
  #ifdef HAS_BASECOLORMAP
3851
- baseColor = SRGBtoLINEAR(textureSample(pbr_baseColorSampler, pbr_baseColorSampler, fragmentInputs.pbr_vUV)) * pbrMaterial.baseColorFactor;
3852
- #else
3853
- baseColor = pbrMaterial.baseColorFactor;
4092
+ baseColor = SRGBtoLINEAR(
4093
+ textureSample(pbr_baseColorSampler, pbr_baseColorSamplerSampler, fragmentInputs.pbr_vUV)
4094
+ ) * pbrMaterial.baseColorFactor;
3854
4095
  #endif
3855
4096
 
3856
4097
  #ifdef ALPHA_CUTOFF
@@ -3861,7 +4102,7 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3861
4102
 
3862
4103
  var color = vec3<f32>(0.0, 0.0, 0.0);
3863
4104
 
3864
- if (pbrMaterial.unlit) {
4105
+ if (pbrMaterial.unlit != 0u) {
3865
4106
  color = baseColor.rgb;
3866
4107
  } else {
3867
4108
  // Metallic and Roughness material properties are packed together
@@ -3872,7 +4113,11 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3872
4113
  #ifdef HAS_METALROUGHNESSMAP
3873
4114
  // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
3874
4115
  // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
3875
- 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
+ );
3876
4121
  perceptualRoughness = mrSample.g * perceptualRoughness;
3877
4122
  metallic = mrSample.b * metallic;
3878
4123
  #endif
@@ -3949,22 +4194,25 @@ fn pbr_filterColor(colorUnused: vec4<f32>) -> vec4<f32> {
3949
4194
 
3950
4195
  // Calculate lighting contribution from image based lighting source (IBL)
3951
4196
  #ifdef USE_IBL
3952
- if (pbrMaterial.IBLenabled) {
4197
+ if (pbrMaterial.IBLenabled != 0) {
3953
4198
  color += getIBLContribution(pbrInfo, n, reflection);
3954
4199
  }
3955
4200
  #endif
3956
4201
 
3957
4202
  // Apply optional PBR terms for additional (optional) shading
3958
4203
  #ifdef HAS_OCCLUSIONMAP
3959
- if (pbrMaterial.occlusionMapEnabled) {
3960
- 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;
3961
4207
  color = mix(color, color * ao, pbrMaterial.occlusionStrength);
3962
4208
  }
3963
4209
  #endif
3964
4210
 
3965
4211
  #ifdef HAS_EMISSIVEMAP
3966
- if (pbrMaterial.emissiveMapEnabled) {
3967
- 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;
3968
4216
  color += emissive;
3969
4217
  }
3970
4218
  #endif
@@ -4002,8 +4250,21 @@ var uniformBlock = (
4002
4250
  } pbrProjection;
4003
4251
  `
4004
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
+ );
4005
4265
  var pbrProjection = {
4006
4266
  name: "pbrProjection",
4267
+ source: wgslUniformBlock,
4007
4268
  vs: uniformBlock,
4008
4269
  fs: uniformBlock,
4009
4270
  // TODO why is this needed?
@@ -4012,7 +4273,7 @@ var pbrProjection = {
4012
4273
  modelViewProjectionMatrix: "mat4x4<f32>",
4013
4274
  modelMatrix: "mat4x4<f32>",
4014
4275
  normalMatrix: "mat4x4<f32>",
4015
- camera: "vec3<i32>"
4276
+ camera: "vec3<f32>"
4016
4277
  }
4017
4278
  };
4018
4279
 
@@ -4022,9 +4283,9 @@ var pbrMaterial = {
4022
4283
  uniforms: {},
4023
4284
  name: "pbrMaterial",
4024
4285
  dependencies: [lighting, pbrProjection],
4025
- source: source2,
4026
- vs: vs2,
4027
- fs: fs3,
4286
+ source: source3,
4287
+ vs: vs3,
4288
+ fs: fs4,
4028
4289
  defines: {
4029
4290
  LIGHTING_FRAGMENT: true,
4030
4291
  HAS_NORMALMAP: false,