@needle-tools/materialx 1.1.1 → 1.2.0

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.
@@ -0,0 +1,31 @@
1
+ import * as THREE from 'three';
2
+
3
+ export interface Callbacks {
4
+ readonly cacheKey?: string;
5
+ readonly getTexture: (path: string) => Promise<THREE.Texture | null | void>;
6
+ }
7
+
8
+ export interface LightData {
9
+ type: number;
10
+ position: THREE.Vector3;
11
+ direction: THREE.Vector3;
12
+ color: THREE.Color;
13
+ intensity: number;
14
+ decay_rate: number;
15
+ inner_angle: number;
16
+ outer_angle: number;
17
+ }
18
+
19
+ export function prepareEnvTexture(texture: THREE.Texture, capabilities: any): THREE.Texture;
20
+
21
+ export function getLightRotation(): THREE.Matrix4;
22
+
23
+ export function findLights(doc: any): Array<any>;
24
+
25
+ export function registerLights(mx: any, genContext: any): Promise<void>;
26
+
27
+ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lightData: LightData[], lightCount: number };
28
+
29
+ export function getUniformValues(shaderStage: any, loaders: Callbacks, searchPath: string): Record<string, THREE.Uniform>;
30
+
31
+ export function generateMaterialPropertiesForUniforms(material: THREE.ShaderMaterial, shaderStage: any): void;
@@ -4,7 +4,6 @@
4
4
  //
5
5
  import * as THREE from 'three';
6
6
  import { debug, debugUpdate } from './utils.js';
7
- import { MaterialX } from './materialx.types.js';
8
7
 
9
8
  const IMAGE_PROPERTY_SEPARATOR = "_";
10
9
  const UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "uaddressmode";
@@ -13,20 +12,19 @@ const FILTER_TYPE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "filtertype";
13
12
  const IMAGE_PATH_SEPARATOR = "/";
14
13
 
15
14
  /**
16
- * Initialized the environment texture as MaterialX expects it
15
+ * Initializes the environment texture as MaterialX expects it
17
16
  * @param {THREE.Texture} texture
18
17
  * @param {Object} capabilities
19
18
  * @returns {THREE.Texture}
20
19
  */
21
20
  export function prepareEnvTexture(texture, capabilities) {
22
- let newTexture = new THREE.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type);
21
+ const newTexture = new THREE.DataTexture(texture.image.data, texture.image.width, texture.image.height, /** @type {any} */(texture.format), texture.type);
23
22
  newTexture.wrapS = THREE.RepeatWrapping;
24
23
  newTexture.anisotropy = capabilities.getMaxAnisotropy();
25
24
  newTexture.minFilter = THREE.LinearMipmapLinearFilter;
26
25
  newTexture.magFilter = THREE.LinearFilter;
27
26
  newTexture.generateMipmaps = true;
28
27
  newTexture.needsUpdate = true;
29
-
30
28
  return newTexture;
31
29
  }
32
30
 
