zincjs 2.4.1-beta.2 → 2.4.1-beta.4
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 +80 -74
- package/build/zinc.js +3 -3
- package/build/zinc.js.map +1 -1
- package/package.json +1 -1
- package/src/loaders/GLTFToZincJSLoader.js +60 -3
- package/src/loaders/JSONLoader.js +2 -2
- package/src/loaders/niftiReader.js +2 -2
- package/src/loaders/primitivesLoader.js +1 -1
- package/src/primitives/geometry.js +1 -1
- package/src/primitives/glyph.js +18 -4
- package/src/primitives/glyphset.js +468 -38
- package/src/primitives/lines.js +1 -1
- package/src/primitives/lod.js +7 -0
- package/src/primitives/pointset.js +13 -22
- package/src/primitives/texturePrimitive.js +12 -0
- package/src/primitives/textureSlides.js +8 -1
- package/src/primitives/zincObject.js +4 -0
- package/src/region.js +16 -2
- package/src/renderer.js +25 -6
- package/src/scene.js +27 -3
- package/src/sceneExporter.js +94 -12
- package/src/sceneLoader.js +58 -1
- package/src/texture/texture.js +10 -0
- package/src/texture/textureArray.js +9 -0
- package/src/tsl/glyphRenderMaterial.js +53 -0
- package/src/tsl/glyphTransform.js +306 -0
- package/src/{tls → tsl}/morphColorMaterial.js +4 -14
- package/src/{tls → tsl}/textureSlides.js +4 -1
- package/vite.config.js +1 -0
- package/src/three/GLTFExporter.js +0 -2501
- /package/src/{tls → tsl}/pointsMaterial.js +0 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
|
+
import {
|
|
3
|
+
Fn,
|
|
4
|
+
If,
|
|
5
|
+
attributeArray,
|
|
6
|
+
instanceIndex,
|
|
7
|
+
int,
|
|
8
|
+
float,
|
|
9
|
+
vec3,
|
|
10
|
+
uniform,
|
|
11
|
+
mix,
|
|
12
|
+
select,
|
|
13
|
+
max,
|
|
14
|
+
} from 'three/tsl';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Mirrors the string repeat_mode values used throughout glyphset.js as small
|
|
18
|
+
* integers, since TSL uniforms/comparisons work with numeric types.
|
|
19
|
+
*/
|
|
20
|
+
const REPEAT_MODE = { NONE: 0, MIRROR: 1, AXES_2D: 2, AXES_3D: 3 };
|
|
21
|
+
|
|
22
|
+
const repeatModeToInt = (repeat_mode) => {
|
|
23
|
+
switch (repeat_mode) {
|
|
24
|
+
case "MIRROR": return REPEAT_MODE.MIRROR;
|
|
25
|
+
case "AXES_2D": return REPEAT_MODE.AXES_2D;
|
|
26
|
+
case "AXES_3D": return REPEAT_MODE.AXES_3D;
|
|
27
|
+
default: return REPEAT_MODE.NONE;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const multiplierForRepeatMode = (repeat_mode) => {
|
|
32
|
+
if (repeat_mode == "AXES_2D" || repeat_mode == "MIRROR") return 2;
|
|
33
|
+
if (repeat_mode == "AXES_3D") return 3;
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* GPU port of Glyphset's resolve_glyph_axes() + the per-frame keyframe
|
|
39
|
+
* interpolation from updateMorphGlyphsets(). This is only used for the
|
|
40
|
+
* recurring, per-frame time-varying animation path - the one-time,
|
|
41
|
+
* load-time glyph transform/colour computation still runs on the CPU (see
|
|
42
|
+
* glyphset.js).
|
|
43
|
+
*
|
|
44
|
+
* baseSize/offset/scaleFactors/globalScale/repeat_mode are fixed for the
|
|
45
|
+
* lifetime of a glyphset, so they're baked in as uniforms once here rather
|
|
46
|
+
* than re-passed on every dispatch; bottomFrame/topFrame/proportion are the
|
|
47
|
+
* only per-frame-changing uniforms (see uniforms.bottomFrame etc. on the
|
|
48
|
+
* returned object).
|
|
49
|
+
*
|
|
50
|
+
* @param {Object} params
|
|
51
|
+
* @param {number} params.baseCount - number of raw (pre-repeat_mode-expansion)
|
|
52
|
+
* glyph records per keyframe (positions.length/3 for a single frame).
|
|
53
|
+
* @param {number} params.numberOfTimeSteps - number of keyframes.
|
|
54
|
+
* @param {number} params.outputCount - final instance count after
|
|
55
|
+
* repeat_mode expansion (glyphset.js's numberOfVertices).
|
|
56
|
+
* @param {string} params.repeat_mode - "NONE" | "MIRROR" | "AXES_2D" | "AXES_3D".
|
|
57
|
+
* @param {Float32Array} params.positionsData - flattened [time][record][xyz].
|
|
58
|
+
* @param {Float32Array} params.axis1Data
|
|
59
|
+
* @param {Float32Array} params.axis2Data
|
|
60
|
+
* @param {Float32Array} params.axis3Data
|
|
61
|
+
* @param {Float32Array} params.scaleData
|
|
62
|
+
* @param {Float32Array} [params.colorData] - flattened [time][record][rgb],
|
|
63
|
+
* omitted when the glyphset has no colours.
|
|
64
|
+
* @param {Array<number>} params.baseSize
|
|
65
|
+
* @param {Array<number>} params.offset
|
|
66
|
+
* @param {Array<number>} params.scaleFactors
|
|
67
|
+
* @returns {Object} { uniforms, compute, outputs } - update
|
|
68
|
+
* uniforms.bottomFrame/topFrame/proportion.value then pass `compute` to
|
|
69
|
+
* renderer.compute()/computeAsync(); read results back from
|
|
70
|
+
* outputs.position/axis1/axis2/axis3/color (each a StorageBufferNode -
|
|
71
|
+
* the raw attribute to read back is `outputs.position.value` etc).
|
|
72
|
+
*/
|
|
73
|
+
function createGlyphTransformCompute({
|
|
74
|
+
baseCount,
|
|
75
|
+
outputCount,
|
|
76
|
+
repeat_mode,
|
|
77
|
+
positionsData,
|
|
78
|
+
axis1Data,
|
|
79
|
+
axis2Data,
|
|
80
|
+
axis3Data,
|
|
81
|
+
scaleData,
|
|
82
|
+
colorData,
|
|
83
|
+
baseSize,
|
|
84
|
+
offset,
|
|
85
|
+
scaleFactors,
|
|
86
|
+
globalScale,
|
|
87
|
+
}) {
|
|
88
|
+
const multiplier = multiplierForRepeatMode(repeat_mode);
|
|
89
|
+
|
|
90
|
+
const positionsBuffer = attributeArray(positionsData, 'vec3');
|
|
91
|
+
const axis1Buffer = attributeArray(axis1Data, 'vec3');
|
|
92
|
+
const axis2Buffer = attributeArray(axis2Data, 'vec3');
|
|
93
|
+
const axis3Buffer = attributeArray(axis3Data, 'vec3');
|
|
94
|
+
const scaleBuffer = attributeArray(scaleData, 'vec3');
|
|
95
|
+
const colorBuffer = colorData ? attributeArray(colorData, 'vec3') : undefined;
|
|
96
|
+
|
|
97
|
+
const outPosition = attributeArray(outputCount, 'vec3');
|
|
98
|
+
const outAxis1 = attributeArray(outputCount, 'vec3');
|
|
99
|
+
const outAxis2 = attributeArray(outputCount, 'vec3');
|
|
100
|
+
const outAxis3 = attributeArray(outputCount, 'vec3');
|
|
101
|
+
const outColor = colorData ? attributeArray(outputCount, 'vec3') : undefined;
|
|
102
|
+
|
|
103
|
+
const uniforms = {
|
|
104
|
+
bottomFrame: uniform(0, 'int'),
|
|
105
|
+
topFrame: uniform(0, 'int'),
|
|
106
|
+
proportion: uniform(1),
|
|
107
|
+
repeatMode: uniform(repeatModeToInt(repeat_mode), 'int'),
|
|
108
|
+
baseSize: uniform(new THREE.Vector3(...baseSize)),
|
|
109
|
+
offset: uniform(new THREE.Vector3(...offset)),
|
|
110
|
+
scaleFactors: uniform(new THREE.Vector3(...scaleFactors)),
|
|
111
|
+
globalScale: uniform(globalScale),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const computeFn = Fn(() => {
|
|
115
|
+
|
|
116
|
+
const outIdx = int(instanceIndex);
|
|
117
|
+
const inputIdx = outIdx.div(int(multiplier));
|
|
118
|
+
const copyIdx = outIdx.mod(int(multiplier));
|
|
119
|
+
|
|
120
|
+
const bottomIdx = uniforms.bottomFrame.mul(int(baseCount)).add(inputIdx);
|
|
121
|
+
const topIdx = uniforms.topFrame.mul(int(baseCount)).add(inputIdx);
|
|
122
|
+
|
|
123
|
+
// Matches updateMorphGlyphsets(): bottom*proportion + top*(1-proportion).
|
|
124
|
+
const point = mix(positionsBuffer.element(topIdx), positionsBuffer.element(bottomIdx), uniforms.proportion);
|
|
125
|
+
const axis1 = mix(axis1Buffer.element(topIdx), axis1Buffer.element(bottomIdx), uniforms.proportion);
|
|
126
|
+
const axis2 = mix(axis2Buffer.element(topIdx), axis2Buffer.element(bottomIdx), uniforms.proportion);
|
|
127
|
+
const axis3 = mix(axis3Buffer.element(topIdx), axis3Buffer.element(bottomIdx), uniforms.proportion);
|
|
128
|
+
const scale = mix(scaleBuffer.element(topIdx), scaleBuffer.element(bottomIdx), uniforms.proportion);
|
|
129
|
+
|
|
130
|
+
// NOTE: each branch below assigns straight into the output storage
|
|
131
|
+
// buffer elements (outPosition.element(outIdx).assign(...) etc.),
|
|
132
|
+
// rather than into a shared vec3(0).toVar() declared before the
|
|
133
|
+
// If/Else and read back afterwards - that pattern (var declared
|
|
134
|
+
// outside an If().Else(), written in both branches, read after)
|
|
135
|
+
// reliably crashes this three.js version's WGSL codegen (verified via
|
|
136
|
+
// a native crash bisected down to exactly that shape in
|
|
137
|
+
// test/glyphTransformCompute.test.js's development). Writing directly
|
|
138
|
+
// to the output buffer inside each branch avoids it.
|
|
139
|
+
|
|
140
|
+
const isNoneOrMirror = uniforms.repeatMode.equal(int(REPEAT_MODE.NONE))
|
|
141
|
+
.or(uniforms.repeatMode.equal(int(REPEAT_MODE.MIRROR)));
|
|
142
|
+
|
|
143
|
+
If(isNoneOrMirror, () => {
|
|
144
|
+
|
|
145
|
+
// resolve_glyph_axes(): NONE / MIRROR branch.
|
|
146
|
+
const signVec = vec3(
|
|
147
|
+
select(scale.x.lessThan(0), float(-1), float(1)),
|
|
148
|
+
select(scale.y.lessThan(0), float(-1), float(1)),
|
|
149
|
+
select(scale.z.lessThan(0), float(-1), float(1)),
|
|
150
|
+
);
|
|
151
|
+
const axisScale = signVec.mul(uniforms.baseSize).add(scale.mul(uniforms.scaleFactors)).mul(uniforms.globalScale);
|
|
152
|
+
const baseAxis1 = axis1.mul(axisScale.x);
|
|
153
|
+
const baseAxis2 = axis2.mul(axisScale.y);
|
|
154
|
+
const baseAxis3 = axis3.mul(axisScale.z);
|
|
155
|
+
const basePoint = point
|
|
156
|
+
.add(baseAxis1.mul(uniforms.offset.x))
|
|
157
|
+
.add(baseAxis2.mul(uniforms.offset.y))
|
|
158
|
+
.add(baseAxis3.mul(uniforms.offset.z));
|
|
159
|
+
|
|
160
|
+
const isMirrorCopy = uniforms.repeatMode.equal(int(REPEAT_MODE.MIRROR)).and(copyIdx.equal(int(1)));
|
|
161
|
+
|
|
162
|
+
const a1 = select(isMirrorCopy, baseAxis1.negate(), baseAxis1).toVar();
|
|
163
|
+
const a2 = select(isMirrorCopy, baseAxis2.negate(), baseAxis2).toVar();
|
|
164
|
+
const a3 = select(isMirrorCopy, baseAxis3.negate(), baseAxis3).toVar();
|
|
165
|
+
const p = basePoint.toVar();
|
|
166
|
+
|
|
167
|
+
If(uniforms.repeatMode.equal(int(REPEAT_MODE.MIRROR)).and(scale.x.lessThan(0)), () => {
|
|
168
|
+
// shift glyph origin to end of axis1
|
|
169
|
+
p.subAssign(a1);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// reverse axis3 if required to maintain a right-handed coordinate system
|
|
173
|
+
const triple = a3.dot(a1.cross(a2));
|
|
174
|
+
If(triple.lessThan(0), () => {
|
|
175
|
+
a3.assign(a3.negate());
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
outPosition.element(outIdx).assign(p);
|
|
179
|
+
outAxis1.element(outIdx).assign(a1);
|
|
180
|
+
outAxis2.element(outIdx).assign(a2);
|
|
181
|
+
outAxis3.element(outIdx).assign(a3);
|
|
182
|
+
|
|
183
|
+
}).Else(() => {
|
|
184
|
+
|
|
185
|
+
// resolve_glyph_axes(): AXES_2D / AXES_3D branch.
|
|
186
|
+
const signVec = vec3(
|
|
187
|
+
select(scale.x.lessThan(0), float(-1), float(1)),
|
|
188
|
+
select(scale.y.lessThan(0), float(-1), float(1)),
|
|
189
|
+
select(scale.z.lessThan(0), float(-1), float(1)),
|
|
190
|
+
);
|
|
191
|
+
const axisScale = signVec.mul(uniforms.baseSize.x).add(scale.mul(uniforms.scaleFactors.x)).mul(uniforms.globalScale);
|
|
192
|
+
const finalPoint = point
|
|
193
|
+
.add(axis1.mul(axisScale.x).mul(uniforms.offset.x))
|
|
194
|
+
.add(axis2.mul(axisScale.y).mul(uniforms.offset.y))
|
|
195
|
+
.add(axis3.mul(axisScale.z).mul(uniforms.offset.z));
|
|
196
|
+
|
|
197
|
+
const useScale = select(copyIdx.equal(int(0)), scale.x,
|
|
198
|
+
select(copyIdx.equal(int(1)), scale.y, scale.z));
|
|
199
|
+
|
|
200
|
+
const isAxes2D = uniforms.repeatMode.equal(int(REPEAT_MODE.AXES_2D));
|
|
201
|
+
|
|
202
|
+
const useAxis1 = select(copyIdx.equal(int(0)), axis1,
|
|
203
|
+
select(copyIdx.equal(int(1)), axis2, axis3));
|
|
204
|
+
const useAxis2 = select(copyIdx.equal(int(0)), axis2,
|
|
205
|
+
select(copyIdx.equal(int(1)), select(isAxes2D, axis1, axis3), axis1));
|
|
206
|
+
|
|
207
|
+
const finalScale1 = uniforms.baseSize.x.add(useScale.mul(uniforms.scaleFactors.x)).mul(uniforms.globalScale);
|
|
208
|
+
const finalAxis1 = useAxis1.mul(finalScale1);
|
|
209
|
+
|
|
210
|
+
const axis3Raw = finalAxis1.cross(useAxis2);
|
|
211
|
+
const mag1 = axis3Raw.length();
|
|
212
|
+
let scaling1 = uniforms.baseSize.z.add(useScale.mul(uniforms.scaleFactors.z)).mul(uniforms.globalScale)
|
|
213
|
+
.div(max(mag1, 1e-8));
|
|
214
|
+
scaling1 = select(isAxes2D.and(copyIdx.greaterThan(int(0))), scaling1.mul(-1), scaling1);
|
|
215
|
+
const finalAxis3 = select(mag1.greaterThan(0), axis3Raw.mul(scaling1), axis3Raw);
|
|
216
|
+
|
|
217
|
+
const axis2Raw = finalAxis3.cross(finalAxis1);
|
|
218
|
+
const mag2 = axis2Raw.length();
|
|
219
|
+
const scaling2 = uniforms.baseSize.y.add(useScale.mul(uniforms.scaleFactors.y)).mul(uniforms.globalScale)
|
|
220
|
+
.div(max(mag2, 1e-8));
|
|
221
|
+
const finalAxis2 = select(mag2.greaterThan(0), axis2Raw.mul(scaling2), axis2Raw);
|
|
222
|
+
|
|
223
|
+
outPosition.element(outIdx).assign(finalPoint);
|
|
224
|
+
outAxis1.element(outIdx).assign(finalAxis1);
|
|
225
|
+
outAxis2.element(outIdx).assign(finalAxis2);
|
|
226
|
+
outAxis3.element(outIdx).assign(finalAxis3);
|
|
227
|
+
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (colorBuffer) {
|
|
231
|
+
const color = mix(colorBuffer.element(topIdx), colorBuffer.element(bottomIdx), uniforms.proportion);
|
|
232
|
+
outColor.element(outIdx).assign(color);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
} )().compute( outputCount );
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
uniforms,
|
|
239
|
+
compute: computeFn,
|
|
240
|
+
outputs: {
|
|
241
|
+
position: outPosition,
|
|
242
|
+
axis1: outAxis1,
|
|
243
|
+
axis2: outAxis2,
|
|
244
|
+
axis3: outAxis3,
|
|
245
|
+
color: outColor,
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Reads a glyph-transform compute pass's output buffers back to the CPU,
|
|
252
|
+
* without dispatching a new renderer.compute() call first - i.e. assumes
|
|
253
|
+
* the buffers already hold the desired result from a previous compute()
|
|
254
|
+
* dispatch (see dispatchAndReadbackGlyphTransform, or a bare
|
|
255
|
+
* renderer.compute(glyphCompute.compute) call). Split out from
|
|
256
|
+
* dispatchAndReadbackGlyphTransform so a caller that already dispatched
|
|
257
|
+
* recently (e.g. Glyphset's debounced accurate resync, which reuses the
|
|
258
|
+
* buffers its own immediately-preceding fast/no-readback dispatch just
|
|
259
|
+
* wrote) doesn't have to pay for - or risk - a second, redundant
|
|
260
|
+
* renderer.compute() call right on top of the first: back-to-back compute
|
|
261
|
+
* dispatches in close succession have been observed to reliably crash the
|
|
262
|
+
* (Node-only, test-time) WebGPU native backend.
|
|
263
|
+
*
|
|
264
|
+
* @param {THREE.WebGPURenderer} renderer
|
|
265
|
+
* @param {Object} glyphCompute - return value of createGlyphTransformCompute().
|
|
266
|
+
* @returns {Promise<Object>} { position, axis1, axis2, axis3, color } -
|
|
267
|
+
* plain Float32Arrays, one vec3 per output glyph instance (color only
|
|
268
|
+
* present when the glyphset has colours).
|
|
269
|
+
*/
|
|
270
|
+
async function readbackGlyphTransform(renderer, glyphCompute) {
|
|
271
|
+
const { position, axis1, axis2, axis3, color } = glyphCompute.outputs;
|
|
272
|
+
// Read sequentially rather than Promise.all-ing these - concurrent
|
|
273
|
+
// getArrayBufferAsync() calls against the same device have been observed
|
|
274
|
+
// to crash the (Node-only, test-time) WebGPU native backend; one at a
|
|
275
|
+
// time is the safe pattern here.
|
|
276
|
+
const positionResult = new Float32Array(await renderer.getArrayBufferAsync(position.value));
|
|
277
|
+
const axis1Result = new Float32Array(await renderer.getArrayBufferAsync(axis1.value));
|
|
278
|
+
const axis2Result = new Float32Array(await renderer.getArrayBufferAsync(axis2.value));
|
|
279
|
+
const axis3Result = new Float32Array(await renderer.getArrayBufferAsync(axis3.value));
|
|
280
|
+
const colorResult = color ? new Float32Array(await renderer.getArrayBufferAsync(color.value)) : undefined;
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
position: positionResult,
|
|
284
|
+
axis1: axis1Result,
|
|
285
|
+
axis2: axis2Result,
|
|
286
|
+
axis3: axis3Result,
|
|
287
|
+
color: colorResult,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Dispatches a glyph-transform compute pass built by
|
|
293
|
+
* createGlyphTransformCompute() and reads its output buffers back to the
|
|
294
|
+
* CPU. Update `glyphCompute.uniforms.bottomFrame/topFrame/proportion(/
|
|
295
|
+
* globalScale).value` before calling this.
|
|
296
|
+
*
|
|
297
|
+
* @param {THREE.WebGPURenderer} renderer
|
|
298
|
+
* @param {Object} glyphCompute - return value of createGlyphTransformCompute().
|
|
299
|
+
* @returns {Promise<Object>} see readbackGlyphTransform().
|
|
300
|
+
*/
|
|
301
|
+
async function dispatchAndReadbackGlyphTransform(renderer, glyphCompute) {
|
|
302
|
+
renderer.compute(glyphCompute.compute);
|
|
303
|
+
return readbackGlyphTransform(renderer, glyphCompute);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export { createGlyphTransformCompute, dispatchAndReadbackGlyphTransform, readbackGlyphTransform, REPEAT_MODE };
|
|
@@ -2,7 +2,9 @@ import * as THREE from 'three/webgpu';
|
|
|
2
2
|
import { Fn, attribute, materialColor, materialOpacity, mix, uniform, vec4 } from 'three/tsl';
|
|
3
3
|
|
|
4
4
|
//Maps a classic material's constructor name to its NodeMaterial
|
|
5
|
-
//equivalent, since only NodeMaterial exposes colorNode.
|
|
5
|
+
//equivalent, since only NodeMaterial exposes colorNode/positionNode.
|
|
6
|
+
//Exported for reuse anywhere else a classic material needs upgrading to a
|
|
7
|
+
//NodeMaterial to attach a custom node to (see glyphRenderMaterial.js).
|
|
6
8
|
const NODE_MATERIAL_CLASSES = {
|
|
7
9
|
MeshBasicMaterial: THREE.MeshBasicNodeMaterial,
|
|
8
10
|
MeshLambertMaterial: THREE.MeshLambertNodeMaterial,
|
|
@@ -16,15 +18,6 @@ const NODE_MATERIAL_CLASSES = {
|
|
|
16
18
|
* targets {@link updateMorphColorAttribute} (in utilities.js) keeps
|
|
17
19
|
* published as the 'morphColor0'/'morphColor1' geometry attributes -
|
|
18
20
|
* whichever two morph targets currently have non-zero influence.
|
|
19
|
-
*
|
|
20
|
-
* This replaces the legacy `material.onBeforeCompile = augmentMorphColor`
|
|
21
|
-
* approach, which patched raw GLSL into the classic WebGL shader and has no
|
|
22
|
-
* effect once a material is compiled through the WebGPU/TSL pipeline.
|
|
23
|
-
* three.js's own built-in WebGPU morph target system packs morph colour
|
|
24
|
-
* data into its morph texture (see three's Morph.js) but its blend loop
|
|
25
|
-
* only ever applies the result to position/normal, never colour, so this
|
|
26
|
-
* has to be done by hand.
|
|
27
|
-
*
|
|
28
21
|
* Converts `material` to its NodeMaterial equivalent first if it isn't one
|
|
29
22
|
* already, since only NodeMaterial exposes `colorNode`.
|
|
30
23
|
*
|
|
@@ -47,9 +40,6 @@ const applyMorphColorNode = (material) => {
|
|
|
47
40
|
|
|
48
41
|
const morphColorMix = uniform(0);
|
|
49
42
|
|
|
50
|
-
//materialColor already folds in material.color and, if present, .map -
|
|
51
|
-
//multiplying it by the blended per vertex morph colour keeps that
|
|
52
|
-
//compositing instead of replacing it outright.
|
|
53
43
|
target.colorNode = Fn(() => {
|
|
54
44
|
const colorA = attribute('morphColor0', 'vec3');
|
|
55
45
|
const colorB = attribute('morphColor1', 'vec3');
|
|
@@ -62,4 +52,4 @@ const applyMorphColorNode = (material) => {
|
|
|
62
52
|
return target;
|
|
63
53
|
};
|
|
64
54
|
|
|
65
|
-
export { applyMorphColorNode };
|
|
55
|
+
export { applyMorphColorNode, NODE_MATERIAL_CLASSES };
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
If,
|
|
12
12
|
varying,
|
|
13
13
|
float,
|
|
14
|
+
sRGBTransferEOTF,
|
|
14
15
|
} from 'three/tsl';
|
|
15
16
|
|
|
16
17
|
export function createWebGPUMaterial() {
|
|
@@ -111,7 +112,9 @@ placeholderTexture.needsUpdate = true;
|
|
|
111
112
|
// Contrast calculations
|
|
112
113
|
const contrastedColor = brightenedColor.sub(vec3(0.5)).mul(uniforms.contrast).add(vec3(0.5));
|
|
113
114
|
|
|
114
|
-
|
|
115
|
+
// WebGPURenderer always applies an sRGB OETF (linear -> sRGB) encode to
|
|
116
|
+
// the final composited frame, we are applying an sRGB -> linear here to cancel out the effect.
|
|
117
|
+
return vec4(sRGBTransferEOTF(contrastedColor), 1.0);
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
// Assign to NodeMaterial slots
|
package/vite.config.js
CHANGED
|
@@ -27,6 +27,7 @@ export default defineConfig({
|
|
|
27
27
|
'three/tsl': 'THREE',
|
|
28
28
|
'three/webgpu': 'THREE',
|
|
29
29
|
'three-spritetext': 'SpriteText',
|
|
30
|
+
'three/examples/jsm/exporters/GLTFExporter': 'GLTFExporter',
|
|
30
31
|
'three/examples/jsm/loaders/GLTFLoader': 'GLTFLoader',
|
|
31
32
|
'fflate': 'fflate'
|
|
32
33
|
}
|