@volter/blender-engine 0.1.90 → 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
|
}
|
|
@@ -363,23 +381,15 @@ ${compiled.uvs.map(n => `varying vec2 ${uvVarying(n)};`).join('\n')}`;
|
|
|
363
381
|
'#include <project_vertex>',
|
|
364
382
|
`vBlenderObjectPosition = transformed;
|
|
365
383
|
vBlenderObjectNormal = objectNormal;
|
|
366
|
-
|
|
367
|
-
#ifdef USE_INSTANCING
|
|
368
|
-
blenderWorldPosition = instanceMatrix * blenderWorldPosition;
|
|
369
|
-
#endif
|
|
384
|
+
mat4 blenderWorldMatrix = modelMatrix;
|
|
370
385
|
#ifdef USE_BATCHING
|
|
371
|
-
|
|
386
|
+
blenderWorldMatrix = blenderWorldMatrix * batchingMatrix;
|
|
372
387
|
#endif
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
// including the supported instance/batch normal transforms. Multiplying by
|
|
376
|
-
// transpose(view) removes that view transform without another matrix inverse.
|
|
377
|
-
// Our instance planners retain ordinary draws for shear/singular transforms.
|
|
378
|
-
vec3 blenderWorldNormal = transpose(mat3(viewMatrix)) * transformedNormal;
|
|
379
|
-
#ifdef FLIP_SIDED
|
|
380
|
-
blenderWorldNormal = -blenderWorldNormal;
|
|
388
|
+
#ifdef USE_INSTANCING
|
|
389
|
+
blenderWorldMatrix = blenderWorldMatrix * instanceMatrix;
|
|
381
390
|
#endif
|
|
382
|
-
|
|
391
|
+
vBlenderWorldPosition = (blenderWorldMatrix * vec4(transformed, 1.0)).xyz;
|
|
392
|
+
vBlenderWorldNormal = normalize(transpose(inverse(mat3(blenderWorldMatrix))) * objectNormal);
|
|
383
393
|
vBlenderOrco = blenderOrco;
|
|
384
394
|
${compiled.attributes.map(n => `${attributeVarying(n)} = ${graphAttributeName(n)};`).join('\n')}
|
|
385
395
|
${compiled.uvs.map(n => `${uvVarying(n)} = ${attribute(channels[n] ?? 0)};`).join('\n')}
|
|
@@ -109,7 +109,7 @@ export function applyPhysicalMaterial(material: THREE.MeshPhysicalMaterial, inpu
|
|
|
109
109
|
blenderWorldExtinction: {value: new THREE.Vector3()}};
|
|
110
110
|
uniforms.set(material, values);
|
|
111
111
|
const held = values;
|
|
112
|
-
material.customProgramCacheKey = () => `blender-principled-physical-
|
|
112
|
+
material.customProgramCacheKey = () => `blender-principled-physical-v5${graphProgramKey(material)}`;
|
|
113
113
|
material.onBeforeRender = (renderer, scene, camera, geometry, object) => {
|
|
114
114
|
bindNamedUvChannels(material, geometry);
|
|
115
115
|
bindGraphDraw(material, geometry, renderer, scene, camera, object, graphShadow);
|
|
@@ -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);
|