@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 +2 -2
- package/src/loader/loader.three.ts +25 -7
- package/src/materialx.helper.ts +48 -3
- package/src/materialx.material.ts +26 -10
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
257
|
-
|
|
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
|
package/src/materialx.helper.ts
CHANGED
|
@@ -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
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|