@@ -34,7 +32,7 @@ export function prepareEnvTexture(texture, capabilities) {
34
32
  * Get Three uniform from MaterialX vector
35
33
  * @param {any} value
36
34
  * @param {any} dimension
37
- * @returns {THREE.Uniform}
35
+ * @returns {Array<number>}
38
36
  */
39
37
  function fromVector(value, dimension) {
40
38
  let outValue;
@@ -52,8 +50,11 @@ function fromVector(value, dimension) {
52
50
 
53
51
  /**
54
52
  * Get Three uniform from MaterialX matrix
53
+ * @param {any} matrix
54
+ * @param {number} dimension
55
+ * @returns {Array<number>}
55
56
  */
56
- function fromMatrix(matrix: MaterialX.Matrix, dimension: MaterialX.Matrix["size"]) {
57
+ function fromMatrix(matrix, dimension) {
57
58
  const vec = new Array(dimension);
58
59
  if (matrix) {
59
60
  for (let i = 0; i < matrix.numRows(); ++i) {
@@ -69,19 +70,11 @@ function fromMatrix(matrix: MaterialX.Matrix, dimension: MaterialX.Matrix["size"
69
70
  return vec;
70
71
  }
71
72
 
72
-
73
- export type Loaders = {
74
- /**
75
- * Cache key for the loaders, used to identify and reuse textures
76
- */
77
- readonly cacheKey: string;
78
- /**
79
- * Get a texture by path
80
- * @param {string} path - The path to the texture
81
- * @return {Promise<THREE.Texture>} - A promise that resolves to the texture
82
- */
83
- readonly getTexture: (path: string) => Promise<THREE.Texture>;
84
- }
73
+ /**
74
+ * @typedef {Object} Callbacks
75
+ * @property {string} [cacheKey] - Cache key for the loaders, used to identify and reuse textures
76
+ * @property {(path: string) => Promise<THREE.Texture | null | void>} getTexture - Get a texture by path
77
+ */
85
78
 
86
79
  const defaultTexture = new THREE.Texture();
87
80
  defaultTexture.needsUpdate = true;
@@ -94,21 +87,28 @@ defaultTexture.image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAA
94
87
  // defaultTexture.magFilter = THREE.NearestFilter;
95
88
  // defaultTexture.repeat = new THREE.Vector2(100, 100);
96
89
 
97
-
98
90
  const defaultNormalTexture = new THREE.Texture();
99
91
  defaultNormalTexture.needsUpdate = true;
100
92
  defaultNormalTexture.image = new Image();
101
93
  defaultNormalTexture.image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIBAMAAAA2IaO4AAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAABJQTFRFgYH4gIH4gYH3gIH3gIH5gID4m94ORAAAADFJREFUeJxjZBBkfMdo9P/BB0aBj/8FGB0ufghgFGT4r8wo+P8rD2Pgo3sMjIz8jAwAMLoN0ZjS5hgAAAAASUVORK5CYII=";
102
94
 
103
-
104
- function tryGetFromCache(key: string): any {
95
+ /**
96
+ * @param {string} key
97
+ * @returns {any}
98
+ */
99
+ function tryGetFromCache(key) {
105
100
  const wasEnabled = THREE.Cache.enabled;
106
101
  THREE.Cache.enabled = true;
107
102
  const value = THREE.Cache.get(key);
108
103
  THREE.Cache.enabled = wasEnabled;
109
104
  return value;
110
105
  }
111
- function addToCache(key: string, value: any): void {
106
+
107
+ /**
108
+ * @param {string} key
109
+ * @param {any} value
110
+ */
111
+ function addToCache(key, value) {
112
112
  const wasEnabled = THREE.Cache.enabled;
113
113
  THREE.Cache.enabled = true;
114
114
  THREE.Cache.add(key, value);
@@ -118,10 +118,17 @@ function addToCache(key: string, value: any): void {
118
118
 
119
119
  /**
120
120
  * Get Three uniform from MaterialX value
121
+ * @param {any} uniforms
122
+ * @param {string} type
123
+ * @param {any} value
124
+ * @param {string} name
125
+ * @param {Callbacks} loaders
126
+ * @param {string} searchPath
127
+ * @returns {THREE.Uniform}
121
128
  */
122
- function toThreeUniform(uniforms: any, type: string, value: any, name: string, loaders: Loaders, searchPath: string): THREE.Uniform {
129
+ function toThreeUniform(uniforms, type, value, name, loaders, searchPath) {
123
130
 
124
- const uniform = new THREE.Uniform<any>(null);
131
+ const uniform = new THREE.Uniform(/** @type {any} */(null));
125
132
 
126
133
  switch (type) {
127
134
  case 'float':
@@ -130,21 +137,21 @@ function toThreeUniform(uniforms: any, type: string, value: any, name: string, l
130
137
  uniform.value = value;
131
138
  break;
132
139
  case 'vector2':
133
- uniform.value = fromVector(value, 2);
140
+ uniform.value = /** @type {any} */ (fromVector(value, 2));
134
141
  break;
135
142
  case 'vector3':
136
143
  case 'color3':
137
- uniform.value = fromVector(value, 3);
144
+ uniform.value = /** @type {any} */ (fromVector(value, 3));
138
145
  break;
139
146
  case 'vector4':
140
147
  case 'color4':
141
- uniform.value = fromVector(value, 4);
148
+ uniform.value = /** @type {any} */ (fromVector(value, 4));
142
149
  break;
143
150
  case 'matrix33':
144
- uniform.value = fromMatrix(value, 9);
151
+ uniform.value = /** @type {any} */ (fromMatrix(value, 9));
145
152
  break;
146
153
  case 'matrix44':
147
- uniform.value = fromMatrix(value, 16);
154
+ uniform.value = /** @type {any} */ (fromMatrix(value, 16));
148
155
  break;
149
156
  case 'filename':
150
157
  if (value) {
@@ -165,7 +172,7 @@ function toThreeUniform(uniforms: any, type: string, value: any, name: string, l
165
172
  checkCache = true;
166
173
  }
167
174
 
168
- const cacheKey = `${loaders.cacheKey}-${texturePath}`;
175
+ const cacheKey = loaders.cacheKey?.length ? `${loaders.cacheKey}-${texturePath}` : texturePath;
169
176
  const cacheValue = checkCache ? tryGetFromCache(cacheKey) : null;
170
177
  if (cacheValue) {
171
178
  if (debug) console.log('[MaterialX] Use cached texture: ', cacheKey, cacheValue);
@@ -180,28 +187,30 @@ function toThreeUniform(uniforms: any, type: string, value: any, name: string, l
180
187
  }
181
188
  }
182
189
  else {
183
- if (name.toLowerCase().includes("normal")) {
184
- uniform.value = defaultNormalTexture;
185
- }
186
- else {
187
- uniform.value = defaultTexture;
188
- }
189
-
190
190
  if (debug) console.log('[MaterialX] Load texture:', texturePath);
191
+
192
+ if (name.toLowerCase().includes("normal")) uniform.value = /** @type {any} */ (defaultNormalTexture);
193
+ else uniform.value = /** @type {any} */ (defaultTexture);
194
+ const defaultValue = uniform.value;
191
195
  // Save the loading promise in the cache
192
- const promise = loaders.getTexture(texturePath).then(res => {
193
- if (res) {
194
- res = res.clone(); // we need to clone the texture once to avoid colorSpace issues with other materials
195
- res.colorSpace = THREE.LinearSRGBColorSpace;
196
- setTextureParameters(res, name, uniforms);
197
- }
198
- return res;
199
- });
200
- if (checkCache) {
201
- addToCache(cacheKey, promise);
202
- }
203
- promise.then(res => {
204
- if (res) uniform.value = res;
196
+ const promise = loaders.getTexture(texturePath)
197
+ ?.then(res => {
198
+ if (res) {
199
+ res = res.clone(); // we need to clone the texture once to avoid colorSpace issues with other materials
200
+ res.colorSpace = THREE.LinearSRGBColorSpace;
201
+ setTextureParameters(res, name, uniforms);
202
+ }
203
+ return res;
204
+ })
205
+ .catch(err => {
206
+ console.error(`[MaterialX] Failed to load texture ${name} '${texturePath}'`, err);
207
+ return defaultValue;
208
+ });
209
+
210
+ if (checkCache) addToCache(cacheKey, promise);
211
+
212
+ promise?.then(res => {
213
+ if (res) uniform.value = /** @type {any} */ (res);
205
214
  else console.warn(`[MaterialX] Failed to load texture ${name} '${texturePath}'`);
206
215
  });
207
216
  }
@@ -222,12 +231,15 @@ function toThreeUniform(uniforms: any, type: string, value: any, name: string, l
222
231
  return uniform;
223
232
  }
224
233
 
225
- const valueTypeWarningMap = new Map<string, boolean>();
234
+ /** @type {Map<string, boolean>} */
235
+ const valueTypeWarningMap = new Map();
226
236
 
227
237
  /**
228
238
  * Get Three wrapping mode
239
+ * @param {number} mode
240
+ * @returns {THREE.Wrapping}
229
241
  */
230
- function getWrapping(mode: number): THREE.Wrapping {
242
+ function getWrapping(mode) {
231
243
  let wrap;
232
244
  switch (mode) {
233
245
  case 1:
@@ -246,11 +258,14 @@ function getWrapping(mode: number): THREE.Wrapping {
246
258
  return wrap;
247
259
  }
248
260
 
249
-
250
261
  /**
251
262
  * Set Three texture parameters
263
+ * @param {THREE.Texture} texture
264
+ * @param {string} name
265
+ * @param {any} uniforms
266
+ * @param {boolean} [generateMipmaps=true]
252
267
  */
253
- function setTextureParameters(texture: THREE.Texture, name: string, uniforms: any, generateMipmaps = true) {
268
+ function setTextureParameters(texture, name, uniforms, generateMipmaps = true) {
254
269
  const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);
255
270
  const base = name.substring(0, idx) || name;
256
271
 
@@ -265,15 +280,16 @@ function setTextureParameters(texture: THREE.Texture, name: string, uniforms: an
265
280
  }
266
281
 
267
282
  const mxFilterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1;
268
- let minFilter: THREE.TextureFilter = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter;
283
+ let minFilter = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter;
269
284
  if (mxFilterType === 0) {
270
- minFilter = generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter;
285
+ minFilter = /** @type {any} */ (generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter);
271
286
  }
272
287
  texture.minFilter = minFilter;
273
288
  }
274
289
 
275
290
  /**
276
291
  * Return the global light rotation matrix
292
+ * @returns {THREE.Matrix4}
277
293
  */
278
294
  export function getLightRotation() {
279
295
  return new THREE.Matrix4().makeRotationY(Math.PI / 2);
@@ -281,11 +297,11 @@ export function getLightRotation() {
281
297
 
282
298
  /**
283
299
  * Returns all lights nodes in a MaterialX document
284
- * @param {mx.Document} doc
285
- * @returns {Array.<mx.Node>}
300
+ * @param {any} doc
301
+ * @returns {Array<any>}
286
302
  */
287
- export function findLights(doc: MaterialX.Document) {
288
- let lights = new Array<any>;
303
+ export function findLights(doc) {
304
+ let lights = new Array();
289
305
  for (let node of doc.getNodes()) {
290
306
  if (node.getType() === "lightshader")
291
307
  lights.push(node);
@@ -293,14 +309,16 @@ export function findLights(doc: MaterialX.Document) {
293
309
  return lights;
294
310
  }
295
311
 
312
+ /** @type {Object<string, number>} */
296
313
  let lightTypesBound = {};
297
314
 
298
315
  /**
299
316
  * Register lights in shader generation context
300
- * @param {MaterialX.MODULE} mx MaterialX Module
301
- * @param {mx.GenContext} genContext Shader generation context
317
+ * @param {any} mx - MaterialX Module
318
+ * @param {any} genContext - Shader generation context
319
+ * @returns {Promise<void>}
302
320
  */
303
- export async function registerLights(mx: MaterialX.MODULE, genContext: any): Promise<void> {
321
+ export async function registerLights(mx, genContext) {
304
322
  lightTypesBound = {};
305
323
  const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
306
324
  mx.HwShaderGenerator.unbindLightShaders(genContext);
@@ -353,7 +371,12 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
353
371
  if (debug) console.log("Light types bound in MaterialX context", lightTypesBound);
354
372
  }
355
373
 
356
- // Converts Three.js light type to MaterialX node name
374
+ const _lightTypeWarnings = {}
375
+ /**
376
+ * Converts Three.js light type to MaterialX node name
377
+ * @param {string} threeLightType
378
+ * @returns {string|null}
379
+ */
357
380
  function threeLightTypeToMaterialXNodeName(threeLightType) {
358
381
  switch (threeLightType) {
359
382
  case 'PointLight':
@@ -363,26 +386,33 @@ function threeLightTypeToMaterialXNodeName(threeLightType) {
363
386
  case 'SpotLight':
364
387
  return 'ND_spot_light';
365
388
  default:
366
- console.warn('MaterialX: Unsupported light type: ' + threeLightType);
367
- return 'ND_point_light'; // Default to point light
389
+ if (!_lightTypeWarnings[threeLightType]) {
390
+ _lightTypeWarnings[threeLightType] = true;
391
+ console.warn('MaterialX: Unsupported light type: ' + threeLightType);
392
+ }
393
+ return null; // Unsupported light type
368
394
  }
369
- };
370
-
371
- export type LightData = {
372
- type: number, // Light type ID
373
- position: THREE.Vector3, // Position in world space
374
- direction: THREE.Vector3, // Direction in world space
375
- color: THREE.Color, // Color of the light
376
- intensity: number, // Intensity of the light
377
- decay_rate: number, // Decay rate for point and spot lights
378
- inner_angle: number, // Inner angle for spot lights
379
- outer_angle: number, // Outer angle for spot lights
380
395
  }
381
396
 
397
+ /**
398
+ * @typedef {Object} LightData
399
+ * @property {number} type - Light type ID
400
+ * @property {THREE.Vector3} position - Position in world space
401
+ * @property {THREE.Vector3} direction - Direction in world space
402
+ * @property {THREE.Color} color - Color of the light
403
+ * @property {number} intensity - Intensity of the light
404
+ * @property {number} decay_rate - Decay rate for point and spot lights
405
+ * @property {number} inner_angle - Inner angle for spot lights
406
+ * @property {number} outer_angle - Outer angle for spot lights
407
+ */
408
+
382
409
  /**
383
410
  * Update light data for shader uniforms
411
+ * @param {Array<THREE.Light>} lights
412
+ * @param {any} genContext
413
+ * @returns {{ lightData: LightData[], lightCount: number }}
384
414
  */
385
- export function getLightData(lights: Array<THREE.Light>, genContext: any): { lightData: LightData[], lightCount: number } {
415
+ export function getLightData(lights, genContext) {
386
416
  const lightData = new Array();
387
417
  const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
388
418
 
@@ -395,8 +425,12 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
395
425
 
396
426
  const lightDefinitionName = threeLightTypeToMaterialXNodeName(light.type);
397
427
 
398
- if (!lightTypesBound[lightDefinitionName])
399
- console.error("MaterialX: Light type not registered in context. Make sure to register light types before using them.", lightDefinitionName);
428
+ if(!lightDefinitionName){
429
+ continue; // Unsupported light type
430
+ }
431
+ if (!lightTypesBound[lightDefinitionName]) {
432
+ if(debug) console.error("MaterialX: Light type not registered in context. Make sure to register light types before using them.", lightDefinitionName);
433
+ }
400
434
 
401
435
  const wp = light.getWorldPosition(new THREE.Vector3());
402
436
  const wq = light.getWorldQuaternion(new THREE.Quaternion());
@@ -408,8 +442,8 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
408
442
  // float cosDir = dot(result.direction, -light.direction);
409
443
  // float spotAttenuation = smoothstep(low, high, cosDir);
410
444
 
411
- const outerAngleRad = (light as THREE.SpotLight).angle;
412
- const innerAngleRad = outerAngleRad * (1 - (light as THREE.SpotLight).penumbra);
445
+ const outerAngleRad = /** @type {THREE.SpotLight} */ (light).angle;
446
+ const innerAngleRad = outerAngleRad * (1 - /** @type {THREE.SpotLight} */ (light).penumbra);
413
447
  const inner_angle = Math.cos(innerAngleRad);
414
448
  const outer_angle = Math.cos(outerAngleRad);
415
449
 
@@ -420,7 +454,7 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
420
454
  color: new THREE.Color().fromArray(light.color.toArray()),
421
455
  // Luminous efficacy for converting radiant power in watts (W) to luminous flux in lumens (lm) at a wavelength of 555 nm.
422
456
  // 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.
423
- intensity: light.intensity * ((light as THREE.PointLight).isPointLight ? 683.0 / 3.1415 : (light as THREE.SpotLight).isSpotLight ? 683.0 / 3.1415 : 1.0),
457
+ intensity: light.intensity * (/** @type {THREE.PointLight} */ (light).isPointLight ? 683.0 / 3.1415 : /** @type {THREE.SpotLight} */ (light).isSpotLight ? 683.0 / 3.1415 : 1.0),
424
458
  decay_rate: 2.0,
425
459
  // Approximations for testing – the relevant light has 61.57986...129.4445 as inner/outer spot angle
426
460
  inner_angle: inner_angle,
@@ -453,8 +487,13 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
453
487
 
454
488
  /**
455
489
  * Get uniform values for a shader
490
+ * @param {any} shaderStage
491
+ * @param {Callbacks} loaders
492
+ * @param {string} searchPath
493
+ * @returns {Object<string, THREE.Uniform>}
456
494
  */
457
- export function getUniformValues(shaderStage: MaterialX.ShaderStage, loaders: Loaders, searchPath: string) {
495
+ export function getUniformValues(shaderStage, loaders, searchPath) {
496
+ /** @type {Object<string, THREE.Uniform>} */
458
497
  const threeUniforms = {};
459
498
 
460
499
  const uniformBlocks = shaderStage.getUniformBlocks()
@@ -468,8 +507,8 @@ export function getUniformValues(shaderStage: MaterialX.ShaderStage, loaders: Lo
468
507
  const value = variable.getValue()?.getData();
469
508
  const uniformName = variable.getVariable();
470
509
  const type = variable.getType().getName();
471
- if (debug) console.log("Adding uniform", { path: variable.getPath(), name: uniformName, value: value, type: type });
472
510
  threeUniforms[uniformName] = toThreeUniform(uniforms, type, value, uniformName, loaders, searchPath);
511
+ if (debug) console.log("Adding uniform", { path: variable.getPath(), type: type, name: uniformName, value: threeUniforms[uniformName], },);
473
512
  }
474
513
  }
475
514
  }
@@ -477,7 +516,11 @@ export function getUniformValues(shaderStage: MaterialX.ShaderStage, loaders: Lo
477
516
  return threeUniforms;
478
517
  }
479
518
 
480
- export function generateMaterialPropertiesForUniforms(material: THREE.ShaderMaterial, shaderStage: MaterialX.ShaderStage) {
519
+ /**
520
+ * @param {THREE.ShaderMaterial} material
521
+ * @param {any} shaderStage
522
+ */
523
+ export function generateMaterialPropertiesForUniforms(material, shaderStage) {
481
524
 
482
525
  const uniformBlocks = shaderStage.getUniformBlocks()
483
526
  for (const [blockName, uniforms] of Object.entries(uniformBlocks)) {
@@ -501,22 +544,27 @@ export function generateMaterialPropertiesForUniforms(material: THREE.ShaderMate
501
544
  break;
502
545
  }
503
546
  if (key) {
504
- Object.defineProperty(material, key, {
505
- get: function () {
506
- return this.uniforms?.[uniformName].value
507
- },
508
- set: function (v) {
509
- const uniforms = this.uniforms;
510
- if (!uniforms || !uniforms[uniformName]) {
511
- console.warn(`[MaterialX] Uniform ${uniformName} not found in ${this.name} uniforms`);
512
- return;
547
+ if (material.hasOwnProperty(key)) {
548
+ if (debug) console.warn(`[MaterialX] Uniform ${uniformName} already exists in material as property ${key}, skipping.`);
549
+ }
550
+ else {
551
+ Object.defineProperty(material, key, {
552
+ get: function () {
553
+ return this.uniforms?.[uniformName].value
554
+ },
555
+ set: function (v) {
556
+ const uniforms = this.uniforms;
557
+ if (!uniforms || !uniforms[uniformName]) {
558
+ console.warn(`[MaterialX] Uniform ${uniformName} not found in ${this.name} uniforms`);
559
+ return;
560
+ }
561
+ this.uniforms[uniformName].value = v;
562
+ this.uniformsNeedUpdate = true;
513
563
  }
514
- this.uniforms[uniformName].value = v;
515
- this.uniformsNeedUpdate = true;
516
- }
517
- });
564
+ });
565
+ }
518
566
  }
519
567
  }
520
568
  }
521
569
  }
522
- }
570
+ }