@needle-tools/materialx 1.0.1-next.b9467c8 → 1.0.1-next.b9638d9
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/README.md +0 -5
- package/codegen/register_types.ts +0 -4
- package/index.ts +1 -1
- package/package.json +3 -18
- package/src/{materialx.helper.ts → helper.js} +190 -162
- package/src/index.ts +2 -2
- package/src/loader/loader.needle.ts +40 -27
- package/src/loader/loader.three.ts +395 -152
- package/src/materialx.ts +128 -161
- package/src/textureHelper.ts +6 -6
- package/src/utils.ts +4 -39
- package/src/materialx.material.ts +0 -227
- package/src/materialx.types.d.ts +0 -50
package/README.md
CHANGED
|
@@ -2,9 +2,5 @@
|
|
|
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";
|
|
7
5
|
|
|
8
6
|
// Register types
|
|
9
|
-
TypeStore.add("MaterialXMaterial", MaterialXMaterial);
|
|
10
|
-
TypeStore.add("MaterialXUniformUpdate", MaterialXUniformUpdate);
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/materialx",
|
|
3
|
-
"version": "1.0.1-next.
|
|
3
|
+
"version": "1.0.1-next.b9638d9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"exports": {
|
|
@@ -8,11 +8,7 @@
|
|
|
8
8
|
"import": "./index.ts",
|
|
9
9
|
"require": "./index.js"
|
|
10
10
|
},
|
|
11
|
-
"./package.json": "./package.json"
|
|
12
|
-
"./codegen/register_types.ts": {
|
|
13
|
-
"import": "./codegen/register_types.ts",
|
|
14
|
-
"require": "./codegen/register_types.js"
|
|
15
|
-
}
|
|
11
|
+
"./package.json": "./package.json"
|
|
16
12
|
},
|
|
17
13
|
"peerDependencies": {
|
|
18
14
|
"@needle-tools/engine": "4.x",
|
|
@@ -27,16 +23,5 @@
|
|
|
27
23
|
"publishConfig": {
|
|
28
24
|
"access": "public",
|
|
29
25
|
"registry": "https://registry.npmjs.org/"
|
|
30
|
-
}
|
|
31
|
-
"keywords": [
|
|
32
|
-
"needle",
|
|
33
|
-
"materialx",
|
|
34
|
-
"material",
|
|
35
|
-
"shader",
|
|
36
|
-
"threejs",
|
|
37
|
-
"three.js",
|
|
38
|
-
"webgl",
|
|
39
|
-
"mtlx",
|
|
40
|
-
"rendering"
|
|
41
|
-
]
|
|
26
|
+
}
|
|
42
27
|
}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
//
|
|
5
5
|
|
|
6
|
-
import { getParam
|
|
6
|
+
import { getParam } from '@needle-tools/engine';
|
|
7
7
|
import * as THREE from 'three';
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
const debug = getParam("debugmaterialx");
|
|
10
10
|
|
|
11
11
|
const IMAGE_PROPERTY_SEPARATOR = "_";
|
|
12
12
|
const UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "uaddressmode";
|
|
@@ -20,7 +20,8 @@ const IMAGE_PATH_SEPARATOR = "/";
|
|
|
20
20
|
* @param {Object} capabilities
|
|
21
21
|
* @returns {THREE.Texture}
|
|
22
22
|
*/
|
|
23
|
-
export function prepareEnvTexture(texture, capabilities)
|
|
23
|
+
export function prepareEnvTexture(texture, capabilities)
|
|
24
|
+
{
|
|
24
25
|
let newTexture = new THREE.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type);
|
|
25
26
|
newTexture.wrapS = THREE.RepeatWrapping;
|
|
26
27
|
newTexture.anisotropy = capabilities.getMaxAnisotropy();
|
|
@@ -38,12 +39,15 @@ export function prepareEnvTexture(texture, capabilities) {
|
|
|
38
39
|
* @param {any} dimension
|
|
39
40
|
* @returns {THREE.Uniform}
|
|
40
41
|
*/
|
|
41
|
-
function fromVector(value, dimension)
|
|
42
|
+
function fromVector(value, dimension)
|
|
43
|
+
{
|
|
42
44
|
let outValue;
|
|
43
|
-
if (value)
|
|
45
|
+
if (value)
|
|
46
|
+
{
|
|
44
47
|
outValue = [...value.data()];
|
|
45
48
|
}
|
|
46
|
-
else
|
|
49
|
+
else
|
|
50
|
+
{
|
|
47
51
|
outValue = [];
|
|
48
52
|
for (let i = 0; i < dimension; ++i)
|
|
49
53
|
outValue.push(0.0);
|
|
@@ -54,16 +58,23 @@ function fromVector(value, dimension) {
|
|
|
54
58
|
|
|
55
59
|
/**
|
|
56
60
|
* Get Three uniform from MaterialX matrix
|
|
61
|
+
* @param {mx.matrix} matrix
|
|
62
|
+
* @param {mx.matrix.size} dimension
|
|
57
63
|
*/
|
|
58
|
-
function fromMatrix(matrix
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
function fromMatrix(matrix, dimension)
|
|
65
|
+
{
|
|
66
|
+
let vec = [];
|
|
67
|
+
if (matrix)
|
|
68
|
+
{
|
|
69
|
+
for (let i = 0; i < matrix.numRows(); ++i)
|
|
70
|
+
{
|
|
71
|
+
for (let k = 0; k < matrix.numColumns(); ++k)
|
|
72
|
+
{
|
|
63
73
|
vec.push(matrix.getItem(i, k));
|
|
64
74
|
}
|
|
65
75
|
}
|
|
66
|
-
} else
|
|
76
|
+
} else
|
|
77
|
+
{
|
|
67
78
|
for (let i = 0; i < dimension; ++i)
|
|
68
79
|
vec.push(0.0);
|
|
69
80
|
}
|
|
@@ -71,99 +82,125 @@ function fromMatrix(matrix: MaterialX.Matrix, dimension: MaterialX.Matrix["size"
|
|
|
71
82
|
return vec;
|
|
72
83
|
}
|
|
73
84
|
|
|
74
|
-
|
|
75
|
-
export type Loaders = {
|
|
76
|
-
getTexture: (path: string) => THREE.Texture;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
85
|
/**
|
|
80
86
|
* Get Three uniform from MaterialX value
|
|
81
87
|
* @param {mx.Uniform.type} type
|
|
82
88
|
* @param {mx.Uniform.value} value
|
|
83
89
|
* @param {mx.Uniform.name} name
|
|
84
90
|
* @param {mx.Uniforms} uniforms
|
|
85
|
-
* @param {
|
|
91
|
+
* @param {THREE.textureLoader} textureLoader
|
|
86
92
|
* @param {string} searchPath
|
|
87
93
|
* @param {boolean} flipY
|
|
88
94
|
*/
|
|
89
|
-
function toThreeUniform(type
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY)
|
|
96
|
+
{
|
|
97
|
+
let outValue = null;
|
|
98
|
+
switch (type)
|
|
99
|
+
{
|
|
92
100
|
case 'float':
|
|
93
101
|
case 'integer':
|
|
94
102
|
case 'boolean':
|
|
95
|
-
|
|
103
|
+
outValue = value;
|
|
96
104
|
break;
|
|
97
105
|
case 'vector2':
|
|
98
|
-
|
|
106
|
+
outValue = fromVector(value, 2);
|
|
99
107
|
break;
|
|
100
108
|
case 'vector3':
|
|
101
109
|
case 'color3':
|
|
102
|
-
|
|
110
|
+
outValue = fromVector(value, 3);
|
|
111
|
+
break;
|
|
103
112
|
case 'vector4':
|
|
104
113
|
case 'color4':
|
|
105
|
-
|
|
114
|
+
outValue = fromVector(value, 4);
|
|
115
|
+
break;
|
|
106
116
|
case 'matrix33':
|
|
107
|
-
|
|
117
|
+
outValue = fromMatrix(value, 9);
|
|
118
|
+
break;
|
|
108
119
|
case 'matrix44':
|
|
109
|
-
|
|
120
|
+
outValue = fromMatrix(value, 16);
|
|
121
|
+
break;
|
|
110
122
|
case 'filename':
|
|
111
|
-
if (value)
|
|
123
|
+
if (value)
|
|
124
|
+
{
|
|
112
125
|
// Cache / reuse texture to avoid reload overhead.
|
|
113
126
|
// Note: that data blobs and embedded data textures are not cached as they are transient data.
|
|
114
127
|
let checkCache = false;
|
|
115
128
|
let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value;
|
|
116
|
-
if (value.startsWith('blob:'))
|
|
129
|
+
if (value.startsWith('blob:'))
|
|
130
|
+
{
|
|
117
131
|
texturePath = value;
|
|
118
132
|
if (debug) console.log('Load blob URL:', texturePath);
|
|
119
133
|
checkCache = false;
|
|
120
134
|
}
|
|
121
|
-
else if (value.startsWith('http'))
|
|
135
|
+
else if (value.startsWith('http'))
|
|
136
|
+
{
|
|
122
137
|
texturePath = value;
|
|
123
138
|
if (debug) console.log('Load HTTP URL:', texturePath);
|
|
124
139
|
}
|
|
125
|
-
else if (value.startsWith('data:'))
|
|
140
|
+
else if (value.startsWith('data:'))
|
|
141
|
+
{
|
|
126
142
|
texturePath = value;
|
|
127
143
|
checkCache = false;
|
|
128
144
|
if (debug) console.log('Load data URL:', texturePath);
|
|
129
145
|
}
|
|
130
146
|
const cachedTexture = checkCache && THREE.Cache.get(texturePath);
|
|
131
|
-
if (cachedTexture)
|
|
132
|
-
|
|
133
|
-
|
|
147
|
+
if (cachedTexture)
|
|
148
|
+
{
|
|
149
|
+
// Get texture from cache
|
|
150
|
+
outValue = cachedTexture;
|
|
151
|
+
if (debug) console.log('Use cached texture: ', texturePath, outValue);
|
|
134
152
|
}
|
|
135
|
-
else
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
else
|
|
154
|
+
{
|
|
155
|
+
outValue = textureLoader.load(
|
|
156
|
+
texturePath,
|
|
157
|
+
function (texture) {
|
|
158
|
+
if (debug) console.log('Load new texture: ' + texturePath, texture);
|
|
159
|
+
outValue = texture;
|
|
160
|
+
|
|
161
|
+
// Add texture to ThreeJS cache
|
|
162
|
+
if (checkCache)
|
|
163
|
+
THREE.Cache.add(texturePath, texture);
|
|
164
|
+
},
|
|
165
|
+
undefined,
|
|
166
|
+
function (error) {
|
|
167
|
+
console.error('Error loading texture: ', error);
|
|
168
|
+
});
|
|
169
|
+
|
|
138
170
|
// Set address & filtering mode
|
|
139
|
-
if (
|
|
140
|
-
|
|
171
|
+
if (outValue)
|
|
172
|
+
setTextureParameters(outValue, name, uniforms, flipY);
|
|
141
173
|
}
|
|
142
174
|
}
|
|
143
175
|
break;
|
|
144
176
|
case 'samplerCube':
|
|
145
177
|
case 'string':
|
|
146
|
-
|
|
178
|
+
break;
|
|
147
179
|
default:
|
|
148
180
|
const key = type + ':' + name;
|
|
149
|
-
if (!valueTypeWarningMap.has(key))
|
|
181
|
+
if (!valueTypeWarningMap.has(key))
|
|
182
|
+
{
|
|
150
183
|
valueTypeWarningMap.set(key, true);
|
|
151
184
|
console.warn('MaterialX: Unsupported uniform type: ' + type + ' for uniform: ' + name, value);
|
|
152
185
|
}
|
|
153
|
-
|
|
186
|
+
outValue = null;
|
|
154
187
|
}
|
|
188
|
+
|
|
189
|
+
return outValue;
|
|
155
190
|
}
|
|
156
191
|
|
|
157
|
-
const valueTypeWarningMap = new Map
|
|
192
|
+
const valueTypeWarningMap = new Map();
|
|
158
193
|
|
|
159
194
|
/**
|
|
160
195
|
* Get Three wrapping mode
|
|
161
196
|
* @param {mx.TextureFilter.wrap} mode
|
|
162
197
|
* @returns {THREE.Wrapping}
|
|
163
198
|
*/
|
|
164
|
-
function getWrapping(mode)
|
|
199
|
+
function getWrapping(mode)
|
|
200
|
+
{
|
|
165
201
|
let wrap;
|
|
166
|
-
switch (mode)
|
|
202
|
+
switch (mode)
|
|
203
|
+
{
|
|
167
204
|
case 1:
|
|
168
205
|
wrap = THREE.ClampToEdgeWrapping;
|
|
169
206
|
break;
|
|
@@ -185,9 +222,12 @@ function getWrapping(mode) {
|
|
|
185
222
|
* @param {mx.TextureFilter.minFilter} type
|
|
186
223
|
* @param {mx.TextureFilter.generateMipmaps} generateMipmaps
|
|
187
224
|
*/
|
|
188
|
-
function getMinFilter(type, generateMipmaps)
|
|
189
|
-
|
|
190
|
-
|
|
225
|
+
function getMinFilter(type, generateMipmaps)
|
|
226
|
+
{
|
|
227
|
+
/** @type {THREE.TextureFilter} */
|
|
228
|
+
let filterType = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter;
|
|
229
|
+
if (type === 0)
|
|
230
|
+
{
|
|
191
231
|
filterType = generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter;
|
|
192
232
|
}
|
|
193
233
|
return filterType;
|
|
@@ -200,22 +240,25 @@ function getMinFilter(type, generateMipmaps) {
|
|
|
200
240
|
* @param {mx.Uniforms} uniforms
|
|
201
241
|
* @param {mx.TextureFilter.generateMipmaps} generateMipmaps
|
|
202
242
|
*/
|
|
203
|
-
function setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true)
|
|
243
|
+
function setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true)
|
|
244
|
+
{
|
|
204
245
|
const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);
|
|
205
246
|
const base = name.substring(0, idx) || name;
|
|
206
247
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
248
|
+
texture.generateMipmaps = generateMipmaps;
|
|
249
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
250
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
251
|
+
texture.magFilter = THREE.LinearFilter;
|
|
252
|
+
texture.flipY = flipY;
|
|
212
253
|
|
|
213
|
-
if (uniforms.find(base + UADDRESS_MODE_SUFFIX))
|
|
254
|
+
if (uniforms.find(base + UADDRESS_MODE_SUFFIX))
|
|
255
|
+
{
|
|
214
256
|
const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData();
|
|
215
257
|
texture.wrapS = getWrapping(uaddressmode);
|
|
216
258
|
}
|
|
217
259
|
|
|
218
|
-
if (uniforms.find(base + VADDRESS_MODE_SUFFIX))
|
|
260
|
+
if (uniforms.find(base + VADDRESS_MODE_SUFFIX))
|
|
261
|
+
{
|
|
219
262
|
const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData();
|
|
220
263
|
texture.wrapT = getWrapping(vaddressmode);
|
|
221
264
|
}
|
|
@@ -227,7 +270,8 @@ function setTextureParameters(texture, name, uniforms, flipY = true, generateMip
|
|
|
227
270
|
/**
|
|
228
271
|
* Return the global light rotation matrix
|
|
229
272
|
*/
|
|
230
|
-
export function getLightRotation()
|
|
273
|
+
export function getLightRotation()
|
|
274
|
+
{
|
|
231
275
|
return new THREE.Matrix4().makeRotationY(Math.PI / 2);
|
|
232
276
|
}
|
|
233
277
|
|
|
@@ -236,27 +280,32 @@ export function getLightRotation() {
|
|
|
236
280
|
* @param {mx.Document} doc
|
|
237
281
|
* @returns {Array.<mx.Node>}
|
|
238
282
|
*/
|
|
239
|
-
export function findLights(doc
|
|
240
|
-
|
|
241
|
-
|
|
283
|
+
export function findLights(doc)
|
|
284
|
+
{
|
|
285
|
+
let lights = [];
|
|
286
|
+
for (let node of doc.getNodes())
|
|
287
|
+
{
|
|
242
288
|
if (node.getType() === "lightshader")
|
|
243
289
|
lights.push(node);
|
|
244
290
|
}
|
|
245
291
|
return lights;
|
|
246
292
|
}
|
|
247
293
|
|
|
248
|
-
let lightTypesBound = {};
|
|
249
|
-
|
|
250
294
|
/**
|
|
251
295
|
* Register lights in shader generation context
|
|
252
|
-
* @param {
|
|
296
|
+
* @param {Object} mx MaterialX Module
|
|
297
|
+
* @param {Array.<mx.Node>} lights Light nodes
|
|
253
298
|
* @param {mx.GenContext} genContext Shader generation context
|
|
299
|
+
* @returns {Array.<mx.Node>}
|
|
254
300
|
*/
|
|
255
|
-
export async function registerLights(mx
|
|
256
|
-
|
|
257
|
-
const maxLightCount = genContext.getOptions().hwMaxActiveLightSources;
|
|
301
|
+
export async function registerLights(mx, lights, genContext)
|
|
302
|
+
{
|
|
258
303
|
mx.HwShaderGenerator.unbindLightShaders(genContext);
|
|
304
|
+
|
|
305
|
+
const lightTypesBound = {};
|
|
306
|
+
const lightData = [];
|
|
259
307
|
let lightId = 1;
|
|
308
|
+
|
|
260
309
|
// All light types so that we have NodeDefs for them
|
|
261
310
|
const defaultLightRigXml = `<?xml version="1.0"?>
|
|
262
311
|
<materialx version="1.39">
|
|
@@ -274,7 +323,7 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
|
|
|
274
323
|
|
|
275
324
|
// Load default light rig XML to ensure we have all light types available
|
|
276
325
|
const lightRigDoc = mx.createDocument();
|
|
277
|
-
await mx.readFromXmlString(lightRigDoc, defaultLightRigXml
|
|
326
|
+
await mx.readFromXmlString(lightRigDoc, defaultLightRigXml);
|
|
278
327
|
const document = mx.createDocument();
|
|
279
328
|
const stdlib = mx.loadStandardLibraries(genContext);
|
|
280
329
|
document.setDataLibrary(stdlib);
|
|
@@ -282,19 +331,18 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
|
|
|
282
331
|
const defaultLights = findLights(document);
|
|
283
332
|
if (debug) console.log("Default lights in MaterialX document", defaultLights);
|
|
284
333
|
|
|
285
|
-
// Loading a document seems to reset this option for some reason, so we set it again
|
|
286
|
-
genContext.getOptions().hwMaxActiveLightSources = maxLightCount;
|
|
287
|
-
|
|
288
334
|
// Register types only – we get these from the default light rig XML above
|
|
289
335
|
// This is needed to ensure that the light shaders are bound for each light type
|
|
290
|
-
for (let light of defaultLights)
|
|
336
|
+
for (let light of defaultLights)
|
|
337
|
+
{
|
|
291
338
|
const lightDef = light.getNodeDef();
|
|
292
339
|
if (debug) console.log("Default light node definition", lightDef);
|
|
293
340
|
if (!lightDef) continue;
|
|
294
341
|
|
|
295
342
|
const lightName = lightDef.getName();
|
|
296
343
|
if (debug) console.log("Registering default light", { lightName, lightDef });
|
|
297
|
-
if (!lightTypesBound[lightName])
|
|
344
|
+
if (!lightTypesBound[lightName])
|
|
345
|
+
{
|
|
298
346
|
// TODO check if we need to bind light shader for each three.js light instead of once per type
|
|
299
347
|
if (debug) console.log("Bind light shader for node", { lightName, lightId, lightDef });
|
|
300
348
|
lightTypesBound[lightName] = lightId;
|
|
@@ -303,40 +351,52 @@ export async function registerLights(mx: MaterialX.MODULE, genContext: any): Pro
|
|
|
303
351
|
}
|
|
304
352
|
|
|
305
353
|
if (debug) console.log("Light types bound in MaterialX context", lightTypesBound);
|
|
306
|
-
}
|
|
307
354
|
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
console.
|
|
319
|
-
|
|
355
|
+
// MaterialX light nodes
|
|
356
|
+
for (let light of lights)
|
|
357
|
+
{
|
|
358
|
+
// Skip if light does not have a node definition
|
|
359
|
+
if (!("getNodeDef" in light)) continue;
|
|
360
|
+
|
|
361
|
+
let nodeDef = light.getNodeDef();
|
|
362
|
+
let nodeName = nodeDef.getName();
|
|
363
|
+
if (!lightTypesBound[nodeName])
|
|
364
|
+
{
|
|
365
|
+
if (debug) console.log("bind light shader for node", { nodeName, lightId, nodeDef });
|
|
366
|
+
lightTypesBound[nodeName] = lightId;
|
|
367
|
+
mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const lightDirection = light.getValueElement("direction").getValue().getData().data();
|
|
371
|
+
const lightColor = light.getValueElement("color").getValue().getData().data();
|
|
372
|
+
const lightIntensity = light.getValueElement("intensity").getValue().getData();
|
|
373
|
+
|
|
374
|
+
let rotatedLightDirection = new THREE.Vector3(...lightDirection)
|
|
375
|
+
rotatedLightDirection.transformDirection(getLightRotation())
|
|
376
|
+
|
|
377
|
+
lightData.push({
|
|
378
|
+
type: lightTypesBound[nodeName],
|
|
379
|
+
direction: rotatedLightDirection,
|
|
380
|
+
color: new THREE.Vector3(...lightColor),
|
|
381
|
+
intensity: lightIntensity,
|
|
382
|
+
});
|
|
320
383
|
}
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
type LightData = {
|
|
324
|
-
type: number, // Light type ID
|
|
325
|
-
position: THREE.Vector3, // Position in world space
|
|
326
|
-
direction: THREE.Vector3, // Direction in world space
|
|
327
|
-
color: THREE.Color, // Color of the light
|
|
328
|
-
intensity: number, // Intensity of the light
|
|
329
|
-
decay_rate: number, // Decay rate for point and spot lights
|
|
330
|
-
inner_angle: number, // Inner angle for spot lights
|
|
331
|
-
outer_angle: number, // Outer angle for spot lights
|
|
332
|
-
}
|
|
333
384
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
385
|
+
const threeLightTypeToMaterialXNodeName = (threeLightType) => {
|
|
386
|
+
switch (threeLightType) {
|
|
387
|
+
case 'PointLight':
|
|
388
|
+
return 'ND_point_light';
|
|
389
|
+
case 'DirectionalLight':
|
|
390
|
+
return 'ND_directional_light';
|
|
391
|
+
case 'SpotLight':
|
|
392
|
+
return 'ND_spot_light';
|
|
393
|
+
default:
|
|
394
|
+
console.warn('MaterialX: Unsupported light type: ' + threeLightType);
|
|
395
|
+
return 'ND_point_light'; // Default to point light
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
if (debug) console.log("Registering lights in MaterialX context", lights, lightData);
|
|
340
400
|
|
|
341
401
|
// Three.js lights
|
|
342
402
|
for (let light of lights) {
|
|
@@ -348,82 +408,50 @@ export function getLightData(lights: any, genContext: any): { lightData: LightDa
|
|
|
348
408
|
const lightDefinitionName = threeLightTypeToMaterialXNodeName(light.type);
|
|
349
409
|
|
|
350
410
|
if (!lightTypesBound[lightDefinitionName])
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
// Shader math from the generated MaterialX shader:
|
|
357
|
-
// float low = min(light.inner_angle, light.outer_angle);
|
|
358
|
-
// float high = light.inner_angle;
|
|
359
|
-
// float cosDir = dot(result.direction, -light.direction);
|
|
360
|
-
// float spotAttenuation = smoothstep(low, high, cosDir);
|
|
361
|
-
|
|
362
|
-
const outerAngleRad = light.angle;
|
|
363
|
-
const innerAngleRad = outerAngleRad * (1 - light.penumbra);
|
|
364
|
-
const inner_angle = Math.cos(innerAngleRad);
|
|
365
|
-
const outer_angle = Math.cos(outerAngleRad);
|
|
411
|
+
{
|
|
412
|
+
lightTypesBound[lightDefinitionName] = lightId;
|
|
413
|
+
const nodeDef = null;
|
|
414
|
+
mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);
|
|
415
|
+
}
|
|
366
416
|
|
|
367
417
|
lightData.push({
|
|
368
418
|
type: lightTypesBound[lightDefinitionName],
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
// Luminous efficacy for converting radiant power in watts (W) to luminous flux in lumens (lm) at a wavelength of 555 nm.
|
|
373
|
-
// 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.
|
|
374
|
-
intensity: light.intensity * (light.isPointLight ? 683.0 / 3.1415 : light.isSpotLight ? 683.0 / 3.1415 : 1.0),
|
|
375
|
-
decay_rate: 2.0,
|
|
376
|
-
// Approximations for testing – the relevant light has 61.57986...129.4445 as inner/outer spot angle
|
|
377
|
-
inner_angle: inner_angle,
|
|
378
|
-
outer_angle: outer_angle,
|
|
419
|
+
direction: light.direction?.clone() || new THREE.Vector3(0, -1, 0),
|
|
420
|
+
color: new THREE.Vector3().fromArray(light.color.toArray()),
|
|
421
|
+
intensity: light.intensity,
|
|
379
422
|
});
|
|
380
423
|
}
|
|
381
424
|
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
// If we don't have enough entries in lightData, fill with empty lights
|
|
386
|
-
while (lightData.length < maxLightCount) {
|
|
387
|
-
const emptyLight = {
|
|
388
|
-
type: 0, // Default light type
|
|
389
|
-
position: new THREE.Vector3(0, 0, 0),
|
|
390
|
-
direction: new THREE.Vector3(0, 0, -1),
|
|
391
|
-
color: new THREE.Color(0, 0, 0),
|
|
392
|
-
intensity: 0.0,
|
|
393
|
-
decay_rate: 2.0,
|
|
394
|
-
inner_angle: 0.0,
|
|
395
|
-
outer_angle: 0.0,
|
|
396
|
-
};
|
|
397
|
-
lightData.push(emptyLight);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (debugUpdate) console.log("Registered lights in MaterialX context", lightTypesBound, lightData);
|
|
425
|
+
// Make sure max light count is large enough
|
|
426
|
+
genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lightData.length);
|
|
401
427
|
|
|
402
|
-
return
|
|
428
|
+
return lightData;
|
|
403
429
|
}
|
|
404
430
|
|
|
405
431
|
/**
|
|
406
432
|
* Get uniform values for a shader
|
|
433
|
+
* @param {mx.shaderStage} shaderStage
|
|
434
|
+
* @param {THREE.TextureLoader} textureLoader
|
|
407
435
|
*/
|
|
408
|
-
export function getUniformValues(shaderStage
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
for (let i = 0; i < uniforms.size(); ++i)
|
|
436
|
+
export function getUniformValues(shaderStage, textureLoader, searchPath, flipY)
|
|
437
|
+
{
|
|
438
|
+
let threeUniforms = {};
|
|
439
|
+
|
|
440
|
+
const uniformBlocks = Object.values(shaderStage.getUniformBlocks());
|
|
441
|
+
uniformBlocks.forEach(uniforms =>
|
|
442
|
+
{
|
|
443
|
+
if (!uniforms.empty())
|
|
444
|
+
{
|
|
445
|
+
for (let i = 0; i < uniforms.size(); ++i)
|
|
446
|
+
{
|
|
418
447
|
const variable = uniforms.get(i);
|
|
419
448
|
const value = variable.getValue()?.getData();
|
|
420
449
|
const name = variable.getVariable();
|
|
421
|
-
if (debug) console.log("Adding uniform", { path: variable.getPath(), name, value, type: variable.getType().getName() });
|
|
422
450
|
threeUniforms[name] = new THREE.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms,
|
|
423
|
-
|
|
451
|
+
textureLoader, searchPath, flipY));
|
|
424
452
|
}
|
|
425
453
|
}
|
|
426
|
-
}
|
|
454
|
+
});
|
|
427
455
|
|
|
428
456
|
return threeUniforms;
|
|
429
457
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { initializeMaterialX, state } from "./materialx.js";
|
|
2
2
|
|
|
3
3
|
const getMaterialXEnvironment = () => state.materialXEnvironment;
|
|
4
4
|
|
|
5
|
-
export {
|
|
5
|
+
export { initializeMaterialX, getMaterialXEnvironment };
|