@needle-tools/materialx 1.1.1-next.b7e5e45 → 1.1.1-next.fb25319
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/bin/.gitattributes +4 -0
- package/bin/README.md +6 -0
- package/{index.ts → index.d.ts} +1 -1
- package/index.js +2 -0
- package/{needle.ts → needle.d.ts} +1 -1
- package/needle.js +2 -0
- package/package.json +22 -8
- package/src/index.d.ts +11 -0
- package/src/{index.ts → index.js} +2 -4
- package/src/loader/loader.needle.d.ts +15 -0
- package/src/loader/loader.needle.js +62 -0
- package/src/loader/loader.three.d.ts +71 -0
- package/src/loader/{loader.three.ts → loader.three.js} +75 -82
- package/src/materialx.d.ts +60 -0
- package/src/materialx.helper.d.ts +31 -0
- package/src/{materialx.helper.ts → materialx.helper.js} +110 -69
- package/src/{materialx.ts → materialx.js} +104 -60
- package/src/materialx.material.d.ts +37 -0
- package/src/{materialx.material.ts → materialx.material.js} +70 -35
- package/src/utils.d.ts +17 -0
- package/src/{utils.ts → utils.js} +18 -5
- package/src/utils.texture.d.ts +13 -0
- package/src/{utils.texture.ts → utils.texture.js} +18 -17
- package/src/loader/loader.needle.ts +0 -43
- package/tsconfig.json +0 -20
|
@@ -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
|
-
*
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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 | null | void>;
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
129
|
+
function toThreeUniform(uniforms, type, value, name, loaders, searchPath) {
|
|
123
130
|
|
|
124
|
-
const uniform = new THREE.Uniform
|
|
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) {
|
|
@@ -182,8 +189,8 @@ function toThreeUniform(uniforms: any, type: string, value: any, name: string, l
|
|
|
182
189
|
else {
|
|
183
190
|
if (debug) console.log('[MaterialX] Load texture:', texturePath);
|
|
184
191
|
|
|
185
|
-
if (name.toLowerCase().includes("normal")) uniform.value = defaultNormalTexture;
|
|
186
|
-
else uniform.value = defaultTexture;
|
|
192
|
+
if (name.toLowerCase().includes("normal")) uniform.value = /** @type {any} */ (defaultNormalTexture);
|
|
193
|
+
else uniform.value = /** @type {any} */ (defaultTexture);
|
|
187
194
|
const defaultValue = uniform.value;
|
|
188
195
|
// Save the loading promise in the cache
|
|
189
196
|
const promise = loaders.getTexture(texturePath)
|
|
@@ -201,9 +208,9 @@ function toThreeUniform(uniforms: any, type: string, value: any, name: string, l
|
|
|
201
208
|
});
|
|
202
209
|
|
|
203
210
|
if (checkCache) addToCache(cacheKey, promise);
|
|
204
|
-
|
|
211
|
+
|
|
205
212
|
promise?.then(res => {
|
|
206
|
-
if (res) uniform.value = res;
|
|
213
|
+
if (res) uniform.value = /** @type {any} */ (res);
|
|
207
214
|
else console.warn(`[MaterialX] Failed to load texture ${name} '${texturePath}'`);
|
|
208
215
|
});
|
|
209
216
|
}
|
|
@@ -224,12 +231,15 @@ function toThreeUniform(uniforms: any, type: string, value: any, name: string, l
|
|
|
224
231
|
return uniform;
|
|
225
232
|
}
|
|
226
233
|
|
|
227
|
-
|
|
234
|
+
/** @type {Map<string, boolean>} */
|
|
235
|
+
const valueTypeWarningMap = new Map();
|
|
228
236
|
|
|
229
237
|
/**
|
|
230
238
|
* Get Three wrapping mode
|
|
239
|
+
* @param {number} mode
|
|
240
|
+
* @returns {THREE.Wrapping}
|
|
231
241
|
*/
|
|
232
|
-
function getWrapping(mode
|
|
242
|
+
function getWrapping(mode) {
|
|
233
243
|
let wrap;
|
|
234
244
|
switch (mode) {
|
|
235
245
|
case 1:
|
|
@@ -248,11 +258,14 @@ function getWrapping(mode: number): THREE.Wrapping {
|
|
|
248
258
|
return wrap;
|
|
249
259
|
}
|
|
250
260
|
|
|
251
|
-
|
|
252
261
|
/**
|
|
253
262
|
* Set Three texture parameters
|
|
263
|
+
* @param {THREE.Texture} texture
|
|
264
|
+
* @param {string} name
|
|
265
|
+
* @param {any} uniforms
|
|
266
|
+
* @param {boolean} [generateMipmaps=true]
|
|
254
267
|
*/
|
|
255
|
-
function setTextureParameters(texture
|
|
268
|
+
function setTextureParameters(texture, name, uniforms, generateMipmaps = true) {
|
|
256
269
|
const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);
|
|
257
270
|
const base = name.substring(0, idx) || name;
|
|
258
271
|
|
|
@@ -267,15 +280,16 @@ function setTextureParameters(texture: THREE.Texture, name: string, uniforms: an
|
|
|
267
280
|
}
|
|
268
281
|
|
|
269
282
|
const mxFilterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1;
|
|
270
|
-
let minFilter
|
|
283
|
+
let minFilter = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter;
|
|
271
284
|
if (mxFilterType === 0) {
|
|
272
|
-
minFilter = generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter;
|
|
285
|
+
minFilter = /** @type {any} */ (generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter);
|
|
273
286
|
}
|
|
274
287
|
texture.minFilter = minFilter;
|
|
275
288
|
}
|
|
276
289
|
|
|
277
290
|
/**
|
|
278
291
|
* Return the global light rotation matrix
|
|
292
|
+
* @returns {THREE.Matrix4}
|
|
279
293
|
*/
|
|
280
294
|
export function getLightRotation() {
|
|
281
295
|
return new THREE.Matrix4().makeRotationY(Math.PI / 2);
|
|
@@ -283,11 +297,11 @@ export function getLightRotation() {
|
|
|
283
297
|
|
|
284
298
|
/**
|
|
285
299
|
* Returns all lights nodes in a MaterialX document
|
|
286
|
-
* @param {
|
|
287
|
-
* @returns {Array
|
|
300
|
+
* @param {any} doc
|
|
301
|
+
* @returns {Array<any>}
|
|
288
302
|
*/
|
|
289
|
-
export function findLights(doc
|
|
290
|
-
let lights = new Array
|
|
303
|
+
export function findLights(doc) {
|
|
304
|
+
let lights = new Array();
|
|
291
305
|
for (let node of doc.getNodes()) {
|
|
292
306
|
if (node.getType() === "lightshader")
|
|
293
307
|
lights.push(node);
|
|
@@ -295,14 +309,16 @@ export function findLights(doc: MaterialX.Document) {
|
|
|
295
309
|
return lights;
|
|
296
310
|
}
|
|
297
311
|
|
|
312
|
+
/** @type {Object<string, number>} */
|
|
298
313
|
let lightTypesBound = {};
|
|
299
314
|
|
|
300
315
|
/**
|
|
301
316
|
* Register lights in shader generation context
|
|
302
|
-
* @param {
|
|
303
|
-
* @param {
|
|
317
|
+
* @param {any} mx - MaterialX Module
|
|
318
|
+
* @param {any} genContext - Shader generation context
|
|
319
|
+
* @returns {Promise<void>}
|
|
304
320
|
*/
|
|
305
|
-
export async function registerLights(mx
|
|
321
|
+
export async function registerLights(mx, genContext) {
|
|
306
322
|
lightTypesBound = {};
|
|
307
323
|
const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
|
|
308
324
|
mx.HwShaderGenerator.unbindLightShaders(genContext);
|
|
@@ -355,7 +371,12 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
|
|
|
355
371
|
if (debug) console.log("Light types bound in MaterialX context", lightTypesBound);
|
|
356
372
|
}
|
|
357
373
|
|
|
358
|
-
|
|
374
|
+
const _lightTypeWarnings = {}
|
|
375
|
+
/**
|
|
376
|
+
* Converts Three.js light type to MaterialX node name
|
|
377
|
+
* @param {string} threeLightType
|
|
378
|
+
* @returns {string|null}
|
|
379
|
+
*/
|
|
359
380
|
function threeLightTypeToMaterialXNodeName(threeLightType) {
|
|
360
381
|
switch (threeLightType) {
|
|
361
382
|
case 'PointLight':
|
|
@@ -365,26 +386,33 @@ function threeLightTypeToMaterialXNodeName(threeLightType) {
|
|
|
365
386
|
case 'SpotLight':
|
|
366
387
|
return 'ND_spot_light';
|
|
367
388
|
default:
|
|
368
|
-
|
|
369
|
-
|
|
389
|
+
if (!_lightTypeWarnings[threeLightType]) {
|
|
390
|
+
_lightTypeWarnings[threeLightType] = true;
|
|
391
|
+
console.warn('MaterialX: Unsupported light type: ' + threeLightType);
|
|
392
|
+
}
|
|
393
|
+
return null; // Unsupported light type
|
|
370
394
|
}
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
export type LightData = {
|
|
374
|
-
type: number, // Light type ID
|
|
375
|
-
position: THREE.Vector3, // Position in world space
|
|
376
|
-
direction: THREE.Vector3, // Direction in world space
|
|
377
|
-
color: THREE.Color, // Color of the light
|
|
378
|
-
intensity: number, // Intensity of the light
|
|
379
|
-
decay_rate: number, // Decay rate for point and spot lights
|
|
380
|
-
inner_angle: number, // Inner angle for spot lights
|
|
381
|
-
outer_angle: number, // Outer angle for spot lights
|
|
382
395
|
}
|
|
383
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
|
+
|
|
384
409
|
/**
|
|
385
410
|
* Update light data for shader uniforms
|
|
411
|
+
* @param {Array<THREE.Light>} lights
|
|
412
|
+
* @param {any} genContext
|
|
413
|
+
* @returns {{ lightData: LightData[], lightCount: number }}
|
|
386
414
|
*/
|
|
387
|
-
export function getLightData(lights
|
|
415
|
+
export function getLightData(lights, genContext) {
|
|
388
416
|
const lightData = new Array();
|
|
389
417
|
const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
|
|
390
418
|
|
|
@@ -397,8 +425,12 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
|
|
|
397
425
|
|
|
398
426
|
const lightDefinitionName = threeLightTypeToMaterialXNodeName(light.type);
|
|
399
427
|
|
|
400
|
-
if
|
|
401
|
-
|
|
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
|
+
}
|
|
402
434
|
|
|
403
435
|
const wp = light.getWorldPosition(new THREE.Vector3());
|
|
404
436
|
const wq = light.getWorldQuaternion(new THREE.Quaternion());
|
|
@@ -410,8 +442,8 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
|
|
|
410
442
|
// float cosDir = dot(result.direction, -light.direction);
|
|
411
443
|
// float spotAttenuation = smoothstep(low, high, cosDir);
|
|
412
444
|
|
|
413
|
-
const outerAngleRad =
|
|
414
|
-
const innerAngleRad = outerAngleRad * (1 -
|
|
445
|
+
const outerAngleRad = /** @type {THREE.SpotLight} */ (light).angle;
|
|
446
|
+
const innerAngleRad = outerAngleRad * (1 - /** @type {THREE.SpotLight} */ (light).penumbra);
|
|
415
447
|
const inner_angle = Math.cos(innerAngleRad);
|
|
416
448
|
const outer_angle = Math.cos(outerAngleRad);
|
|
417
449
|
|
|
@@ -422,7 +454,7 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
|
|
|
422
454
|
color: new THREE.Color().fromArray(light.color.toArray()),
|
|
423
455
|
// Luminous efficacy for converting radiant power in watts (W) to luminous flux in lumens (lm) at a wavelength of 555 nm.
|
|
424
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.
|
|
425
|
-
intensity: light.intensity * (
|
|
457
|
+
intensity: light.intensity * (/** @type {THREE.PointLight} */ (light).isPointLight ? 683.0 / 3.1415 : /** @type {THREE.SpotLight} */ (light).isSpotLight ? 683.0 / 3.1415 : 1.0),
|
|
426
458
|
decay_rate: 2.0,
|
|
427
459
|
// Approximations for testing – the relevant light has 61.57986...129.4445 as inner/outer spot angle
|
|
428
460
|
inner_angle: inner_angle,
|
|
@@ -455,8 +487,13 @@ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lig
|
|
|
455
487
|
|
|
456
488
|
/**
|
|
457
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>}
|
|
458
494
|
*/
|
|
459
|
-
export function getUniformValues(shaderStage
|
|
495
|
+
export function getUniformValues(shaderStage, loaders, searchPath) {
|
|
496
|
+
/** @type {Object<string, THREE.Uniform>} */
|
|
460
497
|
const threeUniforms = {};
|
|
461
498
|
|
|
462
499
|
const uniformBlocks = shaderStage.getUniformBlocks()
|
|
@@ -479,7 +516,11 @@ export function getUniformValues(shaderStage: MaterialX.ShaderStage, loaders: Ca
|
|
|
479
516
|
return threeUniforms;
|
|
480
517
|
}
|
|
481
518
|
|
|
482
|
-
|
|
519
|
+
/**
|
|
520
|
+
* @param {THREE.ShaderMaterial} material
|
|
521
|
+
* @param {any} shaderStage
|
|
522
|
+
*/
|
|
523
|
+
export function generateMaterialPropertiesForUniforms(material, shaderStage) {
|
|
483
524
|
|
|
484
525
|
const uniformBlocks = shaderStage.getUniformBlocks()
|
|
485
526
|
for (const [blockName, uniforms] of Object.entries(uniformBlocks)) {
|
|
@@ -1,30 +1,27 @@
|
|
|
1
|
-
import type { MaterialX as MX } from "./materialx.types.js";
|
|
2
1
|
import MaterialX from "../bin/JsMaterialXGenShader.js";
|
|
3
2
|
import { debug } from "./utils.js";
|
|
4
3
|
import { renderPMREMToEquirect } from "./utils.texture.js";
|
|
5
4
|
import { Light, Mesh, MeshBasicMaterial, Object3D, PlaneGeometry, PMREMGenerator, Scene, Texture, WebGLRenderer } from "three";
|
|
6
|
-
import { registerLights, getLightData
|
|
7
|
-
import type { MaterialXMaterial } from "./materialx.material.js";
|
|
8
|
-
|
|
9
|
-
export type MaterialXContext = {
|
|
10
|
-
getTime?(): number,
|
|
11
|
-
getFrame?(): number,
|
|
12
|
-
}
|
|
13
|
-
|
|
5
|
+
import { registerLights, getLightData } from "./materialx.helper.js";
|
|
14
6
|
|
|
15
7
|
export const state = new class {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
/** @type {import("./materialx.types.js").MaterialX.MODULE | null} */
|
|
9
|
+
materialXModule = null;
|
|
10
|
+
/** @type {any} */
|
|
11
|
+
materialXGenerator = null;
|
|
12
|
+
/** @type {any} */
|
|
13
|
+
materialXGenContext = null;
|
|
14
|
+
/** @type {any} */
|
|
15
|
+
materialXStdLib = null;
|
|
16
|
+
/** @type {Promise<void> | null} */
|
|
17
|
+
materialXInitPromise = null;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
|
|
24
20
|
/**
|
|
25
21
|
* Wait for the MaterialX WASM module to be ready.
|
|
22
|
+
* @returns {Promise<void>}
|
|
26
23
|
*/
|
|
27
|
-
export async function ready()
|
|
24
|
+
export async function ready() {
|
|
28
25
|
if (state.materialXInitPromise) {
|
|
29
26
|
return state.materialXInitPromise;
|
|
30
27
|
}
|
|
@@ -33,18 +30,19 @@ export async function ready(): Promise<void> {
|
|
|
33
30
|
if (debug) console.log("[MaterialX] Initializing WASM module...");
|
|
34
31
|
try {
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
/** @type {Array<string>} */
|
|
34
|
+
const urls = await Promise.all([
|
|
37
35
|
/** @ts-ignore */
|
|
38
|
-
import(`../bin/JsMaterialXCore.wasm?url`).then(m => m.default || m),
|
|
36
|
+
import( /* @vite-ignore */ `../bin/JsMaterialXCore.wasm?url`).then(m => m.default || m),
|
|
39
37
|
/** @ts-ignore */
|
|
40
|
-
import(`../bin/JsMaterialXGenShader.wasm?url`).then(m => m.default || m),
|
|
38
|
+
import( /* @vite-ignore */ `../bin/JsMaterialXGenShader.wasm?url`).then(m => m.default || m),
|
|
41
39
|
/** @ts-ignore */
|
|
42
|
-
import(`../bin/JsMaterialXGenShader.data.txt?url`).then(m => m.default || m),
|
|
40
|
+
import( /* @vite-ignore */ `../bin/JsMaterialXGenShader.data.txt?url`).then(m => m.default || m),
|
|
43
41
|
]);
|
|
44
42
|
const [JsMaterialXCore, JsMaterialXGenShader, JsMaterialXGenShader_data] = urls;
|
|
45
43
|
|
|
46
44
|
const module = await MaterialX({
|
|
47
|
-
locateFile: (
|
|
45
|
+
locateFile: (/** @type {string} */ path, /** @type {string} */ scriptDirectory) => {
|
|
48
46
|
if (debug) console.debug("[MaterialX] locateFile called:", { path, scriptDirectory });
|
|
49
47
|
|
|
50
48
|
if (path.includes("JsMaterialXCore.wasm")) {
|
|
@@ -61,7 +59,7 @@ export async function ready(): Promise<void> {
|
|
|
61
59
|
},
|
|
62
60
|
});
|
|
63
61
|
if (debug) console.log("[MaterialX] module loaded", module);
|
|
64
|
-
state.materialXModule =
|
|
62
|
+
state.materialXModule = /** @type {import("./materialx.types.js").MaterialX.MODULE} */ (module);
|
|
65
63
|
|
|
66
64
|
// Initialize shader generator and context
|
|
67
65
|
state.materialXGenerator = module.EsslShaderGenerator.create();
|
|
@@ -108,45 +106,69 @@ export async function ready(): Promise<void> {
|
|
|
108
106
|
})();
|
|
109
107
|
}
|
|
110
108
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
109
|
+
/**
|
|
110
|
+
* @typedef {Object} EnvironmentTextureSet
|
|
111
|
+
* @property {Texture | null} radianceTexture
|
|
112
|
+
* @property {Texture | null} irradianceTexture
|
|
113
|
+
*/
|
|
116
114
|
|
|
117
115
|
/**
|
|
118
116
|
* MaterialXEnvironment manages the environment settings for MaterialX materials.
|
|
119
117
|
*/
|
|
120
118
|
export class MaterialXEnvironment {
|
|
121
119
|
|
|
122
|
-
|
|
120
|
+
/**
|
|
121
|
+
* @param {Scene} scene
|
|
122
|
+
* @returns {MaterialXEnvironment | null}
|
|
123
|
+
*/
|
|
124
|
+
static get(scene) {
|
|
123
125
|
return this.getEnvironment(scene);
|
|
124
126
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
|
|
128
|
+
/** @type {WeakMap<Scene, MaterialXEnvironment>} */
|
|
129
|
+
static _environments = new Map();
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {Scene} scene
|
|
133
|
+
* @returns {MaterialXEnvironment}
|
|
134
|
+
*/
|
|
135
|
+
static getEnvironment(scene) {
|
|
127
136
|
if (this._environments.has(scene)) {
|
|
128
|
-
return this._environments.get(scene)
|
|
137
|
+
return /** @type {MaterialXEnvironment} */ (this._environments.get(scene));
|
|
129
138
|
}
|
|
130
139
|
const env = new MaterialXEnvironment(scene);
|
|
131
140
|
this._environments.set(scene, env);
|
|
132
141
|
return env;
|
|
133
142
|
}
|
|
134
143
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
/** @type {Array<Light>} */
|
|
145
|
+
_lights = [];
|
|
146
|
+
/** @type {import("./materialx.helper.js").LightData[] | null} */
|
|
147
|
+
_lightData = null;
|
|
148
|
+
/** @type {number} */
|
|
149
|
+
_lightCount = 0;
|
|
150
|
+
|
|
151
|
+
/** @type {Promise<boolean> | null} */
|
|
152
|
+
_initializePromise = null;
|
|
153
|
+
/** @type {boolean} */
|
|
154
|
+
_isInitialized = false;
|
|
155
|
+
/** @type {number} */
|
|
156
|
+
_lastUpdateFrame = -1;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @param {Scene} _scene
|
|
160
|
+
*/
|
|
161
|
+
constructor(_scene) {
|
|
162
|
+
this._scene = _scene;
|
|
145
163
|
if (debug) console.log("[MaterialX] Environment created");
|
|
146
164
|
}
|
|
147
165
|
|
|
148
|
-
|
|
149
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Initialize with Needle Engine context
|
|
168
|
+
* @param {WebGLRenderer} renderer
|
|
169
|
+
* @returns {Promise<boolean>}
|
|
170
|
+
*/
|
|
171
|
+
async initialize(renderer) {
|
|
150
172
|
if (this._initializePromise) {
|
|
151
173
|
return this._initializePromise;
|
|
152
174
|
}
|
|
@@ -154,7 +176,12 @@ export class MaterialXEnvironment {
|
|
|
154
176
|
return this._initializePromise;
|
|
155
177
|
}
|
|
156
178
|
|
|
157
|
-
|
|
179
|
+
/**
|
|
180
|
+
* @param {number} frame
|
|
181
|
+
* @param {Scene} scene
|
|
182
|
+
* @param {WebGLRenderer} renderer
|
|
183
|
+
*/
|
|
184
|
+
update(frame, scene, renderer) {
|
|
158
185
|
if (!this._initializePromise) {
|
|
159
186
|
this.initialize(renderer);
|
|
160
187
|
return;
|
|
@@ -220,7 +247,11 @@ export class MaterialXEnvironment {
|
|
|
220
247
|
return this._lightData;
|
|
221
248
|
}
|
|
222
249
|
get lightCount() { return this._lightCount || 0; }
|
|
223
|
-
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @param {import("./materialx.material.js").MaterialXMaterial} material
|
|
253
|
+
*/
|
|
254
|
+
getTextures(material) {
|
|
224
255
|
if (material.envMap) {
|
|
225
256
|
// If the material has its own envMap, we don't use the irradiance texture
|
|
226
257
|
return this._getTextures(material.envMap);
|
|
@@ -228,11 +259,18 @@ export class MaterialXEnvironment {
|
|
|
228
259
|
return this._getTextures(this._scene.environment);
|
|
229
260
|
}
|
|
230
261
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
262
|
+
/** @type {PMREMGenerator | null} */
|
|
263
|
+
_pmremGenerator = null;
|
|
264
|
+
/** @type {WebGLRenderer | null} */
|
|
265
|
+
_renderer = null;
|
|
266
|
+
/** @type {Map<Texture | null, EnvironmentTextureSet>} */
|
|
267
|
+
_texturesCache = new Map();
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @param {WebGLRenderer} renderer
|
|
271
|
+
* @returns {Promise<boolean>}
|
|
272
|
+
*/
|
|
273
|
+
async _initialize(renderer) {
|
|
236
274
|
this._isInitialized = false;
|
|
237
275
|
this._pmremGenerator = new PMREMGenerator(renderer);
|
|
238
276
|
this._renderer = renderer;
|
|
@@ -241,11 +279,13 @@ export class MaterialXEnvironment {
|
|
|
241
279
|
return true;
|
|
242
280
|
}
|
|
243
281
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
282
|
+
/**
|
|
283
|
+
* @param {Texture | null | undefined} texture
|
|
284
|
+
* @returns {{radianceTexture: Texture | null, irradianceTexture: Texture | null}}
|
|
285
|
+
*/
|
|
286
|
+
_getTextures(texture) {
|
|
287
|
+
/** @type {EnvironmentTextureSet | undefined} */
|
|
288
|
+
let res = this._texturesCache.get(texture || null);
|
|
249
289
|
if (res) {
|
|
250
290
|
return res;
|
|
251
291
|
}
|
|
@@ -271,14 +311,18 @@ export class MaterialXEnvironment {
|
|
|
271
311
|
return res;
|
|
272
312
|
}
|
|
273
313
|
|
|
274
|
-
|
|
314
|
+
/**
|
|
315
|
+
* @param {boolean} collectLights
|
|
316
|
+
*/
|
|
317
|
+
updateLighting = (collectLights = false) => {
|
|
275
318
|
if (!this._scene) return;
|
|
276
319
|
// Find lights in scene
|
|
277
320
|
if (collectLights) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
321
|
+
/** @type {Array<Light>} */
|
|
322
|
+
const lights = new Array();
|
|
323
|
+
this._scene.traverse((/** @type {Object3D} */ object) => {
|
|
324
|
+
if ((/** @type {Light} */ (object)).isLight && object.visible)
|
|
325
|
+
lights.push(/** @type {Light} */ (object));
|
|
282
326
|
});
|
|
283
327
|
this._lights = lights;
|
|
284
328
|
}
|