@volter/blender-engine 0.1.89 → 0.1.91
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.
|
@@ -207,6 +207,25 @@ function channelsFor(compiled: CompiledGraph, geometry: THREE.BufferGeometry): R
|
|
|
207
207
|
return channels;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
/** Compare the actual named-layer inputs without allocating and serializing
|
|
211
|
+
* two channel maps on every draw. Missing layers still get their zero buffer,
|
|
212
|
+
* including when this geometry first shares an already-bound material. */
|
|
213
|
+
function channelsMatch(compiled: CompiledGraph, channels: Record<string, number>, geometry: THREE.BufferGeometry): boolean {
|
|
214
|
+
const named = geometry.userData['blenderUvChannels'] as Record<string, number> | undefined;
|
|
215
|
+
const count = geometry.getAttribute('position')?.count ?? 0;
|
|
216
|
+
let same = Object.keys(channels).length === compiled.uvs.length;
|
|
217
|
+
for (const name of compiled.uvs) {
|
|
218
|
+
let channel = name === '' ? 0 : named?.[name];
|
|
219
|
+
if (channel === undefined) {
|
|
220
|
+
channel = 9;
|
|
221
|
+
if (geometry.getAttribute('uv9')?.count !== count)
|
|
222
|
+
geometry.setAttribute('uv9', new THREE.BufferAttribute(new Float32Array(count * 2), 2));
|
|
223
|
+
}
|
|
224
|
+
if (channels[name] !== channel) same = false;
|
|
225
|
+
}
|
|
226
|
+
return same;
|
|
227
|
+
}
|
|
228
|
+
|
|
210
229
|
/** Per draw: a pending program started compiling (see `Pending`), a compiled
|
|
211
230
|
* one swapped in, a refused one dropped, and the channel of each named layer
|
|
212
231
|
* on this geometry. `shadowOf` makes the proxy a program compiles through:
|
|
@@ -261,9 +280,8 @@ export function bindGraphDraw(material: THREE.MeshPhysicalMaterial, geometry: TH
|
|
|
261
280
|
`so it is drawn with its constant values. ${first}`);
|
|
262
281
|
return;
|
|
263
282
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
binding.channels = channels;
|
|
283
|
+
if (!channelsMatch(binding.compiled, binding.channels, geometry)) {
|
|
284
|
+
binding.channels = channelsFor(binding.compiled, geometry);
|
|
267
285
|
material.needsUpdate = true;
|
|
268
286
|
}
|
|
269
287
|
}
|
|
@@ -281,6 +281,7 @@ export class BlenderTransparentInstances {
|
|
|
281
281
|
for (const n of this.projection.elements) this.observe(n);
|
|
282
282
|
for (const n of this.root.matrixWorld.elements) this.observe(n);
|
|
283
283
|
const observedGeometry = new Set<THREE.BufferGeometry>();
|
|
284
|
+
const observedMaterials = new Set<THREE.Material>();
|
|
284
285
|
for (const mesh of this.objects) {
|
|
285
286
|
// Check eligibility every frame, including opaque -> transparent
|
|
286
287
|
// transitions, but opaque geometry/attribute versions cannot affect a
|
|
@@ -323,17 +324,23 @@ export class BlenderTransparentInstances {
|
|
|
323
324
|
this.observe(sphere?.center.z ?? 0); this.observe(sphere?.radius ?? -1);
|
|
324
325
|
const materials = Array.isArray(mesh.material) ? mesh.material : null;
|
|
325
326
|
this.observe(materials?.length ?? -1);
|
|
326
|
-
if (materials) for (const material of materials) this.observeMaterial(material);
|
|
327
|
-
else this.observeMaterial(mesh.material as THREE.Material);
|
|
327
|
+
if (materials) for (const material of materials) this.observeMaterial(material, observedMaterials);
|
|
328
|
+
else this.observeMaterial(mesh.material as THREE.Material, observedMaterials);
|
|
328
329
|
}
|
|
329
330
|
this.stateChanged ||= this.planState.length !== this.stateIndex;
|
|
330
331
|
this.planState.length = this.stateIndex;
|
|
331
332
|
return this.stateChanged;
|
|
332
333
|
}
|
|
333
334
|
|
|
334
|
-
private observeMaterial(material: THREE.Material): void {
|
|
335
|
+
private observeMaterial(material: THREE.Material, observed: Set<THREE.Material>): void {
|
|
336
|
+
// Every slot still observes its identity. Shared state needs one exact
|
|
337
|
+
// census per material, rather than thousands of identical hook/value
|
|
338
|
+
// comparisons for repeated foliage using the same material.
|
|
339
|
+
this.observe(material.uuid);
|
|
340
|
+
if (observed.has(material)) return;
|
|
341
|
+
observed.add(material);
|
|
335
342
|
this.observe(materialDrawHooksSupported(material) ? 1 : 0);
|
|
336
|
-
this.observe(material.
|
|
343
|
+
this.observe(material.version);
|
|
337
344
|
this.observe(material.visible ? 1 : 0); this.observe(material.transparent ? 1 : 0);
|
|
338
345
|
this.observe(material.side); this.observe(material.forceSinglePass ? 1 : 0);
|
|
339
346
|
this.observe((material as THREE.MeshPhysicalMaterial).transmission ?? 0);
|