@needle-tools/materialx 1.1.0 → 1.1.1-next.623fc20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/materialx",
3
- "version": "1.1.0",
3
+ "version": "1.1.1-next.623fc20",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "exports": {
@@ -42,4 +42,4 @@
42
42
  "mtlx",
43
43
  "rendering"
44
44
  ]
45
- }
45
+ }
@@ -14,10 +14,19 @@ export type MaterialX_root_extension = {
14
14
  mtlx: string;
15
15
  /** MaterialX texture pointers */
16
16
  textures: Array<{ name: string, pointer: string }>;
17
+ shaders?: Array<{
18
+ /** The materialx node name */
19
+ name: string,
20
+ /** The original name of the shader */
21
+ originalName: string,
22
+ }>,
17
23
  }
18
24
 
19
25
  export type MaterialX_material_extension = {
20
- name: string; // Material name reference
26
+ /** The MaterialX material name */
27
+ name: string;
28
+ /** The index of the shader in the shaders array of the root extension. */
29
+ shader?: number;
21
30
  }
22
31
 
23
32
  type MaterialDefinition = {
@@ -239,13 +248,23 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
239
248
  const elementName = (renderableElement as any).getNamePath ? (renderableElement as any).getNamePath() : (renderableElement as any).getName();
240
249
 
241
250
  const shader = state.materialXGenerator.generate(elementName, renderableElement, state.materialXGenContext);
251
+
252
+ const rootExtension = this.materialX_root_data;
253
+
254
+ const shaderInfo = rootExtension && material_extension.shader !== undefined && material_extension.shader >= 0
255
+ ? rootExtension.shaders?.[material_extension.shader]
256
+ : null;
257
+
242
258
  const shaderMaterial = new MaterialXMaterial({
243
259
  name: material_extension.name,
260
+ shaderName: shaderInfo?.originalName || shaderInfo?.name || null,
244
261
  shader,
245
- transparent: isTransparent,
246
- side: material_def.doubleSided ? DoubleSide : FrontSide,
247
262
  context: this.context,
248
- precision: this.options.parameters?.precision,
263
+ parameters: {
264
+ transparent: isTransparent,
265
+ side: material_def.doubleSided ? DoubleSide : FrontSide,
266
+ ...this.options.parameters,
267
+ },
249
268
  loaders: {
250
269
  cacheKey: this.options.cacheKey || "",
251
270
  getTexture: async url => {
@@ -253,9 +272,8 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
253
272
  const filenameWithoutExt = url.split('/').pop()?.split('.').shift() || '';
254
273
 
255
274
  // Resolve the texture from the MaterialX root extension
256
- const ext = this.materialX_root_data;
257
- if (ext) {
258
- const textures = ext.textures || [];
275
+ if (rootExtension) {
276
+ const textures = rootExtension.textures || [];
259
277
  let index = -1;
260
278
  for (const texture of textures) {
261
279
  // Find the texture by name and use the pointer string to get the index
@@ -466,12 +466,57 @@ export function getUniformValues(shaderStage: MaterialX.ShaderStage, loaders: Lo
466
466
  for (let i = 0; i < uniforms.size(); ++i) {
467
467
  const variable = uniforms.get(i);
468
468
  const value = variable.getValue()?.getData();
469
- const name = variable.getVariable();
470
- if (debug) console.log("Adding uniform", { path: variable.getPath(), name: name, value: value, type: variable.getType().getName() });
471
- threeUniforms[name] = toThreeUniform(uniforms, variable.getType().getName(), value, name, loaders, searchPath);
469
+ const uniformName = variable.getVariable();
470
+ const type = variable.getType().getName();
471
+ if (debug) console.log("Adding uniform", { path: variable.getPath(), name: uniformName, value: value, type: type });
472
+ threeUniforms[uniformName] = toThreeUniform(uniforms, type, value, uniformName, loaders, searchPath);
472
473
  }
473
474
  }
474
475
  }
475
476
 
476
477
  return threeUniforms;
477
478
  }
479
+
480
+ export function generateMaterialPropertiesForUniforms(material: THREE.ShaderMaterial, shaderStage: MaterialX.ShaderStage) {
481
+
482
+ const uniformBlocks = shaderStage.getUniformBlocks()
483
+ for (const [blockName, uniforms] of Object.entries(uniformBlocks)) {
484
+ // Seems struct uniforms (like in LightData) end up here as well, we should filter those out.
485
+ if (blockName === "LightData") continue;
486
+
487
+ if (!uniforms.empty()) {
488
+ for (let i = 0; i < uniforms.size(); ++i) {
489
+ const variable = uniforms.get(i);
490
+ const uniformName = variable.getVariable();
491
+ let key = variable.getPath().split('/').pop();
492
+ switch (key) {
493
+ case "_Color":
494
+ key = "color";
495
+ break;
496
+ case "_Roughness":
497
+ key = "roughness";
498
+ break;
499
+ case "_Metallic":
500
+ key = "metalness";
501
+ break;
502
+ }
503
+ 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;
513
+ }
514
+ this.uniforms[uniformName].value = v;
515
+ this.uniformsNeedUpdate = true;
516
+ }
517
+ });
518
+ }
519
+ }
520
+ }
521
+ }
522
+ }
@@ -1,7 +1,8 @@
1
1
  import { BufferGeometry, Camera, FrontSide, GLSL3, Group, IUniform, MaterialParameters, Matrix3, Matrix4, Object3D, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
2
2
  import { debug, getFrame, getTime } from "./utils.js";
3
3
  import { MaterialXContext, MaterialXEnvironment } from "./materialx.js";
4
- import { getUniformValues, Loaders } from "./materialx.helper.js";
4
+ import { generateMaterialPropertiesForUniforms, getUniformValues, Loaders } from "./materialx.helper.js";
5
+ import { cloneUniforms, cloneUniformsGroups } from "three/src/renderers/shaders/UniformsUtils.js";
5
6
 
6
7
 
7
8
  // Add helper matrices for uniform updates (similar to MaterialX example)
@@ -10,13 +11,12 @@ const worldViewPos = new Vector3();
10
11
 
11
12
  declare type MaterialXMaterialInitParameters = {
12
13
  name: string,
14
+ shaderName?: string | null, // Optional name of the shader
13
15
  shader: any,
14
16
  loaders: Loaders,
15
17
  context: MaterialXContext,
16
18
  // Optional parameters
17
- transparent?: boolean,
18
- side?: MaterialParameters['side'],
19
- precision?: MaterialParameters['precision'],
19
+ parameters?: MaterialParameters,
20
20
  }
21
21
 
22
22
  type Uniforms = Record<string, IUniform & { needsUpdate?: boolean }>;
@@ -24,13 +24,25 @@ type Precision = "highp" | "mediump" | "lowp";
24
24
 
25
25
  export class MaterialXMaterial extends ShaderMaterial {
26
26
 
27
+ /** The original name of the shader */
28
+ readonly shaderName : string | null = null;
29
+
27
30
  copy(source: MaterialXMaterial): this {
28
31
  super.copy(source);
29
32
  this._context = source._context;
33
+ this._shader = source._shader;
34
+ this.uniforms = cloneUniforms(source.uniforms) as Uniforms;
35
+ this.uniformsGroups = cloneUniformsGroups(source.uniformsGroups);
36
+ this.envMapIntensity = source.envMapIntensity;
37
+ this.envMap = source.envMap;
38
+ generateMaterialPropertiesForUniforms(this, this._shader.getStage('pixel'));
39
+ generateMaterialPropertiesForUniforms(this, this._shader.getStage('vertex'));
40
+ this.needsUpdate = true;
30
41
  return this;
31
42
  }
32
43
 
33
44
  private _context: MaterialXContext | null = null;
45
+ private _shader: any;
34
46
 
35
47
  constructor(init?: MaterialXMaterialInitParameters) {
36
48
 
@@ -63,7 +75,7 @@ export class MaterialXMaterial extends ShaderMaterial {
63
75
  vertexShader = vertexShader.replace(/\bi_color_0\b/g, 'color');
64
76
 
65
77
  // Patch fragmentShader
66
- const precision = init.precision || "highp" as Precision;
78
+ const precision = init.parameters?.precision || "highp" as Precision;
67
79
  fragmentShader = fragmentShader.replace(/precision mediump float;/g, `precision ${precision} float;`);
68
80
  fragmentShader = fragmentShader.replace(/#define M_FLOAT_EPS 1e-8/g, precision === "highp" ? `#define M_FLOAT_EPS 1e-8` : `#define M_FLOAT_EPS 1e-3`);
69
81
 
@@ -124,19 +136,21 @@ export class MaterialXMaterial extends ShaderMaterial {
124
136
  if (hasColor) defines['USE_COLOR'] = '';
125
137
 
126
138
  const searchPath = ""; // Could be derived from the asset path if needed
127
- const isTransparent = init.transparent ?? false;
139
+ const isTransparent = init.parameters?.transparent ?? false;
128
140
  super({
129
141
  name: init.name,
130
142
  uniforms: {},
131
143
  vertexShader: vertexShader,
132
144
  fragmentShader: fragmentShader,
133
145
  glslVersion: GLSL3,
134
- transparent: isTransparent,
135
- side: init.side ? init.side : FrontSide,
136
146
  depthTest: true,
137
147
  depthWrite: !isTransparent,
138
148
  defines: defines,
149
+ ...init.parameters, // Spread any additional parameters passed to the material
139
150
  });
151
+ this._context = init.context;
152
+ this._shader = init.shader;
153
+ this.shaderName = init.shaderName || null;
140
154
 
141
155
  Object.assign(this.uniforms, {
142
156
  ...getUniformValues(init.shader.getStage('vertex'), init.loaders, searchPath),
@@ -158,7 +172,9 @@ export class MaterialXMaterial extends ShaderMaterial {
158
172
  u_lightData: { value: [], needsUpdate: false }, // Array of light data. We need to set needsUpdate to false until we actually update it
159
173
  });
160
174
 
161
- this._context = init.context;
175
+ generateMaterialPropertiesForUniforms(this, init.shader.getStage('pixel'));
176
+ generateMaterialPropertiesForUniforms(this, init.shader.getStage('vertex'));
177
+
162
178
 
163
179
  if (debug) {
164
180
  // Get lighting and environment data from MaterialX environment
@@ -216,7 +232,7 @@ export class MaterialXMaterial extends ShaderMaterial {
216
232
  if (frame === undefined) frame = getFrame();
217
233
  uniforms.u_frame.value = frame;
218
234
  }
219
-
235
+
220
236
  // Update light uniforms
221
237
  this.updateEnvironmentUniforms(environment);
222
238