@needle-tools/materialx 1.0.1-next.b9467c8 → 1.0.1-next.b9638d9

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.
package/README.md CHANGED
@@ -1,10 +1,5 @@
1
1
  # Needle MaterialX
2
2
 
3
- Load and display MaterialX materials in Needle Engine
4
-
5
- ## Installation
6
- `npm i @needle-tools/materialx`
7
-
8
3
  ## How to use
9
4
 
10
5
  To use with Needle Engine simply import the module
@@ -2,9 +2,5 @@
2
2
  import { TypeStore } from "@needle-tools/engine"
3
3
 
4
4
  // Import types
5
- import { MaterialXMaterial } from "../src/materialx.material.js";
6
- import { MaterialXUniformUpdate } from "../src/loader/loader.needle.js";
7
5
 
8
6
  // Register types
9
- TypeStore.add("MaterialXMaterial", MaterialXMaterial);
10
- TypeStore.add("MaterialXUniformUpdate", MaterialXUniformUpdate);
package/index.ts CHANGED
@@ -2,4 +2,4 @@ import { registerNeedleLoader } from "./src/loader/loader.needle.js";
2
2
 
3
3
  registerNeedleLoader();
4
4
 
5
- export { ready, getMaterialXEnvironment } from "./src/index.js";
5
+ export { initializeMaterialX, getMaterialXEnvironment } from "./src/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/materialx",
3
- "version": "1.0.1-next.b9467c8",
3
+ "version": "1.0.1-next.b9638d9",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "exports": {
@@ -8,11 +8,7 @@
8
8
  "import": "./index.ts",
9
9
  "require": "./index.js"
10
10
  },
11
- "./package.json": "./package.json",
12
- "./codegen/register_types.ts": {
13
- "import": "./codegen/register_types.ts",
14
- "require": "./codegen/register_types.js"
15
- }
11
+ "./package.json": "./package.json"
16
12
  },
17
13
  "peerDependencies": {
18
14
  "@needle-tools/engine": "4.x",
@@ -27,16 +23,5 @@
27
23
  "publishConfig": {
28
24
  "access": "public",
29
25
  "registry": "https://registry.npmjs.org/"
30
- },
31
- "keywords": [
32
- "needle",
33
- "materialx",
34
- "material",
35
- "shader",
36
- "threejs",
37
- "three.js",
38
- "webgl",
39
- "mtlx",
40
- "rendering"
41
- ]
26
+ }
42
27
  }
@@ -3,10 +3,10 @@
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  //
5
5
 
6
- import { getParam, getWorldDirection } from '@needle-tools/engine';
6
+ import { getParam } from '@needle-tools/engine';
7
7
  import * as THREE from 'three';
8
- import { debug, debugUpdate } from './utils';
9
- import { MaterialX } from './materialx.types';
8
+
9
+ const debug = getParam("debugmaterialx");
10
10
 
11
11
  const IMAGE_PROPERTY_SEPARATOR = "_";
12
12
  const UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "uaddressmode";
@@ -20,7 +20,8 @@ const IMAGE_PATH_SEPARATOR = "/";
20
20
  * @param {Object} capabilities
21
21
  * @returns {THREE.Texture}
22
22
  */
