@needle-tools/materialx 1.0.7 → 1.1.0-next.bc1b608

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/index.ts CHANGED
@@ -1,5 +1,2 @@
1
- import { registerNeedleLoader } from "./src/loader/loader.needle.js";
2
-
3
- registerNeedleLoader();
4
-
5
- export * from "./src/index.js";
1
+ export * from "./src/index.js";
2
+ export { addPluginForThree } from "./src/loader/loader.three.js";
package/needle.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./src/index.js";
2
+ export { addPluginForNeedleEngine } from "./src/loader/loader.needle.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/materialx",
3
- "version": "1.0.7",
3
+ "version": "1.1.0-next.bc1b608",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "exports": {
@@ -12,6 +12,10 @@
12
12
  "./codegen/register_types.ts": {
13
13
  "import": "./codegen/register_types.ts",
14
14
  "require": "./codegen/register_types.js"
15
+ },
16
+ "./needle": {
17
+ "import": "./needle.ts",
18
+ "require": "./needle.js"
15
19
  }
16
20
  },
17
21
  "peerDependencies": {
@@ -38,4 +42,4 @@
38
42
  "mtlx",
39
43
  "rendering"
40
44
  ]
41
- }
45
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export { ready, type MaterialXContext } from "./materialx.js";
2
2
  export { MaterialXMaterial } from "./materialx.material.js";
3
3
  export { MaterialXLoader } from "./loader/loader.three.js";
