@needle-tools/materialx 1.0.1 → 1.0.2-next.c468cd8

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 CHANGED
@@ -4,5 +4,10 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.0.2] - 2025-07-10
8
+ - Add: Material extension `doubleSided` support
9
+ - Improved lighting support
10
+ - Improved texture loading and fix bug where glTF texture index was not resolved properly
11
+
7
12
  ## [1.0.1] - 2025-07-08
8
13
  - Initial release
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Needle MaterialX
2
2
 
3
+ Web runtime support to load and display MaterialX materials in Needle Engine
4
+
5
+ ## Installation
6
+ `npm i @needle-tools/materialx`
7
+
3
8
  ## How to use
4
9
 
5
10
  To use with Needle Engine simply import the module
@@ -2,5 +2,9 @@
2
2
  import { TypeStore } from "@needle-tools/engine"
3
3
 
4
4
  // Import types
5
+ import { MaterialXMaterial } from "../src/materialx.material.js";
6
+ import { MaterialXUniformUpdate } from "../src/loader/loader.needle.js";
5
7
 
6
8
  // Register types
9
+ TypeStore.add("MaterialXMaterial", MaterialXMaterial);
10
+ TypeStore.add("MaterialXUniformUpdate", MaterialXUniformUpdate);
package/index.ts CHANGED
@@ -2,4 +2,4 @@ import { registerNeedleLoader } from "./src/loader/loader.needle.js";
2
2
 
3
3
  registerNeedleLoader();
4
4
 
5
- export { initializeMaterialX, getMaterialXEnvironment } from "./src/index.js";
5
+ export { ready, getMaterialXEnvironment } from "./src/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/materialx",
3
- "version": "1.0.1",
3
+ "version": "1.0.2-next.c468cd8",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "exports": {
@@ -8,7 +8,11 @@
8
8
  "import": "./index.ts",
9
9
  "require": "./index.js"
10
10
  },
11
- "./package.json": "./package.json"
11
+ "./package.json": "./package.json",
12
+ "./codegen/register_types.ts": {
13
+ "import": "./codegen/register_types.ts",
14
+ "require": "./codegen/register_types.js"
15
+ }
12
16
  },
13
17
  "peerDependencies": {
14
18
  "@needle-tools/engine": "4.x",
@@ -23,5 +27,16 @@
23
27
  "publishConfig": {
24
28
  "access": "public",
25
29
  "registry": "https://registry.npmjs.org/"
26
- }
27
- }
30
+ },
31
+ "keywords": [
32
+ "needle",
33
+ "materialx",
34
+ "material",
35
+ "shader",
36
+ "threejs",
37
+ "three.js",
38
+ "webgl",
39
+ "mtlx",
40
+ "rendering"
41
+ ]
42
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { initializeMaterialX, state } from "./materialx.js";
1
+ import { ready, state } from "./materialx.js";
2
2
 
3
3
  const getMaterialXEnvironment = () => state.materialXEnvironment;
4
4
 
