@needle-tools/materialx 1.6.0-next.2af5fc1 → 1.7.0-next.0d06218
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/CHANGELOG.md +15 -1
- package/README.md +33 -1
- package/bin/JsMaterialXCore.js +5 -13
- package/bin/JsMaterialXCore.wasm +0 -0
- package/bin/JsMaterialXGenShader.data.txt +2127 -2453
- package/bin/JsMaterialXGenShader.js +5 -13
- package/bin/JsMaterialXGenShader.wasm +0 -0
- package/bin/revision.json +3 -3
- package/package.json +10 -6
- package/src/index.d.ts +1 -2
- package/src/loader/loader.three.d.ts +10 -1
- package/src/loader/loader.three.js +26 -19
- package/src/materialx.d.ts +9 -5
- package/src/materialx.helper.d.ts +1 -1
- package/src/materialx.helper.js +97 -42
- package/src/materialx.js +83 -24
- package/src/materialx.material.d.ts +11 -2
- package/src/materialx.material.js +512 -10
- package/src/materialx.types.d.ts +65 -10
- package/src/utils.texture.d.ts +11 -0
- package/src/utils.texture.js +194 -37
- /package/bin/{SHA_0e7685f37737511f2816949b9486d511a5fa71bd → SHA_ab218c56f016a9a2d398e8d306f3aeb439ae9e9e} +0 -0
|
Binary file
|
package/bin/revision.json
CHANGED
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/materialx",
|
|
3
3
|
"description": "MaterialX material support for three.js and Needle Engine – render physically based MaterialX shaders in the browser via WebAssembly",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.7.0-next.0d06218",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
+
"types": "./index.d.ts",
|
|
10
11
|
"import": "./index.js",
|
|
11
|
-
"require": "./index.js"
|
|
12
|
-
"types": "./index.d.ts"
|
|
12
|
+
"require": "./index.js"
|
|
13
13
|
},
|
|
14
14
|
"./needle": {
|
|
15
|
+
"types": "./needle.d.ts",
|
|
15
16
|
"import": "./needle.js",
|
|
16
|
-
"require": "./needle.js"
|
|
17
|
-
"types": "./needle.d.ts"
|
|
17
|
+
"require": "./needle.js"
|
|
18
18
|
},
|
|
19
19
|
"./package.json": "./package.json",
|
|
20
20
|
"./codegen/register_types.ts": {
|
|
@@ -66,5 +66,9 @@
|
|
|
66
66
|
"pbr",
|
|
67
67
|
"3d",
|
|
68
68
|
"wasm"
|
|
69
|
-
]
|
|
69
|
+
],
|
|
70
|
+
"repository": {
|
|
71
|
+
"type": "git",
|
|
72
|
+
"url": "https://github.com/needle-tools/needle-engine-materialx.git"
|
|
73
|
+
}
|
|
70
74
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ready, type MaterialXContext, preloadWasm } from "./materialx.js";
|
|
1
|
+
export { ready, type MaterialXContext, type MaterialXEnvironmentRadianceMode, preloadWasm } from "./materialx.js";
|
|
2
2
|
export { MaterialXEnvironment } from "./materialx.js";
|
|
3
3
|
export { MaterialXMaterial } from "./materialx.material.js";
|
|
4
4
|
export { MaterialXLoader } from "./loader/loader.three.js";
|
|
@@ -10,4 +10,3 @@ declare const Experimental_API: {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export { Experimental_API };
|
|
13
|
-
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Material, MaterialParameters } from "three";
|
|
2
2
|
import { GLTFLoader, GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
3
|
import { MaterialXContext } from "../materialx.js";
|
|
4
|
+
import type { MaterialXEnvironmentRadianceMode } from "../materialx.js";
|
|
4
5
|
import { MaterialXMaterial } from "../materialx.material.js";
|
|
5
6
|
import { Callbacks } from "../materialx.helper.js";
|
|
6
7
|
|
|
@@ -39,6 +40,14 @@ export interface MaterialXLoaderOptions {
|
|
|
39
40
|
cacheKey?: string;
|
|
40
41
|
/** Parameters for the MaterialX loader */
|
|
41
42
|
parameters?: Pick<MaterialParameters, "precision">;
|
|
43
|
+
/** Environment radiance backend. Defaults to direct Three.js CubeUV PMREM sampling. */
|
|
44
|
+
environmentRadianceMode?: MaterialXEnvironmentRadianceMode;
|
|
45
|
+
/** Match Three.js glossy specular antialiasing. Defaults to true. */
|
|
46
|
+
specularAntialiasing?: boolean;
|
|
47
|
+
/** Flip texcoord V at the MaterialX texcoord node output. Defaults to false for standalone .mtlx creation and true for GLTFLoader integration. */
|
|
48
|
+
hwTexcoordVerticalFlip?: boolean;
|
|
49
|
+
/** Flip texcoord V inside MaterialX file texture sampling. Defaults to false for standalone .mtlx creation and true for GLTFLoader integration. */
|
|
50
|
+
fileTextureVerticalFlip?: boolean;
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
export declare class MaterialXLoader implements GLTFLoaderPlugin {
|
|
@@ -71,7 +80,7 @@ export declare function useNeedleMaterialX(
|
|
|
71
80
|
export declare function createMaterialXMaterial(
|
|
72
81
|
mtlx: string,
|
|
73
82
|
materialNodeName: string | number,
|
|
74
|
-
loaders
|
|
83
|
+
loaders?: Callbacks,
|
|
75
84
|
options?: MaterialXLoaderOptions,
|
|
76
85
|
context?: MaterialXContext
|
|
77
86
|
): Promise<Material>;
|
|
@@ -61,7 +61,11 @@ export class MaterialXLoader {
|
|
|
61
61
|
*/
|
|
62
62
|
constructor(parser, options, context) {
|
|
63
63
|
this.parser = parser;
|
|
64
|
-
this.options =
|
|
64
|
+
this.options = {
|
|
65
|
+
...options,
|
|
66
|
+
hwTexcoordVerticalFlip: options?.hwTexcoordVerticalFlip ?? true,
|
|
67
|
+
fileTextureVerticalFlip: options?.fileTextureVerticalFlip ?? true,
|
|
68
|
+
};
|
|
65
69
|
this.context = context;
|
|
66
70
|
|
|
67
71
|
if (debug) console.log("MaterialXLoader created for parser");
|
|
@@ -182,7 +186,7 @@ export function useNeedleMaterialX(loader, options, context) {
|
|
|
182
186
|
/**
|
|
183
187
|
* Parse the MaterialX document once and cache it
|
|
184
188
|
* @param {string} mtlx
|
|
185
|
-
* @returns {Promise<
|
|
189
|
+
* @returns {Promise<import("../materialx.types.js").MaterialX.Document>}
|
|
186
190
|
*/
|
|
187
191
|
async function load(mtlx) {
|
|
188
192
|
// Ensure MaterialX is initialized
|
|
@@ -202,7 +206,7 @@ async function load(mtlx) {
|
|
|
202
206
|
/**
|
|
203
207
|
* @param {string} mtlx
|
|
204
208
|
* @param {string | number} materialNodeNameOrIndex
|
|
205
|
-
* @param {import('../materialx.helper.js').Callbacks} loaders
|
|
209
|
+
* @param {import('../materialx.helper.js').Callbacks} [loaders]
|
|
206
210
|
* @param {MaterialXLoaderOptions} [options]
|
|
207
211
|
* @param {import('../materialx.js').MaterialXContext} [context]
|
|
208
212
|
* @returns {Promise<Material>}
|
|
@@ -210,6 +214,10 @@ async function load(mtlx) {
|
|
|
210
214
|
export async function createMaterialXMaterial(mtlx, materialNodeNameOrIndex, loaders, options, context) {
|
|
211
215
|
try {
|
|
212
216
|
if (debug) console.log(`Creating MaterialX material: ${materialNodeNameOrIndex}`);
|
|
217
|
+
loaders ??= {
|
|
218
|
+
getTexture: async () => null,
|
|
219
|
+
};
|
|
220
|
+
|
|
213
221
|
|
|
214
222
|
const doc = await load(mtlx);
|
|
215
223
|
|
|
@@ -234,7 +242,7 @@ export async function createMaterialXMaterial(mtlx, materialNodeNameOrIndex, loa
|
|
|
234
242
|
for (let i = 0; i < materialNodes.length; ++i) {
|
|
235
243
|
const materialNode = materialNodes[i];
|
|
236
244
|
if (materialNode) {
|
|
237
|
-
const name = materialNode.getNamePath();
|
|
245
|
+
const name = materialNode.getNamePath?.();
|
|
238
246
|
if (debug) console.log(`[MaterialX] Scan material[${i}]: ${name}`);
|
|
239
247
|
|
|
240
248
|
// Find the matching material
|
|
@@ -320,25 +328,21 @@ export async function createMaterialXMaterial(mtlx, materialNodeNameOrIndex, loa
|
|
|
320
328
|
: (state.materialXModule.isTransparentSurface(renderableElement, target) ? "blend" : "opaque");
|
|
321
329
|
const isMask = alphaMode === "mask";
|
|
322
330
|
const isBlend = alphaMode === "blend";
|
|
331
|
+
const renderAsTransparent = isBlend;
|
|
323
332
|
// Both MASK and BLEND need alpha handling in the generated shader.
|
|
324
333
|
const needsAlpha = isMask || isBlend;
|
|
325
334
|
|
|
326
|
-
// Emscripten's getOptions() returns a temporary wrapper
|
|
327
|
-
//
|
|
328
|
-
// matter for generation in a single block right before generate().
|
|
335
|
+
// Emscripten's getOptions() returns a temporary wrapper; set all options
|
|
336
|
+
// that matter for generation in one block right before generate().
|
|
329
337
|
{
|
|
330
338
|
const opts = state.materialXGenContext.getOptions();
|
|
331
339
|
// MASK and BLEND need alpha handling in the generated shader.
|
|
332
340
|
opts.hwTransparency = needsAlpha;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
// convention. With hwTexcoordVerticalFlip flipping UV data, texture
|
|
339
|
-
// sampling needs to flip back to match. fileTextureVerticalFlip does
|
|
340
|
-
// this inside mx_transform_uv.
|
|
341
|
-
opts.fileTextureVerticalFlip = true;
|
|
341
|
+
opts.hwTexcoordVerticalFlip = options?.hwTexcoordVerticalFlip ?? false;
|
|
342
|
+
opts.fileTextureVerticalFlip = options?.fileTextureVerticalFlip ?? false;
|
|
343
|
+
opts.hwSpecularEnvironmentMethod = options?.environmentRadianceMode === "materialx-fis"
|
|
344
|
+
? state.materialXModule.HwSpecularEnvironmentMethod.SPECULAR_ENVIRONMENT_FIS
|
|
345
|
+
: state.materialXModule.HwSpecularEnvironmentMethod.SPECULAR_ENVIRONMENT_PREFILTER;
|
|
342
346
|
}
|
|
343
347
|
|
|
344
348
|
// Generate shaders using the element's name path
|
|
@@ -348,19 +352,22 @@ export async function createMaterialXMaterial(mtlx, materialNodeNameOrIndex, loa
|
|
|
348
352
|
const shader = state.materialXGenerator.generate(elementName, renderableElement, state.materialXGenContext);
|
|
349
353
|
|
|
350
354
|
const shaderMaterial = new MaterialXMaterial({
|
|
351
|
-
name: materialNodeNameOrIndex
|
|
355
|
+
name: typeof elementName === "string" ? elementName : `MaterialX_${materialNodeNameOrIndex}`,
|
|
352
356
|
shaderName: null, //shaderInfo?.originalName || shaderInfo?.name || null,
|
|
353
357
|
shader,
|
|
354
358
|
context: context || {},
|
|
359
|
+
environmentRadianceMode: options?.environmentRadianceMode,
|
|
360
|
+
specularAntialiasing: options?.specularAntialiasing,
|
|
355
361
|
parameters: {
|
|
356
|
-
// MASK
|
|
357
|
-
transparent:
|
|
362
|
+
// MASK uses discard; BLEND uses Three.js transparent sorting and blending.
|
|
363
|
+
transparent: renderAsTransparent,
|
|
358
364
|
// For MASK mode, set alphaTest so Three.js enables alpha testing
|
|
359
365
|
alphaTest: isMask ? 0.0001 : 0,
|
|
360
366
|
...options?.parameters,
|
|
361
367
|
},
|
|
362
368
|
loaders: loaders,
|
|
363
369
|
});
|
|
370
|
+
await shaderMaterial.ready;
|
|
364
371
|
|
|
365
372
|
// Add debugging to see if the material compiles correctly
|
|
366
373
|
if (debug) console.log("[MaterialX] material created:", shaderMaterial.name);
|
package/src/materialx.d.ts
CHANGED
|
@@ -34,13 +34,14 @@ export type MaterialXContext = {
|
|
|
34
34
|
type EnvironmentTextureSet = {
|
|
35
35
|
radianceTexture: Texture | null;
|
|
36
36
|
irradianceTexture: Texture | null;
|
|
37
|
+
dispose?: () => void;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export declare const state: {
|
|
40
41
|
materialXModule: MX.MODULE | null;
|
|
41
|
-
materialXGenerator:
|
|
42
|
-
materialXGenContext:
|
|
43
|
-
materialXStdLib:
|
|
42
|
+
materialXGenerator: MX.MODULE["HwShaderGenerator"] | null;
|
|
43
|
+
materialXGenContext: MX.GenContext | null;
|
|
44
|
+
materialXStdLib: MX.StandardLibrary | null;
|
|
44
45
|
materialXInitPromise: Promise<void> | null;
|
|
45
46
|
};
|
|
46
47
|
|
|
@@ -83,8 +84,11 @@ export declare class MaterialXEnvironment {
|
|
|
83
84
|
|
|
84
85
|
private _pmremGenerator: any | null;
|
|
85
86
|
private _renderer: WebGLRenderer | null;
|
|
86
|
-
private _texturesCache: Map<Texture | null, EnvironmentTextureSet
|
|
87
|
+
private _texturesCache: Map<Texture | null, Map<string, EnvironmentTextureSet>>;
|
|
87
88
|
private _initialize(renderer: WebGLRenderer): Promise<boolean>;
|
|
88
|
-
private _getTextures(texture: Texture | null | undefined): EnvironmentTextureSet;
|
|
89
|
+
private _getTextures(texture: Texture | null | undefined, radianceMode?: MaterialXEnvironmentRadianceMode): EnvironmentTextureSet;
|
|
90
|
+
private _getPMREMGenerator(): any;
|
|
89
91
|
private updateLighting(collectLights?: boolean): void;
|
|
90
92
|
}
|
|
93
|
+
|
|
94
|
+
export type MaterialXEnvironmentRadianceMode = "three-pmrem" | "materialx-prefiltered" | "materialx-fis";
|
|
@@ -28,6 +28,6 @@ export function registerLights(mx: any, genContext: any): Promise<void>;
|
|
|
28
28
|
|
|
29
29
|
export function getLightData(lights: Array<THREE.Light>, genContext: any): { lightData: LightData[], lightCount: number };
|
|
30
30
|
|
|
31
|
-
export function getUniformValues(shaderStage: any, loaders
|
|
31
|
+
export function getUniformValues(shaderStage: any, loaders?: Callbacks, searchPath?: string): Record<string, THREE.Uniform>;
|
|
32
32
|
|
|
33
33
|
export function generateMaterialPropertiesForUniforms(material: THREE.ShaderMaterial, shaderStage: any): void;
|
package/src/materialx.helper.js
CHANGED
|
@@ -36,17 +36,11 @@ export function prepareEnvTexture(texture, capabilities) {
|
|
|
36
36
|
* @returns {Array<number>}
|
|
37
37
|
*/
|
|
38
38
|
function fromVector(value, dimension) {
|
|
39
|
-
|
|
40
|
-
if (value)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
outValue = [];
|
|
45
|
-
for (let i = 0; i < dimension; ++i)
|
|
46
|
-
outValue.push(0.0);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return outValue;
|
|
39
|
+
if (!value) return Array(dimension).fill(0.0);
|
|
40
|
+
if (typeof value.data === "function") return [...value.data()];
|
|
41
|
+
if (typeof value.getData === "function") return fromVector(value.getData(), dimension);
|
|
42
|
+
if (typeof value !== "string" && typeof value[Symbol.iterator] === "function") return [...value];
|
|
43
|
+
return Array(dimension).fill(0.0);
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
/**
|
|
@@ -56,7 +50,7 @@ function fromVector(value, dimension) {
|
|
|
56
50
|
* @returns {Array<number>}
|
|
57
51
|
*/
|
|
58
52
|
function fromMatrix(matrix, dimension) {
|
|
59
|
-
const vec =
|
|
53
|
+
const vec = [];
|
|
60
54
|
if (matrix) {
|
|
61
55
|
for (let i = 0; i < matrix.numRows(); ++i) {
|
|
62
56
|
for (let k = 0; k < matrix.numColumns(); ++k) {
|
|
@@ -125,9 +119,10 @@ function addToCache(key, value) {
|
|
|
125
119
|
* @param {string} name
|
|
126
120
|
* @param {Callbacks} loaders
|
|
127
121
|
* @param {string} searchPath
|
|
122
|
+
* @param {Array<Promise<unknown>>} [pendingTextureLoads]
|
|
128
123
|
* @returns {THREE.Uniform}
|
|
129
124
|
*/
|
|
130
|
-
function toThreeUniform(uniforms, type, value, name, loaders, searchPath) {
|
|
125
|
+
function toThreeUniform(threeUniforms, uniforms, type, value, name, loaders, searchPath, pendingTextureLoads) {
|
|
131
126
|
|
|
132
127
|
const uniform = new THREE.Uniform(/** @type {any} */(null));
|
|
133
128
|
|
|
@@ -178,13 +173,22 @@ function toThreeUniform(uniforms, type, value, name, loaders, searchPath) {
|
|
|
178
173
|
if (cacheValue) {
|
|
179
174
|
if (debug) console.log('[MaterialX] Use cached texture: ', cacheKey, cacheValue);
|
|
180
175
|
if (cacheValue instanceof Promise) {
|
|
181
|
-
cacheValue.then(res => {
|
|
182
|
-
if (res)
|
|
176
|
+
const trackedLoad = cacheValue.then(res => {
|
|
177
|
+
if (res) {
|
|
178
|
+
uniform.value = res;
|
|
179
|
+
if (threeUniforms[name + "_flipY"]) threeUniforms[name + "_flipY"].value = !!res.flipY;
|
|
180
|
+
}
|
|
183
181
|
else console.warn(`[MaterialX] Failed to load texture ${name} '${texturePath}'`);
|
|
182
|
+
return res;
|
|
183
|
+
}).catch(err => {
|
|
184
|
+
console.error(`[MaterialX] Failed to load texture ${name} '${texturePath}'`, err);
|
|
185
|
+
return null;
|
|
184
186
|
});
|
|
187
|
+
pendingTextureLoads?.push(trackedLoad);
|
|
185
188
|
}
|
|
186
189
|
else {
|
|
187
190
|
uniform.value = cacheValue;
|
|
191
|
+
if (threeUniforms[name + "_flipY"]) threeUniforms[name + "_flipY"].value = !!cacheValue.flipY;
|
|
188
192
|
}
|
|
189
193
|
}
|
|
190
194
|
else {
|
|
@@ -197,9 +201,9 @@ function toThreeUniform(uniforms, type, value, name, loaders, searchPath) {
|
|
|
197
201
|
const promise = loaders.getTexture(texturePath)
|
|
198
202
|
?.then(res => {
|
|
199
203
|
if (res) {
|
|
200
|
-
res = res.clone(); // we need to clone the texture once to avoid colorSpace issues with other materials
|
|
201
204
|
res.colorSpace = THREE.LinearSRGBColorSpace;
|
|
202
205
|
setTextureParameters(res, name, uniforms);
|
|
206
|
+
res.needsUpdate = true;
|
|
203
207
|
}
|
|
204
208
|
return res;
|
|
205
209
|
})
|
|
@@ -210,15 +214,21 @@ function toThreeUniform(uniforms, type, value, name, loaders, searchPath) {
|
|
|
210
214
|
|
|
211
215
|
if (checkCache) addToCache(cacheKey, promise);
|
|
212
216
|
|
|
213
|
-
promise?.then(res => {
|
|
217
|
+
const trackedLoad = promise?.then(res => {
|
|
214
218
|
// Replace Promise cache entry with the resolved texture value.
|
|
215
219
|
// This avoids keeping long-lived promise/closure graphs in THREE.Cache.
|
|
216
220
|
if (checkCache && res) addToCache(cacheKey, res);
|
|
217
|
-
if (res)
|
|
221
|
+
if (res) {
|
|
222
|
+
uniform.value = /** @type {any} */ (res);
|
|
223
|
+
if (threeUniforms[name + "_flipY"]) threeUniforms[name + "_flipY"].value = !!res.flipY;
|
|
224
|
+
}
|
|
218
225
|
else console.warn(`[MaterialX] Failed to load texture ${name} '${texturePath}'`);
|
|
226
|
+
return res;
|
|
219
227
|
});
|
|
228
|
+
if (trackedLoad) pendingTextureLoads?.push(trackedLoad);
|
|
220
229
|
}
|
|
221
230
|
}
|
|
231
|
+
threeUniforms[name + "_flipY"] = new THREE.Uniform(!!uniform.value?.flipY);
|
|
222
232
|
break;
|
|
223
233
|
case 'samplerCube':
|
|
224
234
|
case 'string':
|
|
@@ -248,23 +258,69 @@ const valueTypeWarningMap = new Map();
|
|
|
248
258
|
* @param {number} mode
|
|
249
259
|
* @returns {THREE.Wrapping}
|
|
250
260
|
*/
|
|
261
|
+
function getAddressMode(mode) {
|
|
262
|
+
if (typeof mode === "number") return mode;
|
|
263
|
+
switch (String(mode ?? "").toLowerCase()) {
|
|
264
|
+
case "constant":
|
|
265
|
+
return 0;
|
|
266
|
+
case "clamp":
|
|
267
|
+
return 1;
|
|
268
|
+
case "periodic":
|
|
269
|
+
return 2;
|
|
270
|
+
case "mirror":
|
|
271
|
+
return 3;
|
|
272
|
+
default:
|
|
273
|
+
return 2;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get Three wrapping mode
|
|
279
|
+
* @param {unknown} mode
|
|
280
|
+
* @returns {THREE.Wrapping}
|
|
281
|
+
*/
|
|
251
282
|
function getWrapping(mode) {
|
|
252
|
-
|
|
253
|
-
|
|
283
|
+
switch (getAddressMode(mode)) {
|
|
284
|
+
case 0:
|
|
254
285
|
case 1:
|
|
255
|
-
|
|
256
|
-
break;
|
|
257
|
-
case 2:
|
|
258
|
-
wrap = THREE.RepeatWrapping;
|
|
259
|
-
break;
|
|
286
|
+
return THREE.ClampToEdgeWrapping;
|
|
260
287
|
case 3:
|
|
261
|
-
|
|
262
|
-
|
|
288
|
+
return THREE.MirroredRepeatWrapping;
|
|
289
|
+
case 2:
|
|
263
290
|
default:
|
|
264
|
-
|
|
265
|
-
|
|
291
|
+
return THREE.RepeatWrapping;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* @param {unknown} mode
|
|
297
|
+
* @returns {number}
|
|
298
|
+
*/
|
|
299
|
+
function getFilterType(mode) {
|
|
300
|
+
if (typeof mode === "number") return mode;
|
|
301
|
+
switch (String(mode ?? "").toLowerCase()) {
|
|
302
|
+
case "closest":
|
|
303
|
+
return 0;
|
|
304
|
+
case "linear":
|
|
305
|
+
return 1;
|
|
306
|
+
default:
|
|
307
|
+
return -1;
|
|
266
308
|
}
|
|
267
|
-
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* @param {any} uniforms
|
|
313
|
+
* @param {string} name
|
|
314
|
+
* @param {any} defaultValue
|
|
315
|
+
* @returns {any}
|
|
316
|
+
*/
|
|
317
|
+
function getUniformData(uniforms, name, defaultValue) {
|
|
318
|
+
const uniform = uniforms?.find?.(name);
|
|
319
|
+
const value = uniform?.getValue?.();
|
|
320
|
+
if (!value) return defaultValue;
|
|
321
|
+
if (typeof value.getData === "function") return value.getData();
|
|
322
|
+
if (typeof value.data === "function") return value.data();
|
|
323
|
+
return defaultValue;
|
|
268
324
|
}
|
|
269
325
|
|
|
270
326
|
/**
|
|
@@ -278,22 +334,18 @@ function setTextureParameters(texture, name, uniforms, generateMipmaps = true) {
|
|
|
278
334
|
const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);
|
|
279
335
|
const base = name.substring(0, idx) || name;
|
|
280
336
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
texture.wrapS = getWrapping(uaddressmode);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (uniforms.find(base + VADDRESS_MODE_SUFFIX)) {
|
|
287
|
-
const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData();
|
|
288
|
-
texture.wrapT = getWrapping(vaddressmode);
|
|
289
|
-
}
|
|
337
|
+
texture.wrapS = getWrapping(getUniformData(uniforms, base + UADDRESS_MODE_SUFFIX, 2));
|
|
338
|
+
texture.wrapT = getWrapping(getUniformData(uniforms, base + VADDRESS_MODE_SUFFIX, 2));
|
|
290
339
|
|
|
291
|
-
const mxFilterType = uniforms
|
|
340
|
+
const mxFilterType = getFilterType(getUniformData(uniforms, base + FILTER_TYPE_SUFFIX, -1));
|
|
292
341
|
let minFilter = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter;
|
|
342
|
+
let magFilter = THREE.LinearFilter;
|
|
293
343
|
if (mxFilterType === 0) {
|
|
294
344
|
minFilter = /** @type {any} */ (generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter);
|
|
345
|
+
magFilter = THREE.NearestFilter;
|
|
295
346
|
}
|
|
296
347
|
texture.minFilter = minFilter;
|
|
348
|
+
texture.magFilter = magFilter;
|
|
297
349
|
}
|
|
298
350
|
|
|
299
351
|
/**
|
|
@@ -528,9 +580,12 @@ export function getLightData(lights, genContext) {
|
|
|
528
580
|
* @param {any} shaderStage
|
|
529
581
|
* @param {Callbacks} loaders
|
|
530
582
|
* @param {string} searchPath
|
|
583
|
+
* @param {Array<Promise<unknown>>} [pendingTextureLoads]
|
|
531
584
|
* @returns {Object<string, THREE.Uniform>}
|
|
532
585
|
*/
|
|
533
|
-
export function getUniformValues(shaderStage, loaders, searchPath) {
|
|
586
|
+
export function getUniformValues(shaderStage, loaders, searchPath, pendingTextureLoads) {
|
|
587
|
+
loaders ??= { getTexture: async () => null };
|
|
588
|
+
searchPath ??= "";
|
|
534
589
|
/** @type {Object<string, THREE.Uniform>} */
|
|
535
590
|
const threeUniforms = {};
|
|
536
591
|
|
|
@@ -545,7 +600,7 @@ export function getUniformValues(shaderStage, loaders, searchPath) {
|
|
|
545
600
|
const value = variable.getValue()?.getData();
|
|
546
601
|
const uniformName = variable.getVariable();
|
|
547
602
|
const type = variable.getType().getName();
|
|
548
|
-
threeUniforms[uniformName] = toThreeUniform(uniforms, type, value, uniformName, loaders, searchPath);
|
|
603
|
+
threeUniforms[uniformName] = toThreeUniform(threeUniforms, uniforms, type, value, uniformName, loaders, searchPath, pendingTextureLoads);
|
|
549
604
|
if (debug) console.log("Adding uniform", { path: variable.getPath(), type: type, name: uniformName, value: threeUniforms[uniformName], },);
|
|
550
605
|
}
|
|
551
606
|
}
|