@volter/blender-engine 0.1.83 → 0.1.85
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.
|
@@ -120,6 +120,11 @@ export class BlenderOrderedBatches {
|
|
|
120
120
|
draw = new THREE.BatchedMesh(1, 0, 0, family.material);
|
|
121
121
|
draw.dispose();
|
|
122
122
|
draw.copy(template);
|
|
123
|
+
// Three r180's program invalidation reads colorTexture, whereas its
|
|
124
|
+
// program parameters read _colorsTexture. These owned draws never use
|
|
125
|
+
// per-instance colors: expose that same null state to both checks so
|
|
126
|
+
// every draw does not rebuild the already-correct program parameters.
|
|
127
|
+
Object.defineProperty(draw, 'colorTexture', {value: null});
|
|
123
128
|
for (const name of Object.keys(template.geometry.attributes))
|
|
124
129
|
draw.geometry.setAttribute(name, template.geometry.getAttribute(name));
|
|
125
130
|
draw.geometry.setIndex(template.geometry.index);
|
|
@@ -28,6 +28,16 @@ const uniforms = new WeakMap<THREE.MeshPhysicalMaterial, {
|
|
|
28
28
|
blenderMapClip: {value: boolean}; blenderRoughnessClip: {value: boolean}; blenderNormalClip: {value: boolean};
|
|
29
29
|
blenderWorldExtinction: {value: THREE.Vector3};
|
|
30
30
|
}>();
|
|
31
|
+
const drawHooks = new WeakMap<THREE.Material, Pick<THREE.Material, 'onBeforeRender' | 'onBeforeCompile' | 'customProgramCacheKey'>>();
|
|
32
|
+
|
|
33
|
+
/** Internal draws can preserve the engine's known hooks or Three's defaults.
|
|
34
|
+
* A later custom hook may depend on the original object/material identity. */
|
|
35
|
+
export function materialDrawHooksSupported(material: THREE.Material): boolean {
|
|
36
|
+
const hooks = drawHooks.get(material) ?? THREE.Material.prototype;
|
|
37
|
+
return material.onBeforeRender === hooks.onBeforeRender &&
|
|
38
|
+
material.onBeforeCompile === hooks.onBeforeCompile &&
|
|
39
|
+
material.customProgramCacheKey === hooks.customProgramCacheKey;
|
|
40
|
+
}
|
|
31
41
|
|
|
32
42
|
export function applyWorldExtinction(material: THREE.MeshPhysicalMaterial, extinction: THREE.Vector3): void {
|
|
33
43
|
if (!uniforms.has(material)) applyPhysicalMaterial(material);
|
|
@@ -59,7 +69,7 @@ function graphShadow(material: THREE.MeshPhysicalMaterial): THREE.MeshPhysicalMa
|
|
|
59
69
|
/** Copy physical values into an independently cached draw form. Textures and
|
|
60
70
|
* graph uniform values remain borrowed from the authoritative source material. */
|
|
61
71
|
export function syncPhysicalDrawMaterial(source: THREE.Material, target?: THREE.MeshPhysicalMaterial): THREE.MeshPhysicalMaterial | null {
|
|
62
|
-
if (!(source instanceof THREE.MeshPhysicalMaterial) || !uniforms.has(source)) return null;
|
|
72
|
+
if (!(source instanceof THREE.MeshPhysicalMaterial) || !uniforms.has(source) || !materialDrawHooksSupported(source)) return null;
|
|
63
73
|
const copy = target ?? graphShadow(source);
|
|
64
74
|
if (!borrowGraphDrawBinding(source, copy)) {
|
|
65
75
|
if (!target) copy.dispose();
|
|
@@ -180,6 +190,8 @@ export function applyPhysicalMaterial(material: THREE.MeshPhysicalMaterial, inpu
|
|
|
180
190
|
// surface inputs it carries (`blender-graph-material.ts`).
|
|
181
191
|
applyGraphShader(material, shader);
|
|
182
192
|
};
|
|
193
|
+
drawHooks.set(material, {onBeforeRender: material.onBeforeRender,
|
|
194
|
+
onBeforeCompile: material.onBeforeCompile, customProgramCacheKey: material.customProgramCacheKey});
|
|
183
195
|
material.needsUpdate = true;
|
|
184
196
|
}
|
|
185
197
|
values.blenderCoatIor.value = Math.max(1, data.coat_ior);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { graphDrawAttributes } from './blender-graph-material';
|
|
3
|
+
import { materialDrawHooksSupported } from './blender-physical-material';
|
|
3
4
|
|
|
4
5
|
// Small spatial batches retain frustum rejection without duplicating geometry.
|
|
5
6
|
const BATCH_SIZE = 64;
|
|
@@ -12,6 +13,11 @@ function sameMaterials(a: THREE.Material | THREE.Material[], b: THREE.Material |
|
|
|
12
13
|
: a === b;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
export function instanceObjectHooksSupported(object: THREE.Object3D): boolean {
|
|
17
|
+
return object.onBeforeRender === THREE.Object3D.prototype.onBeforeRender &&
|
|
18
|
+
object.onAfterRender === THREE.Object3D.prototype.onAfterRender;
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
export function instanceObjectShown(object: THREE.Object3D): boolean {
|
|
16
22
|
for (let node: THREE.Object3D | null = object; node; node = node.parent)
|
|
17
23
|
if (!node.visible) return false;
|
|
@@ -60,12 +66,13 @@ export class BlenderRuntimeInstances {
|
|
|
60
66
|
for (const object of objects) {
|
|
61
67
|
const mesh = object as THREE.Mesh;
|
|
62
68
|
if (!mesh.isMesh) continue;
|
|
69
|
+
if (!instanceObjectHooksSupported(mesh)) { exclude('customHooks'); continue; }
|
|
63
70
|
if ((mesh as THREE.SkinnedMesh).isSkinnedMesh ||
|
|
64
71
|
(mesh as THREE.InstancedMesh).isInstancedMesh || mesh.morphTargetInfluences ||
|
|
65
72
|
mesh.layers.mask !== 1) { exclude('deformationOrLayers'); continue; }
|
|
66
73
|
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
67
74
|
if (materials.some(m => m.transparent || (m as THREE.MeshPhysicalMaterial).transmission > 0 ||
|
|
68
|
-
(m as THREE.ShaderMaterial).isShaderMaterial)) { exclude('material'); continue; }
|
|
75
|
+
(m as THREE.ShaderMaterial).isShaderMaterial || !materialDrawHooksSupported(m))) { exclude('material'); continue; }
|
|
69
76
|
// Four slots for instanceMatrix, at most twelve for each actual program.
|
|
70
77
|
// Count active inputs, NOT every stored authored layer: retaining unused
|
|
71
78
|
// UVs/colours must not disable batching. No channel is deleted to fit.
|
|
@@ -125,6 +132,8 @@ export class BlenderRuntimeInstances {
|
|
|
125
132
|
if (!this.batches.length) return;
|
|
126
133
|
this.inverse.copy(this.root.matrixWorld).invert();
|
|
127
134
|
for (const {draw, members} of this.batches) {
|
|
135
|
+
const materials = Array.isArray(draw.material) ? draw.material : [draw.material];
|
|
136
|
+
const supportedHooks = materials.every(materialDrawHooksSupported);
|
|
128
137
|
let count = 0;
|
|
129
138
|
let changed = false;
|
|
130
139
|
for (const member of members) {
|
|
@@ -133,6 +142,7 @@ export class BlenderRuntimeInstances {
|
|
|
133
142
|
// A drag can introduce negative scale/shear, or a skin can replace a
|
|
134
143
|
// mesh between frames. Fall back immediately without touching its data.
|
|
135
144
|
const compatible = mesh.parent !== null && mesh.geometry === draw.geometry &&
|
|
145
|
+
supportedHooks && instanceObjectHooksSupported(mesh) &&
|
|
136
146
|
sameMaterials(mesh.material, draw.material) && instanceMatrixSupported(this.matrix);
|
|
137
147
|
if (!compatible) {
|
|
138
148
|
mesh.layers.mask |= member.layers;
|
|
@@ -3,7 +3,8 @@ import {BlenderOrderedBatches, ORDERED_BATCH_CAPACITY} from './blender-ordered-b
|
|
|
3
3
|
import {BlenderDrawMaterials} from './blender-draw-materials';
|
|
4
4
|
import {presenterChanged} from './blender-presenter-change';
|
|
5
5
|
import {graphDrawAttributes} from './blender-graph-material';
|
|
6
|
-
import {
|
|
6
|
+
import {materialDrawHooksSupported} from './blender-physical-material';
|
|
7
|
+
import {instanceMatrixSupported, instanceObjectShown, instanceObjectHooksSupported} from './blender-runtime-instances';
|
|
7
8
|
|
|
8
9
|
const CAPACITY = ORDERED_BATCH_CAPACITY;
|
|
9
10
|
type Entry = {mesh: THREE.Mesh; material: THREE.Material | null; key: string | null; batchKey: string | null; groupOrder: number; z: number; centre: THREE.Vector3};
|
|
@@ -112,6 +113,7 @@ export class BlenderTransparentInstances {
|
|
|
112
113
|
const candidate = materials.length === 1 ? materials[0]! : null;
|
|
113
114
|
const order = groupOrder(mesh);
|
|
114
115
|
if (candidate && candidate.visible && candidate.transparent &&
|
|
116
|
+
materialDrawHooksSupported(candidate) && instanceObjectHooksSupported(mesh) &&
|
|
115
117
|
!(candidate as THREE.ShaderMaterial).isShaderMaterial &&
|
|
116
118
|
!((candidate as THREE.MeshPhysicalMaterial).transmission > 0) &&
|
|
117
119
|
(candidate.side !== THREE.DoubleSide || candidate.forceSinglePass) &&
|
|
@@ -291,6 +293,7 @@ export class BlenderTransparentInstances {
|
|
|
291
293
|
this.observe(mesh.renderOrder);
|
|
292
294
|
this.observe(groupOrder(mesh));
|
|
293
295
|
this.observe(mesh.frustumCulled ? 1 : 0);
|
|
296
|
+
this.observe(instanceObjectHooksSupported(mesh) ? 1 : 0);
|
|
294
297
|
this.observe(mesh.morphTargetInfluences ? 1 : 0);
|
|
295
298
|
for (const n of mesh.matrixWorld.elements) this.observe(n);
|
|
296
299
|
const geometry = mesh.geometry;
|
|
@@ -329,6 +332,7 @@ export class BlenderTransparentInstances {
|
|
|
329
332
|
}
|
|
330
333
|
|
|
331
334
|
private observeMaterial(material: THREE.Material): void {
|
|
335
|
+
this.observe(materialDrawHooksSupported(material) ? 1 : 0);
|
|
332
336
|
this.observe(material.uuid); this.observe(material.version);
|
|
333
337
|
this.observe(material.visible ? 1 : 0); this.observe(material.transparent ? 1 : 0);
|
|
334
338
|
this.observe(material.side); this.observe(material.forceSinglePass ? 1 : 0);
|