5
- export { initializeMaterialX, getMaterialXEnvironment };
5
+ export { ready, getMaterialXEnvironment };
@@ -6,32 +6,21 @@ import type { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
6
6
  import type { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter.js";
7
7
  import { MaterialXLoader } from "./loader.three.js";
8
8
  import { debug } from "../utils.js";
9
- import { state } from "../materialx.js";
9
+ import { MaterialXEnvironment, state } from "../materialx.js";
10
+ import { MaterialXMaterial } from "../materialx.material.js";
10
11
 
11
12
  //@dont-generate-component
12
13
  export class MaterialXUniformUpdate extends Component {
13
14
 
14
- static updateMaterial(mat: Material | Material[], object: Object3D, camera: Camera) {
15
- if (Array.isArray(mat)) {
16
- mat.forEach(m => {
17
- if (m.userData?.updateUniforms) {
18
- m.userData.updateUniforms(object, camera);
19
- }
20
- });
21
- } else if (mat.userData?.updateUniforms) {
22
- mat.userData.updateUniforms(object, camera);
23
- }
24
- }
25
-
26
15
  onEnable(): void {
27
- this.context.addBeforeRenderListener(this.gameObject, this._onBeforeRender);
16
+ this.context.addBeforeRenderListener(this.gameObject, this.onBeforeRenderThree);
28
17
  }
29
18
 
30
19
  onDisable(): void {
31
- this.context.removeBeforeRenderListener(this.gameObject, this._onBeforeRender);
20
+ this.context.removeBeforeRenderListener(this.gameObject, this.onBeforeRenderThree);
32
21
  }
33
22
 
34
- _onBeforeRender = () => {
23
+ onBeforeRenderThree = () => {
35
24
  // Update uniforms or perform any pre-render logic here
36
25
  const gameObject = this.gameObject as any as Mesh;
37
26
  const material = gameObject?.material;
@@ -39,22 +28,24 @@ export class MaterialXUniformUpdate extends Component {
39
28
  const camera = this.context.mainCamera;
40
29
  if (!camera) return;
41
30
 
42
- MaterialXUniformUpdate.updateMaterial(material, gameObject, camera);
31
+ const env = state.materialXEnvironment;
43
32
 
44
- // If this is a Group, we need to update all direct children
45
- if ((gameObject as any as Group).isGroup) {
46
- gameObject.children.forEach((child: Object3D) => {
47
- if (child instanceof Mesh && child.material)
48
- MaterialXUniformUpdate.updateMaterial(child.material, child, camera);
49
- });
33
+ if (Array.isArray(material)) {
34
+ for (const entry of material) {
35
+ if (entry && entry instanceof MaterialXMaterial) {
36
+ entry.updateUniforms(this.context, env, this.gameObject, camera);
37
+ }
38
+ }
39
+ } else if (material instanceof MaterialXMaterial) {
40
+ material.updateUniforms(this.context, env, this.gameObject, camera);
50
41
  }
51
42
  }
52
43
  }
53
44
 
54
45
  export class MaterialXLoaderPlugin implements INeedleGLTFExtensionPlugin {
55
- name = "MaterialXLoaderPlugin";
46
+ readonly name = "MaterialXLoaderPlugin";
56
47
 
57
- mtlxLoader: MaterialXLoader | null = null;
48
+ private loader: MaterialXLoader | null = null;
58
49
 
59
50
  onImport = (loader: GLTFLoader, url: string, context: Context) => {
60
51
  if (debug) console.log("MaterialXLoaderPlugin: Registering MaterialX extension for", url);
@@ -62,14 +53,18 @@ export class MaterialXLoaderPlugin implements INeedleGLTFExtensionPlugin {
62
53
  // Register the MaterialX loader extension
63
54
  // Environment initialization is now handled in the MaterialXLoader constructor
64
55
  loader.register(p => {
65
- this.mtlxLoader = new MaterialXLoader(p, context);
66
- return this.mtlxLoader;
56
+ this.loader = new MaterialXLoader(p, url, context);
57
+ return this.loader;
67
58
  });
68
59
  };
69
60
 
70
61
  onLoaded = (url: string, gltf: GLTF, _context: Context) => {
71
- if (debug) console.log("MaterialXLoaderPlugin: glTF loaded", url, gltf.scene);
62
+ if (debug) console.log("[MaterialX] MaterialXLoaderPlugin: glTF loaded", { url, scene: gltf.scene, materialX_root_data: this.loader?.materialX_root_data });
72
63
 
64
+ // If we don't have MaterialX data in the loaded glTF we don't need to do anything else here
65
+ if (!this.loader?.materialX_root_data) {
66
+ return;
67
+ }
73
68
  // Set up onBeforeRender callbacks for objects with MaterialX materials
74
69
  // This ensures uniforms are updated properly during rendering
75
70
  gltf.scene.traverse((child) => {
@@ -77,26 +72,18 @@ export class MaterialXLoaderPlugin implements INeedleGLTFExtensionPlugin {
77
72
  const mesh = child as Mesh;
78
73
  const material = mesh.material as Material;
79
74
 
80
- if (material?.userData?.updateUniforms) {
81
- if (debug) console.log("Adding MaterialX uniform update component to:", child.name);
75
+ if (material instanceof MaterialXMaterial) {
76
+ if (debug) console.log("[MaterialX] Adding MaterialX uniform update component to:", child.name);
82
77
  child.addComponent(MaterialXUniformUpdate);
83
78
  }
84
79
  }
85
80
  });
86
81
 
87
- if (debug) console.log("Loaded: ", this.mtlxLoader);
88
-
89
- // Initialize MaterialX lighting system with scene data
90
- const environment = state.materialXEnvironment;
91
- environment.initializeFromContext().then(() => {
92
- if (this.mtlxLoader) {
93
- this.mtlxLoader.updateLightingFromEnvironment(environment);
94
- }
95
- });
82
+ if (debug) console.log("[MaterialX] Loaded: ", this.loader);
96
83
  };
97
84
 
98
85
  onExport = (_exporter: GLTFExporter, _context: Context) => {
99
- console.log("TODO: MaterialXLoaderPlugin: Setting up export extensions");
86
+ console.log("[MaterialX] TODO: MaterialXLoaderPlugin: Setting up export extensions");
100
87
  // TODO: Add MaterialX export functionality if needed
101
88
  };
102
89
  }