@needle-tools/materialx 1.5.0-next.b9d5f3f → 1.5.1
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 +48 -10
- package/README.md +11 -3
- package/package.json +1 -1
- package/src/materialx.material.js +45 -16
package/CHANGELOG.md
CHANGED
|
@@ -4,35 +4,70 @@ 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.5.
|
|
7
|
+
## [1.5.1] – 2026-03-22
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- UV patching: always wrap vec3 targets regardless of source UV declaration type
|
|
11
|
+
- Vertex color: wrap vec3→vec4 for color attributes (Three.js provides vec3)
|
|
12
|
+
- Shader test page uses proper environment/lighting matching other test pages
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Playwright e2e tests validating 111+ MaterialX materials for shader compilation
|
|
16
|
+
|
|
17
|
+
## [1.5.0] – 2026-03-20
|
|
8
18
|
|
|
9
19
|
### Added
|
|
10
20
|
- Vertex displacement support (GLSL and ESSL/WebGL 2)
|
|
11
|
-
- Multioutput nodedef pattern for shared surface + displacement parameters
|
|
12
21
|
- Normal recomputation via screen-space derivatives (dFdx/dFdy) for displaced surfaces
|
|
13
22
|
- Procedural noise displacement (fractal3d, position, math nodes)
|
|
14
23
|
- Texture-based displacement (image node sampling in vertex shader)
|
|
15
24
|
- Displacement animation support via Three.js PropertyBinding
|
|
25
|
+
- Three.js shadow support for lit MaterialX shaders (directional, spot, point)
|
|
26
|
+
- Alpha mode detection via `getAlphaMode` for mask/blend transparency
|
|
16
27
|
|
|
17
28
|
### Fixed
|
|
18
|
-
-
|
|
19
|
-
-
|
|
29
|
+
- Unlit shaders no longer emit shadow uniforms that cause compilation errors
|
|
30
|
+
- UV vec2/vec3 patching for displacement vertex shaders
|
|
31
|
+
- Skip MaterialX shader closure types (surfaceshader, displacementshader, etc.) in uniform handling
|
|
20
32
|
|
|
21
33
|
### Changed
|
|
22
34
|
- WASM rebuilt with displacement support (MaterialX 1.39.4, Emscripten 3.1.74)
|
|
35
|
+
- Environment map intensity now combines per-material and scene intensity
|
|
36
|
+
|
|
37
|
+
## [1.4.6] – 2026-03-17
|
|
38
|
+
- Fix: Compatibility with older Rollup/Vite 4 by replacing `import ... with` syntax
|
|
39
|
+
|
|
40
|
+
## [1.4.5] – 2026-03-17
|
|
41
|
+
- Fix: Improved error log formatting with package version
|
|
42
|
+
|
|
43
|
+
## [1.4.4] – 2026-03-17
|
|
44
|
+
- Fix: Minor type fixes and improved debug logging
|
|
23
45
|
|
|
24
46
|
## [1.4.3] – 2026-02-20
|
|
25
|
-
-
|
|
47
|
+
- Add: `globalThis.NEEDLE_MATERIALX_LOCATION` to override WASM location. Use `"package"` for package-local files, or a custom path for self-hosted/CDN.
|
|
26
48
|
|
|
27
49
|
## [1.4.2] – 2026-02-10
|
|
28
50
|
- Fix: Improve error handling when MaterialX renderable element is not found
|
|
29
51
|
|
|
30
52
|
## [1.4.1] – 2026-02-10
|
|
31
|
-
-
|
|
53
|
+
- Change: Use CDN as default WASM source
|
|
54
|
+
|
|
55
|
+
## [1.4.0] – 2026-02-10
|
|
56
|
+
- Change: Load WASM binaries from Needle CDN by default instead of bundling locally
|
|
57
|
+
|
|
58
|
+
## [1.3.4] – 2026-02-09
|
|
59
|
+
- Fix: Matrix update for AR sessions
|
|
60
|
+
|
|
61
|
+
## [1.3.3] – 2026-02-09
|
|
62
|
+
- Add: Support for loading `.mtlx` files by index
|
|
63
|
+
- Fix: Type fixes in loader
|
|
32
64
|
|
|
33
65
|
## [1.3.2] - 2025-08-12
|
|
34
66
|
- Fix: Error when MaterialX extension is not present
|
|
35
67
|
|
|
68
|
+
## [1.3.1] - 2025-08-12
|
|
69
|
+
- Docs: README improvements
|
|
70
|
+
|
|
36
71
|
## [1.3.0] - 2025-08-12
|
|
37
72
|
- Change: Refactor extension to use a documents array instead of a single document, backwards compatibility is maintained
|
|
38
73
|
|
|
@@ -40,7 +75,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
40
75
|
- Add: `preloadWasm` function with support to wait for network idle. This is automatically done for Needle Engine projects.
|
|
41
76
|
|
|
42
77
|
## [1.2.1] - 2025-07-23
|
|
43
|
-
- Fix:
|
|
78
|
+
- Fix: Error caused by scene.environment being null
|
|
44
79
|
|
|
45
80
|
## [1.2.0] - 2025-07-23
|
|
46
81
|
- Add: Support to load raw MaterialX materials (from mtlx as XML)
|
|
@@ -52,12 +87,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
52
87
|
- Add: `useNeedleMaterialX` hooks for vanilla three.js and Needle Engine
|
|
53
88
|
|
|
54
89
|
## [1.0.6] - 2025-07-15
|
|
55
|
-
- Fix:
|
|
90
|
+
- Fix: Texture/environment sampling on some Android devices
|
|
91
|
+
|
|
92
|
+
## [1.0.3] - 2025-07-10
|
|
93
|
+
- Fix: Version bump for npm publish
|
|
56
94
|
|
|
57
95
|
## [1.0.2] - 2025-07-10
|
|
58
96
|
- Add: Material extension `doubleSided` support
|
|
59
|
-
- Improved lighting support
|
|
60
|
-
-
|
|
97
|
+
- Fix: Improved lighting support
|
|
98
|
+
- Fix: Texture loading and glTF texture index resolution
|
|
61
99
|
|
|
62
100
|
## [1.0.1] - 2025-07-08
|
|
63
101
|
- Initial release
|
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# Needle MaterialX – MaterialX Materials for three.js & the Web
|
|
2
2
|
|
|
3
|
-
Web runtime for [MaterialX](https://materialx.org/) materials in [Needle Engine](https://needle.tools) and [three.js](https://threejs.org/). Renders physically based MaterialX shaders in the browser using WebAssembly — load `.mtlx` files or glTF assets with the `NEEDLE_materials_mtlx` extension.
|
|
3
|
+
Web runtime for [MaterialX](https://materialx.org/) materials in [Needle Engine](https://needle.tools) and [three.js](https://threejs.org/). Renders physically based MaterialX shaders in the browser using WebAssembly — load `.mtlx` files or glTF assets with the `NEEDLE_materials_mtlx` extension (created with Needle Engine's Unity integration and ShaderGraph).
|
|
4
4
|
|
|
5
5
|
- MaterialX to WebGL/WebGPU shader generation via WASM
|
|
6
6
|
- Vertex displacement support (procedural noise, texture-based, animatable)
|
|
7
|
+
- Three.js shadow support (directional, spot, point lights)
|
|
8
|
+
- Alpha mask and blend transparency modes
|
|
7
9
|
- glTF extension for embedding MaterialX materials in `.glb`/`.gltf` files
|
|
8
10
|
- Experimental support for loading raw MaterialX XML (`.mtlx`) files
|
|
9
11
|
- Works standalone with three.js or as a Needle Engine module
|
|
@@ -23,16 +25,22 @@ Web runtime for [MaterialX](https://materialx.org/) materials in [Needle Engine]
|
|
|
23
25
|
|
|
24
26
|
### Use with Needle Engine
|
|
25
27
|
|
|
26
|
-
**Needle Engine has built in support for MaterialX shaders.**
|
|
28
|
+
**Needle Engine has built in support for MaterialX shaders.**
|
|
29
|
+
No changes to your code are necessary. The MaterialX module will import lazily when needed.
|
|
27
30
|
|
|
28
31
|
### Use with three.js
|
|
29
32
|
|
|
30
33
|
```ts
|
|
31
34
|
import { useNeedleMaterialX } from "@needle-tools/materialx";
|
|
32
|
-
// Call the function with your GLTFLoader instance
|
|
35
|
+
// Call the function with your GLTFLoader instance to add the GLTFLoader plugin
|
|
33
36
|
useNeedleMaterialX(<yourGltfLoaderInstance>);
|
|
34
37
|
```
|
|
35
38
|
|
|
39
|
+
### Accessing Materials
|
|
40
|
+
MaterialX shaders will create `MaterialXMaterial` materials at runtime. These are custom three.js ShaderMaterials and assigned to objects like any other three.js material.
|
|
41
|
+
|
|
42
|
+
[Learn more in the Needle Engine documentation](https://engine.needle.tools/docs/how-to-guides/export/materialx.html)
|
|
43
|
+
|
|
36
44
|
## WASM
|
|
37
45
|
|
|
38
46
|
### Default (CDN)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.5.
|
|
4
|
+
"version": "1.5.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
@@ -122,7 +122,9 @@ export class MaterialXMaterial extends ShaderMaterial {
|
|
|
122
122
|
fragmentShader = fragmentShader.replace(/\bu_envLightIntensity\b/g, 'envMapIntensity');
|
|
123
123
|
|
|
124
124
|
// Capture some vertex shader properties
|
|
125
|
-
|
|
125
|
+
// Detect whether each UV was originally vec2 or vec3 before removing declarations.
|
|
126
|
+
// Three.js always provides vec2 attributes, so vec3 assignments need wrapping.
|
|
127
|
+
const uv_is_vec2 = vertexShader.includes('in vec2 uv;');
|
|
126
128
|
const uv1_is_vec2 = vertexShader.includes('in vec2 uv1;');
|
|
127
129
|
const uv2_is_vec2 = vertexShader.includes('in vec2 uv2;');
|
|
128
130
|
const uv3_is_vec2 = vertexShader.includes('in vec2 uv3;');
|
|
@@ -142,20 +144,41 @@ export class MaterialXMaterial extends ShaderMaterial {
|
|
|
142
144
|
vertexShader = vertexShader.replace(/in\s+vec4\s+tangent;/g, '');
|
|
143
145
|
var hasColor = vertexShader.includes('in vec4 color;');
|
|
144
146
|
vertexShader = vertexShader.replace(/in\s+vec4\s+color;/g, '');
|
|
147
|
+
// Three.js provides `color` as vec3 but MaterialX declares it as vec4.
|
|
148
|
+
// Wrap assignments to vec4 targets: `color_0 = color;` → `color_0 = vec4(color, 1.0);`
|
|
149
|
+
if (hasColor) {
|
|
150
|
+
vertexShader = vertexShader.replace(/\bvec4 (\w+) = color;/g, 'vec4 $1 = vec4(color, 1.0);');
|
|
151
|
+
vertexShader = vertexShader.replace(/(\w+) = color;/g, (match, name) => {
|
|
152
|
+
if (match.includes('vec4')) return match;
|
|
153
|
+
const isVec4 = new RegExp(`\\bvec4\\s+${name}\\b`).test(vertexShader);
|
|
154
|
+
return isVec4 ? `${name} = vec4(color, 1.0);` : match;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
145
157
|
|
|
146
|
-
// Patch uv
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
// Patch uv vec2→vec3. Three.js always provides uv/uv1/uv2/uv3 as vec2
|
|
159
|
+
// attributes. When MaterialX originally declared them as vec3, any
|
|
160
|
+
// assignment from these attributes to a vec3 variable needs wrapping.
|
|
161
|
+
// When the UV was originally vec2, all assignments are already compatible.
|
|
162
|
+
// Three.js always provides uv/uv1/uv2/uv3 as vec2 attributes.
|
|
163
|
+
// When the generated shader assigns them to vec3 variables, we need to wrap.
|
|
164
|
+
// This applies regardless of the original declaration type, because Three.js
|
|
165
|
+
// always delivers vec2.
|
|
166
|
+
/** @param {string} shader @param {string} uvName */
|
|
167
|
+
function patchUvAssignments(shader, uvName) {
|
|
168
|
+
// 1. Declaration assignments: `vec3 x = <uv>;` → `vec3 x = vec3(<uv>, 0.0);`
|
|
169
|
+
shader = shader.replace(new RegExp(`\\bvec3 (\\w+) = ${uvName};`, 'g'), `vec3 $1 = vec3(${uvName}, 0.0);`);
|
|
170
|
+
// 2. Non-declaration assignments: `x = <uv>;` → wrap only when target is vec3
|
|
171
|
+
shader = shader.replace(new RegExp(`(\\w+) = ${uvName};`, 'g'), (match, name) => {
|
|
172
|
+
if (match.includes('vec3')) return match; // already handled
|
|
173
|
+
const isVec3 = new RegExp(`\\bvec3\\s+${name}\\b`).test(shader);
|
|
174
|
+
return isVec3 ? `${name} = vec3(${uvName}, 0.0);` : match;
|
|
175
|
+
});
|
|
176
|
+
return shader;
|
|
177
|
+
}
|
|
178
|
+
vertexShader = patchUvAssignments(vertexShader, 'uv');
|
|
179
|
+
vertexShader = patchUvAssignments(vertexShader, 'uv1');
|
|
180
|
+
vertexShader = patchUvAssignments(vertexShader, 'uv2');
|
|
181
|
+
vertexShader = patchUvAssignments(vertexShader, 'uv3');
|
|
159
182
|
|
|
160
183
|
// Patch units – seems MaterialX uses different units and we end up with wrong light values?
|
|
161
184
|
// result.direction = light.position - position;
|
|
@@ -182,7 +205,12 @@ export class MaterialXMaterial extends ShaderMaterial {
|
|
|
182
205
|
if (hasTangent) defines['USE_TANGENT'] = '';
|
|
183
206
|
if (hasColor) defines['USE_COLOR'] = '';
|
|
184
207
|
|
|
185
|
-
//
|
|
208
|
+
// Detect whether the vertex shader declares the inverse-transpose matrix uniform.
|
|
209
|
+
// Unlit shaders omit this uniform, so shadow code that references it would fail.
|
|
210
|
+
const hasShadowUniforms = vertexShader.includes('u_worldInverseTransposeMatrix');
|
|
211
|
+
|
|
212
|
+
// Add Three.js shadow support (only when the vertex shader has the required uniforms)
|
|
213
|
+
if (hasShadowUniforms) {
|
|
186
214
|
// Insert shadow pars before main() in vertex shader
|
|
187
215
|
vertexShader = vertexShader.replace(
|
|
188
216
|
/void\s+main\s*\(\s*\)\s*\{/,
|
|
@@ -199,7 +227,7 @@ void main() {`
|
|
|
199
227
|
/(\n\s*)\}(\s*)$/,
|
|
200
228
|
`$1 // Three.js shadow support
|
|
201
229
|
$1 vec4 worldPosition = u_worldMatrix * vec4(position, 1.0);
|
|
202
|
-
$1 vec3 transformedNormal = mat3(viewMatrix) *
|
|
230
|
+
$1 vec3 transformedNormal = normalize(mat3(viewMatrix) * mat3(u_worldInverseTransposeMatrix) * normal);
|
|
203
231
|
$1 #include <shadowmap_vertex>
|
|
204
232
|
$1}$2`
|
|
205
233
|
);
|
|
@@ -320,6 +348,7 @@ void sampleLightSource(LightData light, vec3 position, out lightshader result)`
|
|
|
320
348
|
}
|
|
321
349
|
$2`
|
|
322
350
|
);
|
|
351
|
+
} // end hasShadowUniforms
|
|
323
352
|
|
|
324
353
|
const isTransparent = init.parameters?.transparent ?? false;
|
|
325
354
|
materialParameters = {
|