@needle-tools/materialx 1.0.0 → 1.0.1-next.2ca9014
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 +8 -0
- package/README.md +22 -0
- package/package.json +22 -4
- package/src/helper.js +39 -6
- package/src/loader/loader.three.ts +35 -22
- package/src/materialx.ts +59 -47
- package/bin/README.md +0 -5
- /package/bin/{JsMaterialXGenShader.data → JsMaterialXGenShader.data.txt} +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this package will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
|
+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [1.0.1] - 2025-07-08
|
|
8
|
+
- Initial release
|
package/README.md
CHANGED
|
@@ -1 +1,23 @@
|
|
|
1
|
+
# Needle MaterialX
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
`npm i @needle-tools/materialx@stable`
|
|
5
|
+
|
|
6
|
+
## How to use
|
|
7
|
+
|
|
8
|
+
To use with Needle Engine simply import the module
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import "@needle-tools/materialx"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
<br />
|
|
15
|
+
|
|
16
|
+
# Contact ✒️
|
|
17
|
+
<b>[🌵 Needle](https://needle.tools)</b> •
|
|
18
|
+
[Github](https://github.com/needle-tools) •
|
|
19
|
+
[Twitter](https://twitter.com/NeedleTools) •
|
|
20
|
+
[Discord](https://discord.needle.tools) •
|
|
21
|
+
[Forum](https://forum.needle.tools) •
|
|
22
|
+
[Youtube](https://www.youtube.com/@needle-tools)
|
|
1
23
|
|
package/package.json
CHANGED
|
@@ -1,20 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/materialx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-next.2ca9014",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.ts",
|
|
6
|
-
"
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./index.ts",
|
|
9
|
+
"require": "./index.js"
|
|
10
|
+
},
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
7
13
|
"peerDependencies": {
|
|
8
14
|
"@needle-tools/engine": "4.x",
|
|
9
15
|
"three": "npm:@needle-tools/three@^0.169.5"
|
|
10
16
|
},
|
|
11
17
|
"devDependencies": {
|
|
12
18
|
"@needle-tools/engine": "4.x",
|
|
19
|
+
"@types/three": "0.169.0",
|
|
13
20
|
"three": "npm:@needle-tools/three@^0.169.5",
|
|
14
|
-
"
|
|
21
|
+
"vite": "^7.0.3"
|
|
15
22
|
},
|
|
16
23
|
"publishConfig": {
|
|
17
24
|
"access": "public",
|
|
18
25
|
"registry": "https://registry.npmjs.org/"
|
|
19
|
-
}
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"needle",
|
|
29
|
+
"materialx",
|
|
30
|
+
"material",
|
|
31
|
+
"shader",
|
|
32
|
+
"threejs",
|
|
33
|
+
"three.js",
|
|
34
|
+
"webgl",
|
|
35
|
+
"mtlx",
|
|
36
|
+
"rendering"
|
|
37
|
+
]
|
|
20
38
|
}
|
package/src/helper.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
//
|
|
5
5
|
|
|
6
|
-
import { getParam } from '@needle-tools/engine';
|
|
6
|
+
import { getParam, getWorldDirection } from '@needle-tools/engine';
|
|
7
7
|
import * as THREE from 'three';
|
|
8
8
|
|
|
9
9
|
const debug = getParam("debugmaterialx");
|
|
@@ -301,10 +301,14 @@ export function findLights(doc)
|
|
|
301
301
|
export async function registerLights(mx, lights, genContext)
|
|
302
302
|
{
|
|
303
303
|
mx.HwShaderGenerator.unbindLightShaders(genContext);
|
|
304
|
+
// TODO Remove, not sure why we need that – something resets the value inbetween calls to registerLights
|
|
305
|
+
genContext.getOptions().hwMaxActiveLightSources = 4;
|
|
304
306
|
|
|
305
307
|
const lightTypesBound = {};
|
|
306
308
|
const lightData = [];
|
|
307
309
|
let lightId = 1;
|
|
310
|
+
let lightCount = 0;
|
|
311
|
+
const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
|
|
308
312
|
|
|
309
313
|
// All light types so that we have NodeDefs for them
|
|
310
314
|
const defaultLightRigXml = `<?xml version="1.0"?>
|
|
@@ -331,6 +335,9 @@ export async function registerLights(mx, lights, genContext)
|
|
|
331
335
|
const defaultLights = findLights(document);
|
|
332
336
|
if (debug) console.log("Default lights in MaterialX document", defaultLights);
|
|
333
337
|
|
|
338
|
+
// Loading a document seems to reset this option for some reason, so we set it again
|
|
339
|
+
genContext.getOptions().hwMaxActiveLightSources = maxLightCount;
|
|
340
|
+
|
|
334
341
|
// Register types only – we get these from the default light rig XML above
|
|
335
342
|
// This is needed to ensure that the light shaders are bound for each light type
|
|
336
343
|
for (let light of defaultLights)
|
|
@@ -414,18 +421,44 @@ export async function registerLights(mx, lights, genContext)
|
|
|
414
421
|
mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);
|
|
415
422
|
}
|
|
416
423
|
|
|
424
|
+
const wp = light.getWorldPosition(new THREE.Vector3());
|
|
425
|
+
const wd = getWorldDirection(light, new THREE.Vector3(0,0,-1));
|
|
417
426
|
lightData.push({
|
|
418
427
|
type: lightTypesBound[lightDefinitionName],
|
|
419
|
-
|
|
428
|
+
position: wp.clone(),
|
|
429
|
+
direction: wd.clone(),
|
|
420
430
|
color: new THREE.Vector3().fromArray(light.color.toArray()),
|
|
421
|
-
intensity: light.intensity,
|
|
431
|
+
intensity: light.intensity, // Scale intensity for spot lights
|
|
432
|
+
decay_rate: 2.0, // physically-based default decay rate
|
|
433
|
+
inner_angle: 1.0,
|
|
434
|
+
outer_angle: 2.0,
|
|
422
435
|
});
|
|
423
436
|
}
|
|
424
437
|
|
|
425
|
-
//
|
|
426
|
-
|
|
438
|
+
// Count the number of lights that are not empty
|
|
439
|
+
lightCount = lightData.length;
|
|
440
|
+
|
|
441
|
+
// If we don't have enough entries in lightData, fill with empty lights
|
|
442
|
+
if (lightData.length < maxLightCount)
|
|
443
|
+
{
|
|
444
|
+
const emptyLight = {
|
|
445
|
+
type: 0, // Default light type
|
|
446
|
+
position: new THREE.Vector3(0, 0, 0),
|
|
447
|
+
direction: new THREE.Vector3(0, 0, -1),
|
|
448
|
+
color: new THREE.Vector3(0, 0, 0),
|
|
449
|
+
intensity: 0,
|
|
450
|
+
decay_rate: 2,
|
|
451
|
+
inner_angle: 0,
|
|
452
|
+
outer_angle: 0,
|
|
453
|
+
};
|
|
454
|
+
while (lightData.length < maxLightCount) {
|
|
455
|
+
lightData.push(emptyLight);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (debug) console.log("Registered lights in MaterialX context", lightTypesBound, lightData);
|
|
427
460
|
|
|
428
|
-
return lightData;
|
|
461
|
+
return { lightData, lightCount };
|
|
429
462
|
}
|
|
430
463
|
|
|
431
464
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context } from "@needle-tools/engine";
|
|
2
|
-
import {
|
|
2
|
+
import { ShaderMaterial, Material, MeshStandardMaterial, LoadingManager, TextureLoader, Texture, NearestFilter, Matrix4, GLSL3, AddEquation, OneMinusSrcAlphaFactor, SrcAlphaFactor, DoubleSide, Matrix3, Vector3, Object3D, Camera } from "three";
|
|
3
3
|
import { GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
4
4
|
import { getUniformValues } from "../helper.js";
|
|
5
5
|
import { initializeMaterialX, MaterialXEnvironment, state } from "../materialx.js";
|
|
@@ -25,7 +25,7 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
25
25
|
private documentParsePromise: Promise<any> | null = null;
|
|
26
26
|
private rootDataInitialized = false;
|
|
27
27
|
private environmentInitialized = false;
|
|
28
|
-
private generatedMaterials:
|
|
28
|
+
private generatedMaterials: ShaderMaterial[] = [];
|
|
29
29
|
|
|
30
30
|
constructor(private parser: GLTFParser, private context: Context) {
|
|
31
31
|
if (debug) console.log("MaterialXLoader created for parser");
|
|
@@ -247,23 +247,23 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
247
247
|
// Check transparency and set context options like the reference
|
|
248
248
|
let isTransparent = state.materialXModule.isTransparentSurface(renderableElement, state.materialXGenerator.getTarget());
|
|
249
249
|
state.materialXGenContext.getOptions().hwTransparency = isTransparent;
|
|
250
|
-
|
|
251
|
-
state.materialXGenContext.getOptions().hwSrgbEncodeOutput = true; // Like the reference
|
|
252
|
-
|
|
250
|
+
|
|
253
251
|
// Generate shaders using the element's name path
|
|
254
252
|
if (debug) console.log("Generating MaterialX shaders...");
|
|
255
253
|
const elementName = (renderableElement as any).getNamePath ? (renderableElement as any).getNamePath() : (renderableElement as any).getName();
|
|
256
254
|
|
|
257
255
|
const shader = state.materialXGenerator.generate(elementName, renderableElement, state.materialXGenContext);
|
|
258
256
|
|
|
259
|
-
// Get vertex and fragment shader source
|
|
260
|
-
//
|
|
257
|
+
// Get vertex and fragment shader source, and remove #version directive for newer js.
|
|
258
|
+
// It's added by three.js glslVersion.
|
|
261
259
|
let vertexShader = shader.getSourceCode("vertex").replace(/^#version.*$/gm, '').trim();
|
|
262
260
|
let fragmentShader = shader.getSourceCode("pixel").replace(/^#version.*$/gm, '').trim();
|
|
263
261
|
|
|
264
262
|
// MaterialX uses different attribute names than js defaults,
|
|
265
263
|
// so we patch the MaterialX shaders to match the js standard names.
|
|
266
|
-
// Otherwise, we'd have to modify the mesh attributes (see
|
|
264
|
+
// Otherwise, we'd have to modify the mesh attributes (see original MaterialX for reference).
|
|
265
|
+
|
|
266
|
+
// Patch vertexShader
|
|
267
267
|
vertexShader = vertexShader.replace(/\bi_position\b/g, 'position');
|
|
268
268
|
vertexShader = vertexShader.replace(/\bi_normal\b/g, 'normal');
|
|
269
269
|
vertexShader = vertexShader.replace(/\bi_texcoord_0\b/g, 'uv');
|
|
@@ -271,6 +271,7 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
271
271
|
vertexShader = vertexShader.replace(/\bi_tangent\b/g, 'tangent');
|
|
272
272
|
vertexShader = vertexShader.replace(/\bi_color_0\b/g, 'color');
|
|
273
273
|
|
|
274
|
+
// Patch fragmentShader
|
|
274
275
|
fragmentShader = fragmentShader.replace(/\bi_position\b/g, 'position');
|
|
275
276
|
fragmentShader = fragmentShader.replace(/\bi_normal\b/g, 'normal');
|
|
276
277
|
fragmentShader = fragmentShader.replace(/\bi_texcoord_0\b/g, 'uv');
|
|
@@ -278,16 +279,27 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
278
279
|
fragmentShader = fragmentShader.replace(/\bi_tangent\b/g, 'tangent');
|
|
279
280
|
fragmentShader = fragmentShader.replace(/\bi_color_0\b/g, 'color');
|
|
280
281
|
|
|
281
|
-
//
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
282
|
+
// Remove `in vec3 position;` and so on since they're already declared by ShaderMaterial
|
|
283
|
+
vertexShader = vertexShader.replace(/in\s+vec3\s+position;/g, '');
|
|
284
|
+
vertexShader = vertexShader.replace(/in\s+vec3\s+normal;/g, '');
|
|
285
|
+
vertexShader = vertexShader.replace(/in\s+vec3\s+uv;/g, '');
|
|
286
|
+
vertexShader = vertexShader.replace(/in\s+vec3\s+uv1;/g, '');
|
|
287
|
+
vertexShader = vertexShader.replace(/in\s+vec4\s+tangent;/g, '');
|
|
288
|
+
vertexShader = vertexShader.replace(/in\s+vec4\s+color;/g, '');
|
|
289
|
+
|
|
290
|
+
// Patch uv 2-component to 3-component (`texcoord_0 = uv;` needs to be replaced with `texcoord_0 = vec3(uv, 0.0);`)
|
|
291
|
+
// TODO what if we actually have a 3-component UV? Not sure what three.js does then
|
|
292
|
+
vertexShader = vertexShader.replace(/texcoord_0 = uv;/g, 'texcoord_0 = vec3(uv, 0.0);');
|
|
293
|
+
|
|
294
|
+
// Add tonemapping and colorspace handling
|
|
295
|
+
// Replace `out vec4 out1;` with `out vec4 gl_FragColor;`
|
|
296
|
+
fragmentShader = fragmentShader.replace(/out\s+vec4\s+out1;/, 'layout(location = 0) out vec4 pc_fragColor;\n#define gl_FragColor pc_fragColor');
|
|
297
|
+
// Replace `out1 = vec4(<CAPTURE>)` with `gl_FragColor = vec4(<CAPTURE>)` and tonemapping/colorspace handling
|
|
298
|
+
fragmentShader = fragmentShader.replace(/^\s*out1\s*=\s*vec4\((.*)\);/gm,
|
|
299
|
+
`
|
|
300
|
+
gl_FragColor = vec4($1);
|
|
301
|
+
#include <tonemapping_fragment>
|
|
302
|
+
#include <colorspace_fragment>`);
|
|
291
303
|
|
|
292
304
|
if (debug) {
|
|
293
305
|
console.group("Material: ", materialXData.name);
|
|
@@ -402,7 +414,7 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
402
414
|
// console.log("Generated fragment shader:", fragmentShader.substring(0, 500) + "...");
|
|
403
415
|
|
|
404
416
|
// Create js RawShaderMaterial (with GLSL3 for MaterialX compatibility)
|
|
405
|
-
const shaderMaterial = new
|
|
417
|
+
const shaderMaterial = new ShaderMaterial({
|
|
406
418
|
uniforms: uniforms,
|
|
407
419
|
vertexShader: vertexShader,
|
|
408
420
|
fragmentShader: fragmentShader,
|
|
@@ -499,8 +511,8 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
499
511
|
updateLightingFromEnvironment(environment: MaterialXEnvironment): void {
|
|
500
512
|
|
|
501
513
|
// Get lighting data from environment
|
|
502
|
-
// const lights = environment.getLights() || [];
|
|
503
514
|
const lightData = environment.getLightData() || null;
|
|
515
|
+
const lightCount = environment.getLightCount() || 0;
|
|
504
516
|
const radianceTexture = environment.getRadianceTexture() || null;
|
|
505
517
|
const irradianceTexture = environment.getIrradianceTexture() || null;
|
|
506
518
|
|
|
@@ -513,8 +525,8 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
513
525
|
if (!material.uniforms) return;
|
|
514
526
|
|
|
515
527
|
// Update light count
|
|
516
|
-
if (material.uniforms.u_numActiveLightSources &&
|
|
517
|
-
material.uniforms.u_numActiveLightSources.value =
|
|
528
|
+
if (material.uniforms.u_numActiveLightSources && lightCount >= 0) {
|
|
529
|
+
material.uniforms.u_numActiveLightSources.value = lightCount;
|
|
518
530
|
}
|
|
519
531
|
|
|
520
532
|
// Update light data if we have lights
|
|
@@ -523,6 +535,7 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
|
|
|
523
535
|
material.uniforms.u_lightData = { value: null };
|
|
524
536
|
}
|
|
525
537
|
material.uniforms.u_lightData.value = lightData;
|
|
538
|
+
if (debug) console.log("Updated light data for material", material.name, lightData, material.uniforms, );
|
|
526
539
|
}
|
|
527
540
|
|
|
528
541
|
// Update environment uniforms
|
package/src/materialx.ts
CHANGED
|
@@ -1,28 +1,10 @@
|
|
|
1
|
-
import { Context, delay, isDevEnvironment, ObjectUtils } from "@needle-tools/engine";
|
|
1
|
+
import { Context, delay, isDevEnvironment, ObjectUtils, GameObject } from "@needle-tools/engine";
|
|
2
2
|
import MaterialX from "../bin/JsMaterialXGenShader.js";
|
|
3
3
|
import { debug } from "./utils.js";
|
|
4
4
|
import { renderPMREMToEquirect } from "./textureHelper.js";
|
|
5
5
|
import { Light, MeshBasicMaterial, Object3D, PMREMGenerator } from "three";
|
|
6
6
|
import { registerLights } from "./helper.js";
|
|
7
7
|
|
|
8
|
-
// Configure MaterialX with the correct path for its data files
|
|
9
|
-
const materialXConfig = {
|
|
10
|
-
locateFile: (path: string, scriptDirectory: string) => {
|
|
11
|
-
if (debug) console.debug("MaterialX locateFile called:", { path, scriptDirectory });
|
|
12
|
-
|
|
13
|
-
// Return the correct path for MaterialX data files
|
|
14
|
-
if (path.endsWith('.data') || path.endsWith('.wasm')) {
|
|
15
|
-
// For Vite dev server, we need to use the correct module path
|
|
16
|
-
const correctPath = new URL(`../bin/${path}`, import.meta.url).href;
|
|
17
|
-
if (debug) console.log("Resolved path:", correctPath);
|
|
18
|
-
return correctPath;
|
|
19
|
-
}
|
|
20
|
-
return scriptDirectory + path;
|
|
21
|
-
},
|
|
22
|
-
// Add buffer allocation to handle the data file properly
|
|
23
|
-
wasmBinary: null,
|
|
24
|
-
wasmMemory: null
|
|
25
|
-
};
|
|
26
8
|
|
|
27
9
|
// Global MaterialX module instance - initialized lazily
|
|
28
10
|
export const state = new class {
|
|
@@ -40,7 +22,6 @@ export const state = new class {
|
|
|
40
22
|
}
|
|
41
23
|
}
|
|
42
24
|
|
|
43
|
-
|
|
44
25
|
// Initialize MaterialX WASM module lazily
|
|
45
26
|
export async function initializeMaterialX(): Promise<void> {
|
|
46
27
|
if (state.materialXInitPromise) {
|
|
@@ -50,7 +31,34 @@ export async function initializeMaterialX(): Promise<void> {
|
|
|
50
31
|
if (state.materialXModule) return; // Already initialized
|
|
51
32
|
if (debug) console.log("Initializing MaterialX WASM module...");
|
|
52
33
|
try {
|
|
53
|
-
|
|
34
|
+
|
|
35
|
+
const urls: Array<string> = await Promise.all([
|
|
36
|
+
/** @ts-ignore */
|
|
37
|
+
import(`../bin/JsMaterialXCore.wasm?url`).then(m => m.default || m),
|
|
38
|
+
/** @ts-ignore */
|
|
39
|
+
import(`../bin/JsMaterialXGenShader.wasm?url`).then(m => m.default || m),
|
|
40
|
+
/** @ts-ignore */
|
|
41
|
+
import(`../bin/JsMaterialXGenShader.data.txt?url`).then(m => m.default || m),
|
|
42
|
+
]);
|
|
43
|
+
const [JsMaterialXCore, JsMaterialXGenShader, JsMaterialXGenShader_data] = urls;
|
|
44
|
+
|
|
45
|
+
const module = await MaterialX({
|
|
46
|
+
locateFile: (path: string, scriptDirectory: string) => {
|
|
47
|
+
if (debug) console.debug("MaterialX locateFile called:", { path, scriptDirectory });
|
|
48
|
+
|
|
49
|
+
if (path.includes("JsMaterialXCore.wasm")) {
|
|
50
|
+
return JsMaterialXCore; // Use the URL for the core WASM file
|
|
51
|
+
}
|
|
52
|
+
else if (path.includes("JsMaterialXGenShader.wasm")) {
|
|
53
|
+
return JsMaterialXGenShader; // Use the URL for the shader WASM file
|
|
54
|
+
}
|
|
55
|
+
else if (path.includes("JsMaterialXGenShader.data")) {
|
|
56
|
+
return JsMaterialXGenShader_data; // Use the URL for the shader data file
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return scriptDirectory + path;
|
|
60
|
+
},
|
|
61
|
+
});
|
|
54
62
|
if (debug) console.log("MaterialXLoader module loaded", module);
|
|
55
63
|
state.materialXModule = module;
|
|
56
64
|
|
|
@@ -63,16 +71,29 @@ export async function initializeMaterialX(): Promise<void> {
|
|
|
63
71
|
state.materialXStdLib = module.loadStandardLibraries(state.materialXGenContext);
|
|
64
72
|
tempDoc.setDataLibrary(state.materialXStdLib);
|
|
65
73
|
|
|
66
|
-
//
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
// TODO ShaderInterfaceType.SHADER_INTERFACE_REDUCED would be better, but doesn't actually seem to be supported in the MaterialX javascript bindings
|
|
75
|
+
const options = state.materialXGenContext.getOptions();
|
|
76
|
+
state.materialXGenContext.getOptions().shaderInterfaceType = state.materialXModule.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE;
|
|
77
|
+
|
|
78
|
+
// SPECULAR_ENVIRONMENT_NONE: Do not use specular environment maps.
|
|
79
|
+
// SPECULAR_ENVIRONMENT_FIS: Use Filtered Importance Sampling for specular environment/indirect lighting.
|
|
80
|
+
// SPECULAR_ENVIRONMENT_PREFILTER: Use pre-filtered environment maps for specular environment/indirect lighting.
|
|
81
|
+
state.materialXGenContext.getOptions().hwSpecularEnvironmentMethod = state.materialXModule.HwSpecularEnvironmentMethod.SPECULAR_ENVIRONMENT_FIS;
|
|
82
|
+
|
|
83
|
+
// TRANSMISSION_REFRACTION: Use a refraction approximation for transmission rendering.
|
|
84
|
+
// TRANSMISSION_OPACITY: Use opacity for transmission rendering.
|
|
85
|
+
// state.materialXGenContext.getOptions().hwTransmissionRenderMethod = state.materialXModule.HwTransmissionRenderMethod.TRANSMISSION_REFRACTION;
|
|
86
|
+
|
|
87
|
+
// Turned off because we're doing color space conversion the three.js way
|
|
88
|
+
state.materialXGenContext.getOptions().hwSrgbEncodeOutput = false;
|
|
89
|
+
|
|
90
|
+
// Enables the generation of a prefiltered environment map.
|
|
91
|
+
// TODO Would be great to use but requires setting more uniforms (like u_envPrefilterMip).
|
|
92
|
+
// When set to true, the u_envRadiance map is expected to be a prefiltered environment map.
|
|
93
|
+
// state.materialXGenContext.getOptions().hwWriteEnvPrefilter = true;
|
|
94
|
+
|
|
95
|
+
// Set a reasonable default for max active lights
|
|
96
|
+
state.materialXGenContext.getOptions().hwMaxActiveLightSources = 4;
|
|
76
97
|
|
|
77
98
|
// This prewarms the shader generation context to have all light types
|
|
78
99
|
await registerLights(state.materialXModule, [], state.materialXGenContext);
|
|
@@ -87,8 +108,8 @@ export async function initializeMaterialX(): Promise<void> {
|
|
|
87
108
|
|
|
88
109
|
// MaterialX Environment Manager - handles lighting and environment setup
|
|
89
110
|
export class MaterialXEnvironment {
|
|
90
|
-
private lights: any[] = [];
|
|
91
111
|
private lightData: any = null;
|
|
112
|
+
private lightCount: number = 0;
|
|
92
113
|
private radianceTexture: any = null;
|
|
93
114
|
private irradianceTexture: any = null;
|
|
94
115
|
private context: Context | null = null;
|
|
@@ -102,18 +123,6 @@ export class MaterialXEnvironment {
|
|
|
102
123
|
this.context = context;
|
|
103
124
|
}
|
|
104
125
|
|
|
105
|
-
/*
|
|
106
|
-
// Initialize MaterialX lighting system based on the reference implementation
|
|
107
|
-
async initializeLighting(lightRigXml: string, renderer?: any, radianceTexture?: any, irradianceTexture?: any): Promise<void> {
|
|
108
|
-
if (!materialXModule || !materialXGenContext) {
|
|
109
|
-
console.warn("MaterialX module not initialized, skipping lighting setup");
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
registerLights(materialXModule, this.lights, materialXGenContext);
|
|
114
|
-
}
|
|
115
|
-
*/
|
|
116
|
-
|
|
117
126
|
// Initialize with Needle Engine context
|
|
118
127
|
async initializeFromContext(): Promise<void> {
|
|
119
128
|
if (!this.context) {
|
|
@@ -185,17 +194,20 @@ export class MaterialXEnvironment {
|
|
|
185
194
|
// Find lights in scene
|
|
186
195
|
let lights = new Array<Light>();
|
|
187
196
|
this.context.scene.traverse((object: Object3D) => {
|
|
188
|
-
if ((object as Light).isLight
|
|
197
|
+
if ((object as Light).isLight && GameObject.isActiveInHierarchy(object))
|
|
198
|
+
lights.push(object as Light);
|
|
189
199
|
});
|
|
190
200
|
|
|
191
|
-
|
|
201
|
+
const { lightData, lightCount } = await registerLights(state.materialXModule, lights, state.materialXGenContext);
|
|
202
|
+
this.lightData = lightData;
|
|
203
|
+
this.lightCount = lightCount;
|
|
192
204
|
|
|
193
205
|
// Mark as initialized
|
|
194
206
|
this.initialized = true;
|
|
195
207
|
}
|
|
196
208
|
|
|
197
|
-
// getLights() { return this.lights; }
|
|
198
209
|
getLightData() { return this.lightData; }
|
|
210
|
+
getLightCount() { return this.lightCount; }
|
|
199
211
|
getRadianceTexture() { return this.radianceTexture; }
|
|
200
212
|
getIrradianceTexture() { return this.irradianceTexture; }
|
|
201
213
|
|
package/bin/README.md
DELETED
|
File without changes
|