4
- export { registerNeedleLoader } from "./loader/loader.needle.js";
@@ -1,11 +1,11 @@
1
-
2
-
3
- import { Context, GLTF, addCustomExtensionPlugin, INeedleGLTFExtensionPlugin } from "@needle-tools/engine";
1
+ import { addCustomExtensionPlugin } from "@needle-tools/engine";
2
+ import { Context, GLTF, INeedleGLTFExtensionPlugin } from "@needle-tools/engine";
4
3
  import type { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
5
4
  import type { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter.js";
6
- import { MaterialXLoader } from "./loader.three.js";
5
+ import { addPluginForThree, MaterialXLoader } from "./loader.three.js";
7
6
  import { debug } from "../utils.js";
8
7
 
8
+
9
9
  export class MaterialXLoaderPlugin implements INeedleGLTFExtensionPlugin {
10
10
  readonly name = "MaterialXLoaderPlugin";
11
11
 
@@ -13,39 +13,29 @@ export class MaterialXLoaderPlugin implements INeedleGLTFExtensionPlugin {
13
13
 
14
14
  onImport = (loader: GLTFLoader, url: string, context: Context) => {
15
15
  if (debug) console.log("MaterialXLoaderPlugin: Registering MaterialX extension for", url);
16
-
17
- // Register the MaterialX loader extension
18
- // Environment initialization is now handled in the MaterialXLoader constructor
19
- loader.register(p => {
20
- this.loader = new MaterialXLoader(p, url, {
21
- getTime: () => context.time.time,
22
- getFrame: ()=> context.time.frame,
23
- getScene: () => context.scene,
24
- getRenderer: () => context.renderer,
25
- });
26
- return this.loader;
16
+ addPluginForThree(loader, {
17
+ getTime: () => context.time.time,
18
+ getFrame: () => context.time.frame,
19
+ getScene: () => context.scene,
20
+ getRenderer: () => context.renderer,
21
+ }, {
22
+ cacheKey: url
27
23
  });
28
24
  };
29
25
 
30
26
  onLoaded = (url: string, gltf: GLTF, _context: Context) => {
31
27
  if (debug) console.log("[MaterialX] MaterialXLoaderPlugin: glTF loaded", { url, scene: gltf.scene, materialX_root_data: this.loader?.materialX_root_data });
32
-
33
- // If we don't have MaterialX data in the loaded glTF we don't need to do anything else here
34
- if (!this.loader?.materialX_root_data) {
35
- return;
36
- }
37
-
38
- if (debug) console.log("[MaterialX] Loaded: ", this.loader);
39
-
40
-
41
28
  };
42
29
 
43
30
  onExport = (_exporter: GLTFExporter, _context: Context) => {
44
31
  console.warn("[MaterialX] Export is not supported");
45
- // TODO: Add MaterialX export functionality if needed
46
32
  };
47
33
  }
48
34
 
49
- export function registerNeedleLoader() {
35
+
36
+ /**
37
+ * Add the MaterialXLoaderPlugin to the Needle Engine.
38
+ */
39
+ export async function addPluginForNeedleEngine() {
50
40
  addCustomExtensionPlugin(new MaterialXLoaderPlugin());
51
- }
41
+ }
@@ -1,5 +1,5 @@
1
1
  import { Material, MeshStandardMaterial, DoubleSide, FrontSide } from "three";
2
- import { GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js";
2
+ import { GLTFLoader, GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js";
3
3
  import { ready, state, MaterialXContext } from "../materialx.js";
4
4
  import { debug } from "../utils.js";
5
5
  import { MaterialXMaterial } from "../materialx.material.js";
@@ -48,10 +48,10 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
48
48
  /**
49
49
  * MaterialXLoader constructor
50
50
  * @param parser The GLTFParser instance
51
- * @param url The URL of the GLTF file
51
+ * @param cacheKey The URL of the GLTF file
52
52
  * @param context The context for the GLTF loading process
53
53
  */
54
- constructor(private parser: GLTFParser, private url: string, private context: MaterialXContext) {
54
+ constructor(private parser: GLTFParser, private cacheKey: string, private context: MaterialXContext) {
55
55
  if (debug) console.log("MaterialXLoader created for parser");
56
56
  // Start loading of MaterialX environment if the root extension exists
57
57
  if (this.materialX_root_data) {
@@ -59,6 +59,7 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
59
59
  }
60
60
  }
61
61
 
62
+
62
63
  loadMaterial(materialIndex: number): Promise<Material> | null {
63
64
  const materialDef = this.parser.json.materials?.[materialIndex];
64
65
  if (!materialDef?.extensions?.[this.name]) {
@@ -233,7 +234,7 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
233
234
  side: material_def.doubleSided ? DoubleSide : FrontSide,
234
235
  context: this.context,
235
236
  loaders: {
236
- cacheKey: this.url,
237
+ cacheKey: this.cacheKey,
237
238
  getTexture: async url => {
238
239
  // Find the index of the texture in the parser
239
240
  const filenameWithoutExt = url.split('/').pop()?.split('.').shift() || '';
@@ -292,3 +293,14 @@ export class MaterialXLoader implements GLTFLoaderPlugin {
292
293
  }
293
294
  }
294
295
  }
296
+
297
+
298
+ /**
299
+ * Add the MaterialXLoaderPlugin to the Needle Engine.
300
+ */
301
+ export function addPluginForThree(loader: GLTFLoader, context: MaterialXContext, options: { cacheKey?: string } = {}) {
302
+ loader.register(p => {
303
+ const loader = new MaterialXLoader(p, options.cacheKey || "", context);
304
+ return loader;
305
+ });
306
+ }
@@ -2,11 +2,9 @@
2
2
  // Copyright Contributors to the MaterialX Project
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  //
5
-
6
- import { getWorldDirection } from '@needle-tools/engine';
7
5
  import * as THREE from 'three';
8
- import { debug, debugUpdate } from './utils';
9
- import { MaterialX } from './materialx.types';
6
+ import { debug, debugUpdate } from './utils.js';
7
+ import { MaterialX } from './materialx.types.js';
10
8
 
11
9
  const IMAGE_PROPERTY_SEPARATOR = "_";
12
10
  const UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "uaddressmode";
@@ -384,14 +382,14 @@ export type LightData = {
384
382
  /**
385
383
  * Update light data for shader uniforms
386
384
  */
387
- export function getLightData(lights: any, genContext: any): { lightData: LightData[], lightCount: number } {
385
+ export function getLightData(lights: Array<THREE.Light>, genContext: any): { lightData: LightData[], lightCount: number } {
388
386
  const lightData = new Array();
389
387
  const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
390
388
 
391
389
  // Three.js lights
392
390
  for (let light of lights) {
393
391
  // Skip if light is not a Three.js light
394
- if (!light.isLight) continue;
392
+ if (!light?.isLight) continue;
395
393
 
396
394
  // Types in MaterialX: point_light, directional_light, spot_light
397
395
 
@@ -401,7 +399,8 @@ export function getLightData(lights: any, genContext: any): { lightData: LightDa
401
399
  console.error("MaterialX: Light type not registered in context. Make sure to register light types before using them.", lightDefinitionName);
402
400
 
403
401
  const wp = light.getWorldPosition(new THREE.Vector3());
404
- const wd = getWorldDirection(light, new THREE.Vector3(0, 0, -1));
402
+ const wq = light.getWorldQuaternion(new THREE.Quaternion());
403
+ const wd = new THREE.Vector3(0, 0, -1).applyQuaternion(wq);
405
404
 
406
405
  // Shader math from the generated MaterialX shader:
407
406
  // float low = min(light.inner_angle, light.outer_angle);
@@ -409,8 +408,8 @@ export function getLightData(lights: any, genContext: any): { lightData: LightDa
409
408
  // float cosDir = dot(result.direction, -light.direction);
410
409
  // float spotAttenuation = smoothstep(low, high, cosDir);
411
410
 
412
- const outerAngleRad = light.angle;
413
- const innerAngleRad = outerAngleRad * (1 - light.penumbra);
411
+ const outerAngleRad = (light as THREE.SpotLight).angle;
412
+ const innerAngleRad = outerAngleRad * (1 - (light as THREE.SpotLight).penumbra);
414
413
  const inner_angle = Math.cos(innerAngleRad);
415
414
  const outer_angle = Math.cos(outerAngleRad);
416
415
 
@@ -421,7 +420,7 @@ export function getLightData(lights: any, genContext: any): { lightData: LightDa
421
420
  color: new THREE.Color().fromArray(light.color.toArray()),
422
421
  // Luminous efficacy for converting radiant power in watts (W) to luminous flux in lumens (lm) at a wavelength of 555 nm.
423
422
  // 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.
424
- intensity: light.intensity * (light.isPointLight ? 683.0 / 3.1415 : light.isSpotLight ? 683.0 / 3.1415 : 1.0),
423
+ intensity: light.intensity * ((light as THREE.PointLight).isPointLight ? 683.0 / 3.1415 : (light as THREE.SpotLight).isSpotLight ? 683.0 / 3.1415 : 1.0),
425
424
  decay_rate: 2.0,
426
425
  // Approximations for testing – the relevant light has 61.57986...129.4445 as inner/outer spot angle
427
426
  inner_angle: inner_angle,
@@ -1,5 +1,5 @@
1
1
  import { WebGLRenderer, Scene, WebGLRenderTarget, PlaneGeometry, OrthographicCamera, ShaderMaterial, RGBAFormat, FloatType, LinearFilter, Mesh, EquirectangularReflectionMapping, RepeatWrapping, LinearMipMapLinearFilter, Texture, WebGLUtils } from 'three';
2
- import { getParam } from '@needle-tools/engine';
2
+ import { getParam } from './utils.js';
3
3
 
4
4
  const debug = getParam("debugmaterialx");
5
5
 
package/src/utils.ts CHANGED
@@ -1,5 +1,10 @@
1
- import { Context, getParam } from "@needle-tools/engine";
2
- import { Mesh } from "three";
1
+ export function getParam(name: string) {
2
+ const urlParams = new URLSearchParams(window.location.search);
3
+ const param = urlParams.get(name);
4
+ if (param == null || param === "0" || param === "false") return false;
5
+ if (param === "") return true;
6
+ return param;
7
+ }
3
8
 
4
9
  export const debug = getParam("debugmaterialx");
5
10
  export const debugUpdate = debug === "update";
@@ -12,83 +17,63 @@ export const debugUpdate = debug === "update";
12
17
 
13
18
  // Patch WebGL2 methods for debugging purposes
14
19
 
15
- const patchWebGL2 = () => {
16
- const getUniformLocation = WebGL2RenderingContext.prototype.getUniformLocation;
17
- const programAndNameToUniformLocation = new WeakMap<WebGLUniformLocation, { program: WebGLProgram, name: string }>();
18
- WebGL2RenderingContext.prototype.getUniformLocation = function (program: WebGLProgram, name: string) {
19
- const location = getUniformLocation.call(this, program, name);
20
- if (location) {
21
- programAndNameToUniformLocation.set(location, { program, name });
22
- }
23
- return location;
24
- };
20
+ // const patchWebGL2 = () => {
21
+ // const getUniformLocation = WebGL2RenderingContext.prototype.getUniformLocation;
22
+ // const programAndNameToUniformLocation = new WeakMap<WebGLUniformLocation, { program: WebGLProgram, name: string }>();
23
+ // WebGL2RenderingContext.prototype.getUniformLocation = function (program: WebGLProgram, name: string) {
24
+ // const location = getUniformLocation.call(this, program, name);
25
+ // if (location) {
26
+ // programAndNameToUniformLocation.set(location, { program, name });
27
+ // }
28
+ // return location;
29
+ // };
25
30
 
26
- const uniform4fv = WebGL2RenderingContext.prototype.uniform4fv;
27
- WebGL2RenderingContext.prototype.uniform4fv = function (location: WebGLUniformLocation | null, v: Float32Array | number[]) {
28
- if (location) {
29
- const uniformName = programAndNameToUniformLocation.get(location);
30
- if (true) console.log("Calling uniform4fv", { location, v, name: uniformName?.name });
31
- }
32
- return uniform4fv.call(this, location, v);
33
- };
31
+ // const uniform4fv = WebGL2RenderingContext.prototype.uniform4fv;
32
+ // WebGL2RenderingContext.prototype.uniform4fv = function (location: WebGLUniformLocation | null, v: Float32Array | number[]) {
33
+ // if (location) {
34
+ // const uniformName = programAndNameToUniformLocation.get(location);
35
+ // if (true) console.log("Calling uniform4fv", { location, v, name: uniformName?.name });
36
+ // }
37
+ // return uniform4fv.call(this, location, v);
38
+ // };
34
39
 
35
- const uniform3fv = WebGL2RenderingContext.prototype.uniform3fv;
36
- WebGL2RenderingContext.prototype.uniform3fv = function (location: WebGLUniformLocation | null, v: Float32Array | number[]) {
37
- if (location) {
38
- const uniformName = programAndNameToUniformLocation.get(location);
39
- if (true) console.log("Calling uniform3fv", { location, v, name: uniformName?.name });
40
- }
41
- return uniform3fv.call(this, location, v);
42
- };
40
+ // const uniform3fv = WebGL2RenderingContext.prototype.uniform3fv;
41
+ // WebGL2RenderingContext.prototype.uniform3fv = function (location: WebGLUniformLocation | null, v: Float32Array | number[]) {
42
+ // if (location) {
43
+ // const uniformName = programAndNameToUniformLocation.get(location);
44
+ // if (true) console.log("Calling uniform3fv", { location, v, name: uniformName?.name });
45
+ // }
46
+ // return uniform3fv.call(this, location, v);
47
+ // };
43
48
 
44
- const uniform3iv = WebGL2RenderingContext.prototype.uniform3iv;
45
- WebGL2RenderingContext.prototype.uniform3iv = function (location: WebGLUniformLocation | null, v: Int32Array | number[]) {
46
- if (location) {
47
- const uniformName = programAndNameToUniformLocation.get(location);
48
- if (true) console.log("Calling uniform3iv", { location, v, name: uniformName?.name });
49
- }
50
- return uniform3iv.call(this, location, v);
51
- };
49
+ // const uniform3iv = WebGL2RenderingContext.prototype.uniform3iv;
50
+ // WebGL2RenderingContext.prototype.uniform3iv = function (location: WebGLUniformLocation | null, v: Int32Array | number[]) {
51
+ // if (location) {
52
+ // const uniformName = programAndNameToUniformLocation.get(location);
53
+ // if (true) console.log("Calling uniform3iv", { location, v, name: uniformName?.name });
54
+ // }
55
+ // return uniform3iv.call(this, location, v);
56
+ // };
52
57
 
53
- const uniform3uiv = WebGL2RenderingContext.prototype.uniform3uiv;
54
- WebGL2RenderingContext.prototype.uniform3uiv = function (location: WebGLUniformLocation | null, v: Uint32Array | number[]) {
55
- if (location) {
56
- const uniformName = programAndNameToUniformLocation.get(location);
57
- if (true) console.log("Calling uniform3uiv", { location, v, name: uniformName?.name });
58
- }
59
- return uniform3uiv.call(this, location, v);
60
- };
58
+ // const uniform3uiv = WebGL2RenderingContext.prototype.uniform3uiv;
59
+ // WebGL2RenderingContext.prototype.uniform3uiv = function (location: WebGLUniformLocation | null, v: Uint32Array | number[]) {
60
+ // if (location) {
61
+ // const uniformName = programAndNameToUniformLocation.get(location);
62
+ // if (true) console.log("Calling uniform3uiv", { location, v, name: uniformName?.name });
63
+ // }
64
+ // return uniform3uiv.call(this, location, v);
65
+ // };
61
66
 
62
- const uniform3f = WebGL2RenderingContext.prototype.uniform3f;
63
- WebGL2RenderingContext.prototype.uniform3f = function (location: WebGLUniformLocation
64
- | null, x: number, y: number, z: number) {
65
- if (location) {
66
- const uniformName = programAndNameToUniformLocation.get(location);
67
- if (uniformName?.name !== "diffuse")
68
- if (true) console.log("Calling uniform3f", { location, x, y, z, name: uniformName?.name });
69
- }
70
- return uniform3f.call(this, location, x, y, z);
71
- };
72
- };
73
- // patchWebGL2();
67
+ // const uniform3f = WebGL2RenderingContext.prototype.uniform3f;
68
+ // WebGL2RenderingContext.prototype.uniform3f = function (location: WebGLUniformLocation
69
+ // | null, x: number, y: number, z: number) {
70
+ // if (location) {
71
+ // const uniformName = programAndNameToUniformLocation.get(location);
72
+ // if (uniformName?.name !== "diffuse")
73
+ // if (true) console.log("Calling uniform3f", { location, x, y, z, name: uniformName?.name });
74
+ // }
75
+ // return uniform3f.call(this, location, x, y, z);
76
+ // };
77
+ // };
78
+ // // patchWebGL2();
74
79
 
75
-
76
- // TODO doesn't actually reset yet...
77
- function resetShaders(ctx: Context) {
78
- const scene = ctx.scene;
79
- const gl = ctx.renderer;
80
- console.log(gl.properties, gl.info)
81
- scene.traverse(object => {
82
- if ((object as Mesh).isMesh) {
83
- const mesh = object as Mesh;
84
- if (Array.isArray(mesh.material)) {
85
- mesh.material.forEach(mat => gl.properties.remove(mat));
86
- }
87
- else {
88
- gl.properties.remove(mesh.material);
89
- }
90
- }
91
- })
92
- if (gl.info?.programs)
93
- gl.info.programs.length = 0;
94
- }