23
- export function prepareEnvTexture(texture, capabilities) {
23
+ export function prepareEnvTexture(texture, capabilities)
24
+ {
24
25
  let newTexture = new THREE.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type);
25
26
  newTexture.wrapS = THREE.RepeatWrapping;
26
27
  newTexture.anisotropy = capabilities.getMaxAnisotropy();
@@ -38,12 +39,15 @@ export function prepareEnvTexture(texture, capabilities) {
38
39
  * @param {any} dimension
39
40
  * @returns {THREE.Uniform}
40
41
  */
41
- function fromVector(value, dimension) {
42
+ function fromVector(value, dimension)
43
+ {
42
44
  let outValue;
43
- if (value) {
45
+ if (value)
46
+ {
44
47
  outValue = [...value.data()];
45
48
  }
46
- else {
49
+ else
50
+ {
47
51
  outValue = [];
48
52
  for (let i = 0; i < dimension; ++i)
49
53
  outValue.push(0.0);
@@ -54,16 +58,23 @@ function fromVector(value, dimension) {
54
58
 
55
59
  /**
56
60
  * Get Three uniform from MaterialX matrix
61
+ * @param {mx.matrix} matrix
62
+ * @param {mx.matrix.size} dimension
57
63
  */
58
- function fromMatrix(matrix: MaterialX.Matrix, dimension: MaterialX.Matrix["size"]) {
59
- const vec = new Array(dimension);
60
- if (matrix) {
61
- for (let i = 0; i < matrix.numRows(); ++i) {
62
- for (let k = 0; k < matrix.numColumns(); ++k) {
64
+ function fromMatrix(matrix, dimension)
65
+ {
66
+ let vec = [];
67
+ if (matrix)
68
+ {
69
+ for (let i = 0; i < matrix.numRows(); ++i)
70
+ {
71
+ for (let k = 0; k < matrix.numColumns(); ++k)
72
+ {
63
73
  vec.push(matrix.getItem(i, k));
64
74
  }
65
75
  }
66
- } else {
76
+ } else
77
+ {
67
78
  for (let i = 0; i < dimension; ++i)
68
79
  vec.push(0.0);
69
80
  }
@@ -71,99 +82,125 @@ function fromMatrix(matrix: MaterialX.Matrix, dimension: MaterialX.Matrix["size"
71
82
  return vec;
72
83
  }
73
84
 
74
-
75
- export type Loaders = {
76
- getTexture: (path: string) => THREE.Texture;
77
- }
78
-
79
85
  /**
80
86
  * Get Three uniform from MaterialX value
81
87
  * @param {mx.Uniform.type} type
82
88
  * @param {mx.Uniform.value} value
83
89
  * @param {mx.Uniform.name} name
84
90
  * @param {mx.Uniforms} uniforms
85
- * @param {Loaders} loaders
91
+ * @param {THREE.textureLoader} textureLoader
86
92
  * @param {string} searchPath
87
93
  * @param {boolean} flipY
88
94
  */
89
- function toThreeUniform(type: string, value: any, name: string, uniforms: any, loaders: Loaders, searchPath, flipY: boolean) {
90
-
91
- switch (type) {
95
+ function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY)
96
+ {
97
+ let outValue = null;
98
+ switch (type)
99
+ {
92
100
  case 'float':
93
101
  case 'integer':
94
102
  case 'boolean':
95
- return value;
103
+ outValue = value;
96
104
  break;
97
105
  case 'vector2':
98
- return fromVector(value, 2);
106
+ outValue = fromVector(value, 2);
99
107
  break;
100
108
  case 'vector3':
101
109
  case 'color3':
102
- return fromVector(value, 3);
110
+ outValue = fromVector(value, 3);
111
+ break;
103
112
  case 'vector4':
104
113
  case 'color4':
105
- return fromVector(value, 4);
114
+ outValue = fromVector(value, 4);
115
+ break;
106
116
  case 'matrix33':
107
- return fromMatrix(value, 9);
117
+ outValue = fromMatrix(value, 9);
118
+ break;
108
119
  case 'matrix44':
109
- return fromMatrix(value, 16);
120
+ outValue = fromMatrix(value, 16);
121
+ break;
110
122
  case 'filename':
111
- if (value) {
123
+ if (value)
124
+ {
112
125
  // Cache / reuse texture to avoid reload overhead.
113
126
  // Note: that data blobs and embedded data textures are not cached as they are transient data.
114
127
  let checkCache = false;
115
128
  let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value;
116
- if (value.startsWith('blob:')) {
129
+ if (value.startsWith('blob:'))
130
+ {
117
131
  texturePath = value;
118
132
  if (debug) console.log('Load blob URL:', texturePath);
119
133
  checkCache = false;
120
134
  }
121
- else if (value.startsWith('http')) {
135
+ else if (value.startsWith('http'))
136
+ {
122
137
  texturePath = value;
123
138
  if (debug) console.log('Load HTTP URL:', texturePath);
124
139
  }
125
- else if (value.startsWith('data:')) {
140
+ else if (value.startsWith('data:'))
141
+ {
126
142
  texturePath = value;
127
143
  checkCache = false;
128
144
  if (debug) console.log('Load data URL:', texturePath);
129
145
  }
130
146
  const cachedTexture = checkCache && THREE.Cache.get(texturePath);
131
- if (cachedTexture) {
132
- if (debug) console.log('Use cached texture: ', texturePath, cachedTexture);
133
- return cachedTexture;
147
+ if (cachedTexture)
148
+ {
149
+ // Get texture from cache
150
+ outValue = cachedTexture;
151
+ if (debug) console.log('Use cached texture: ', texturePath, outValue);
134
152
  }
135
- else {
136
- const texture = loaders.getTexture(texturePath);
137
- if (checkCache) THREE.Cache.add(texturePath, texture);
153
+ else
154
+ {
155
+ outValue = textureLoader.load(
156
+ texturePath,
157
+ function (texture) {
158
+ if (debug) console.log('Load new texture: ' + texturePath, texture);
159
+ outValue = texture;
160
+
161
+ // Add texture to ThreeJS cache
162
+ if (checkCache)
163
+ THREE.Cache.add(texturePath, texture);
164
+ },
165
+ undefined,
166
+ function (error) {
167
+ console.error('Error loading texture: ', error);
168
+ });
169
+
138
170
  // Set address & filtering mode
139
- if (texture) setTextureParameters(texture, name, uniforms, flipY);
140
- return texture;
171
+ if (outValue)
172
+ setTextureParameters(outValue, name, uniforms, flipY);
141
173
  }
142
174
  }
143
175
  break;
144
176
  case 'samplerCube':
145
177
  case 'string':
146
- return null;
178
+ break;
147
179
  default:
148
180
  const key = type + ':' + name;
149
- if (!valueTypeWarningMap.has(key)) {
181
+ if (!valueTypeWarningMap.has(key))
182
+ {
150
183
  valueTypeWarningMap.set(key, true);
151
184
  console.warn('MaterialX: Unsupported uniform type: ' + type + ' for uniform: ' + name, value);
152
185
  }
153
- return null;
186
+ outValue = null;
154
187
  }
188
+
189
+ return outValue;
155
190
  }
156
191
 
157
- const valueTypeWarningMap = new Map<string, boolean>();
192
+ const valueTypeWarningMap = new Map();
158
193
 
159
194
  /**
160
195
  * Get Three wrapping mode
161
196
  * @param {mx.TextureFilter.wrap} mode
162
197
  * @returns {THREE.Wrapping}
163
198
  */
164
- function getWrapping(mode) {
199
+ function getWrapping(mode)
200
+ {
165
201
  let wrap;
166
- switch (mode) {
202
+ switch (mode)
203
+ {
167
204
  case 1:
168
205
  wrap = THREE.ClampToEdgeWrapping;
169
206
  break;
@@ -185,9 +222,12 @@ function getWrapping(mode) {
185
222
  * @param {mx.TextureFilter.minFilter} type
186
223
  * @param {mx.TextureFilter.generateMipmaps} generateMipmaps
187
224
  */
188
- function getMinFilter(type, generateMipmaps) {
189
- let filterType: THREE.TextureFilter = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter;
190
- if (type === 0) {
225
+ function getMinFilter(type, generateMipmaps)
226
+ {
227
+ /** @type {THREE.TextureFilter} */
228
+ let filterType = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter;
229
+ if (type === 0)
230
+ {
191
231
  filterType = generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter;
192
232
  }
193
233
  return filterType;
@@ -200,22 +240,25 @@ function getMinFilter(type, generateMipmaps) {
200
240
  * @param {mx.Uniforms} uniforms
201
241
  * @param {mx.TextureFilter.generateMipmaps} generateMipmaps
202
242
  */
203
- function setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true) {
243
+ function setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true)
244
+ {
204
245
  const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);
205
246
  const base = name.substring(0, idx) || name;
206
247
 
207
- // texture.generateMipmaps = generateMipmaps;
208
- // texture.wrapS = THREE.RepeatWrapping;
209
- // texture.wrapT = THREE.RepeatWrapping;
210
- // texture.magFilter = THREE.LinearFilter;
211
- // texture.flipY = flipY;
248
+ texture.generateMipmaps = generateMipmaps;
249
+ texture.wrapS = THREE.RepeatWrapping;
250
+ texture.wrapT = THREE.RepeatWrapping;
251
+ texture.magFilter = THREE.LinearFilter;
252
+ texture.flipY = flipY;
212
253
 
213
- if (uniforms.find(base + UADDRESS_MODE_SUFFIX)) {
254
+ if (uniforms.find(base + UADDRESS_MODE_SUFFIX))
255
+ {
214
256
  const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData();
215
257
  texture.wrapS = getWrapping(uaddressmode);
216
258
  }
217
259
 
218
- if (uniforms.find(base + VADDRESS_MODE_SUFFIX)) {
260
+ if (uniforms.find(base + VADDRESS_MODE_SUFFIX))
261
+ {
219
262
  const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData();
220
263
  texture.wrapT = getWrapping(vaddressmode);
221
264
  }
@@ -227,7 +270,8 @@ function setTextureParameters(texture, name, uniforms, flipY = true, generateMip
227
270
  /**
228
271
  * Return the global light rotation matrix
229
272
  */
230
- export function getLightRotation() {
273
+ export function getLightRotation()
274
+ {
231
275
  return new THREE.Matrix4().makeRotationY(Math.PI / 2);
232
276
  }
233
277
 
@@ -236,27 +280,32 @@ export function getLightRotation() {
236
280
  * @param {mx.Document} doc
237
281
  * @returns {Array.<mx.Node>}
238
282
  */
239
- export function findLights(doc: MaterialX.Document) {
240
- let lights = new Array<any>;
241
- for (let node of doc.getNodes()) {
283
+ export function findLights(doc)
284
+ {
285
+ let lights = [];
286
+ for (let node of doc.getNodes())
287
+ {
242
288
  if (node.getType() === "lightshader")
243
289
  lights.push(node);
244
290
  }
245
291
  return lights;
246
292
  }
247
293
 
248
- let lightTypesBound = {};
249
-
250
294
  /**
251
295
  * Register lights in shader generation context
252
- * @param {MaterialX.MODULE} mx MaterialX Module
296
+ * @param {Object} mx MaterialX Module
297
+ * @param {Array.<mx.Node>} lights Light nodes
253
298
  * @param {mx.GenContext} genContext Shader generation context
299
+ * @returns {Array.<mx.Node>}
254
300
  */
255
- export async function registerLights(mx: MaterialX.MODULE, genContext: any): Promise<void> {
256
- lightTypesBound = {};
257
- const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
301
+ export async function registerLights(mx, lights, genContext)
302
+ {
258
303
  mx.HwShaderGenerator.unbindLightShaders(genContext);
304
+
305
+ const lightTypesBound = {};
306
+ const lightData = [];
259
307
  let lightId = 1;
308
+
260
309
  // All light types so that we have NodeDefs for them
261
310
  const defaultLightRigXml = `<?xml version="1.0"?>
262
311
  <materialx version="1.39">
@@ -274,7 +323,7 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
274
323
 
275
324
  // Load default light rig XML to ensure we have all light types available
276
325
  const lightRigDoc = mx.createDocument();
277
- await mx.readFromXmlString(lightRigDoc, defaultLightRigXml, "");
326
+ await mx.readFromXmlString(lightRigDoc, defaultLightRigXml);
278
327
  const document = mx.createDocument();
279
328
  const stdlib = mx.loadStandardLibraries(genContext);
280
329
  document.setDataLibrary(stdlib);
@@ -282,19 +331,18 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
282
331
  const defaultLights = findLights(document);
283
332
  if (debug) console.log("Default lights in MaterialX document", defaultLights);
284
333
 
285
- // Loading a document seems to reset this option for some reason, so we set it again
286
- genContext.getOptions().hwMaxActiveLightSources = maxLightCount;
287
-
288
334
  // Register types only – we get these from the default light rig XML above
289
335
  // This is needed to ensure that the light shaders are bound for each light type
290
- for (let light of defaultLights) {
336
+ for (let light of defaultLights)
337
+ {
291
338
  const lightDef = light.getNodeDef();
292
339
  if (debug) console.log("Default light node definition", lightDef);
293
340
  if (!lightDef) continue;
294
341
 
295
342
  const lightName = lightDef.getName();
296
343
  if (debug) console.log("Registering default light", { lightName, lightDef });
297
- if (!lightTypesBound[lightName]) {
344
+ if (!lightTypesBound[lightName])
345
+ {
298
346
  // TODO check if we need to bind light shader for each three.js light instead of once per type
299
347
  if (debug) console.log("Bind light shader for node", { lightName, lightId, lightDef });
300
348
  lightTypesBound[lightName] = lightId;
@@ -303,40 +351,52 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
303
351
  }
304
352
 
305
353
  if (debug) console.log("Light types bound in MaterialX context", lightTypesBound);
306
- }
307
354
 
308
- // Converts Three.js light type to MaterialX node name
309
- function threeLightTypeToMaterialXNodeName(threeLightType) {
310
- switch (threeLightType) {
311
- case 'PointLight':
312
- return 'ND_point_light';
313
- case 'DirectionalLight':
314
- return 'ND_directional_light';
315
- case 'SpotLight':
316
- return 'ND_spot_light';
317
- default:
318
- console.warn('MaterialX: Unsupported light type: ' + threeLightType);
319
- return 'ND_point_light'; // Default to point light
355
+ // MaterialX light nodes
356
+ for (let light of lights)
357
+ {
358
+ // Skip if light does not have a node definition
359
+ if (!("getNodeDef" in light)) continue;
360
+
361
+ let nodeDef = light.getNodeDef();
362
+ let nodeName = nodeDef.getName();
363
+ if (!lightTypesBound[nodeName])
364
+ {
365
+ if (debug) console.log("bind light shader for node", { nodeName, lightId, nodeDef });
366
+ lightTypesBound[nodeName] = lightId;
367
+ mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);
368
+ }
369
+
370
+ const lightDirection = light.getValueElement("direction").getValue().getData().data();
371
+ const lightColor = light.getValueElement("color").getValue().getData().data();
372
+ const lightIntensity = light.getValueElement("intensity").getValue().getData();
373
+
374
+ let rotatedLightDirection = new THREE.Vector3(...lightDirection)
375
+ rotatedLightDirection.transformDirection(getLightRotation())
376
+
377
+ lightData.push({
378
+ type: lightTypesBound[nodeName],
379
+ direction: rotatedLightDirection,
380
+ color: new THREE.Vector3(...lightColor),
381
+ intensity: lightIntensity,
382
+ });
320
383
  }
321
- };
322
-
323
- type LightData = {
324
- type: number, // Light type ID
325
- position: THREE.Vector3, // Position in world space
326
- direction: THREE.Vector3, // Direction in world space
327
- color: THREE.Color, // Color of the light
328
- intensity: number, // Intensity of the light
329
- decay_rate: number, // Decay rate for point and spot lights
330
- inner_angle: number, // Inner angle for spot lights
331
- outer_angle: number, // Outer angle for spot lights
332
- }
333
384
 
334
- /**
335
- * Update light data for shader uniforms
336
- */
337
- export function getLightData(lights: any, genContext: any): { lightData: LightData[], lightCount: number } {
338
- const lightData = new Array();
339
- const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
385
+ const threeLightTypeToMaterialXNodeName = (threeLightType) => {
386
+ switch (threeLightType) {
387
+ case 'PointLight':
388
+ return 'ND_point_light';
389
+ case 'DirectionalLight':
390
+ return 'ND_directional_light';
391
+ case 'SpotLight':
392
+ return 'ND_spot_light';
393
+ default:
394
+ console.warn('MaterialX: Unsupported light type: ' + threeLightType);
395
+ return 'ND_point_light'; // Default to point light
396
+ }
397
+ };
398
+
399
+ if (debug) console.log("Registering lights in MaterialX context", lights, lightData);
340
400
 
341
401
  // Three.js lights
342
402
  for (let light of lights) {
@@ -348,82 +408,50 @@ export function getLightData(lights: any, genContext: any): { lightData: LightDa
348
408
  const lightDefinitionName = threeLightTypeToMaterialXNodeName(light.type);
349
409
 
350
410
  if (!lightTypesBound[lightDefinitionName])
351
- console.error("MaterialX: Light type not registered in context. Make sure to register light types before using them.", lightDefinitionName);
352
-
353
- const wp = light.getWorldPosition(new THREE.Vector3());
354
- const wd = getWorldDirection(light, new THREE.Vector3(0, 0, -1));
355
-
356
- // Shader math from the generated MaterialX shader:
357
- // float low = min(light.inner_angle, light.outer_angle);
358
- // float high = light.inner_angle;
359
- // float cosDir = dot(result.direction, -light.direction);
360
- // float spotAttenuation = smoothstep(low, high, cosDir);
361
-
362
- const outerAngleRad = light.angle;
363
- const innerAngleRad = outerAngleRad * (1 - light.penumbra);
364
- const inner_angle = Math.cos(innerAngleRad);
365
- const outer_angle = Math.cos(outerAngleRad);
411
+ {
412
+ lightTypesBound[lightDefinitionName] = lightId;
413
+ const nodeDef = null;
414
+ mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);
415
+ }
366
416
 
367
417
  lightData.push({
368
418
  type: lightTypesBound[lightDefinitionName],
369
- position: wp.clone(),
370
- direction: wd.clone(),
371
- color: new THREE.Color().fromArray(light.color.toArray()),
372
- // Luminous efficacy for converting radiant power in watts (W) to luminous flux in lumens (lm) at a wavelength of 555 nm.
373
- // Also, three.js lights don't have PI scale baked in, but MaterialX does, so we need to divide by PI for point and spot lights.
374
- intensity: light.intensity * (light.isPointLight ? 683.0 / 3.1415 : light.isSpotLight ? 683.0 / 3.1415 : 1.0),
375
- decay_rate: 2.0,
376
- // Approximations for testing – the relevant light has 61.57986...129.4445 as inner/outer spot angle
377
- inner_angle: inner_angle,
378
- outer_angle: outer_angle,
419
+ direction: light.direction?.clone() || new THREE.Vector3(0, -1, 0),
420
+ color: new THREE.Vector3().fromArray(light.color.toArray()),
421
+ intensity: light.intensity,
379
422
  });
380
423
  }
381
424
 
382
- // Count the number of lights that are not empty
383
- const lightCount = lightData.length;
384
-
385
- // If we don't have enough entries in lightData, fill with empty lights
386
- while (lightData.length < maxLightCount) {
387
- const emptyLight = {
388
- type: 0, // Default light type
389
- position: new THREE.Vector3(0, 0, 0),
390
- direction: new THREE.Vector3(0, 0, -1),
391
- color: new THREE.Color(0, 0, 0),
392
- intensity: 0.0,
393
- decay_rate: 2.0,
394
- inner_angle: 0.0,
395
- outer_angle: 0.0,
396
- };
397
- lightData.push(emptyLight);
398
- }
399
-
400
- if (debugUpdate) console.log("Registered lights in MaterialX context", lightTypesBound, lightData);
425
+ // Make sure max light count is large enough
426
+ genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lightData.length);
401
427
 
402
- return { lightData, lightCount };
428
+ return lightData;
403
429
  }
404
430
 
405
431
  /**
406
432
  * Get uniform values for a shader
433
+ * @param {mx.shaderStage} shaderStage
434
+ * @param {THREE.TextureLoader} textureLoader
407
435
  */
408
- export function getUniformValues(shaderStage: MaterialX.ShaderStage, loaders: Loaders, searchPath: string, flipY: boolean) {
409
- const threeUniforms = {};
410
-
411
- const uniformBlocks = shaderStage.getUniformBlocks()
412
- for (const [blockName, uniforms] of Object.entries(uniformBlocks)) {
413
- // Seems struct uniforms (like in LightData) end up here as well, we should filter those out.
414
- if (blockName === "LightData") continue;
415
-
416
- if (!uniforms.empty()) {
417
- for (let i = 0; i < uniforms.size(); ++i) {
436
+ export function getUniformValues(shaderStage, textureLoader, searchPath, flipY)
437
+ {
438
+ let threeUniforms = {};
439
+
440
+ const uniformBlocks = Object.values(shaderStage.getUniformBlocks());
441
+ uniformBlocks.forEach(uniforms =>
442
+ {
443
+ if (!uniforms.empty())
444
+ {
445
+ for (let i = 0; i < uniforms.size(); ++i)
446
+ {
418
447
  const variable = uniforms.get(i);
419
448
  const value = variable.getValue()?.getData();
420
449
  const name = variable.getVariable();
421
- if (debug) console.log("Adding uniform", { path: variable.getPath(), name, value, type: variable.getType().getName() });
422
450
  threeUniforms[name] = new THREE.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms,
423
- loaders, searchPath, flipY));
451
+ textureLoader, searchPath, flipY));
424
452
  }
425
453
  }
426
- }
454
+ });
427
455
 
428
456
  return threeUniforms;
429
457
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ready, state } from "./materialx.js";
1
+ import { initializeMaterialX, state } from "./materialx.js";
2
2
 
3
3
  const getMaterialXEnvironment = () => state.materialXEnvironment;
4
4
 
5
- export { ready, getMaterialXEnvironment };
5
+ export { initializeMaterialX, getMaterialXEnvironment };