@woosh/meep-engine 2.35.1 → 2.35.2
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/core/bvh2/aabb3/aabb3_intersects_frustum_degree.js +6 -6
- package/core/bvh2/traversal/queryBinaryNode_CollectData.js +1 -2
- package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +30 -17
- package/core/collection/HashMap.js +1 -1
- package/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.js +13 -4
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +20 -119
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +9 -7
- package/engine/graphics/ecs/mesh-v2/build_three_object.js +39 -0
- package/engine/graphics/ecs/mesh-v2/render/GenericRendererAdapter.js +1 -1
- package/engine/graphics/ecs/mesh-v2/render/InstancedRendererAdapter.js +54 -6
- package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +14 -5
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +11 -2
- package/engine/graphics/micron/render/v1/VGThreeRenderer.js +5 -4
- package/package.json +1 -1
|
@@ -19,18 +19,18 @@ export function aabb3_intersects_frustum_degree(
|
|
|
19
19
|
frustum
|
|
20
20
|
) {
|
|
21
21
|
|
|
22
|
-
let i = 0;
|
|
23
22
|
let result = 2;
|
|
23
|
+
let i = 0;
|
|
24
24
|
|
|
25
25
|
for (; i < 24; i += 4) {
|
|
26
26
|
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
27
|
+
const p_x = frustum[i];
|
|
28
|
+
const p_y = frustum[i + 1];
|
|
29
|
+
const p_z = frustum[i + 2];
|
|
30
|
+
const p_w = frustum[i + 3];
|
|
31
31
|
|
|
32
32
|
const plane_side = computeAABB3PlaneSide(
|
|
33
|
-
|
|
33
|
+
p_x, p_y, p_z, p_w,
|
|
34
34
|
x0, y0, z0, x1, y1, z1
|
|
35
35
|
);
|
|
36
36
|
|
|
@@ -13,13 +13,12 @@ let stackPointer = 0;
|
|
|
13
13
|
*/
|
|
14
14
|
export function queryBinaryNode_CollectData(destination, destinationOffset, root) {
|
|
15
15
|
let n;
|
|
16
|
+
let i = 0;
|
|
16
17
|
|
|
17
18
|
const stackOffset = stackPointer;
|
|
18
19
|
|
|
19
20
|
stack[stackPointer++] = root;
|
|
20
21
|
|
|
21
|
-
let i = 0;
|
|
22
|
-
|
|
23
22
|
while (stackPointer-- > stackOffset) {
|
|
24
23
|
|
|
25
24
|
n = stack[stackPointer];
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { aabb3_intersects_frustum_degree } from "../aabb3/aabb3_intersects_frustum_degree.js";
|
|
2
|
+
import { queryBinaryNode_CollectData } from "./queryBinaryNode_CollectData.js";
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
*
|
|
3
6
|
* @type {(BinaryNode|LeafNode)[]}
|
|
@@ -30,32 +33,42 @@ export function queryBinaryNode_FrustumIntersections_Data(destination, destinati
|
|
|
30
33
|
|
|
31
34
|
n = stack[stackPointer];
|
|
32
35
|
|
|
33
|
-
const
|
|
36
|
+
const intersection_degree = aabb3_intersects_frustum_degree(
|
|
37
|
+
n.x0, n.y0, n.z0,
|
|
38
|
+
n.x1, n.y1, n.z1,
|
|
39
|
+
frustum
|
|
40
|
+
);
|
|
34
41
|
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
}
|
|
42
|
+
if (intersection_degree === 2) {
|
|
43
|
+
// fully inside
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
offset += queryBinaryNode_CollectData(destination, offset, n);
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
} else if (intersection_degree === 1) {
|
|
48
|
+
// partly inside
|
|
42
49
|
|
|
43
|
-
if (
|
|
44
|
-
stack[stackPointer++] = right;
|
|
45
|
-
}
|
|
50
|
+
if (n.isBinaryNode === true) {
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
const right = n.right;
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
if (right !== null) {
|
|
55
|
+
stack[stackPointer++] = right;
|
|
56
|
+
}
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
// leaf node
|
|
58
|
+
const left = n.left;
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
if (left !== null) {
|
|
61
|
+
stack[stackPointer++] = left;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
} else {
|
|
65
|
+
// leaf node
|
|
66
|
+
|
|
67
|
+
destination[offset] = n.object;
|
|
68
|
+
|
|
69
|
+
offset++;
|
|
70
|
+
}
|
|
57
71
|
|
|
58
|
-
offset++;
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
}
|
|
@@ -3,6 +3,7 @@ import { HighlightRenderElementSource } from "../plugin/HighlightRenderElementSo
|
|
|
3
3
|
import Highlight from "../Highlight.js";
|
|
4
4
|
import { OutlineRenderPlugin } from "../plugin/OutlineRenderPlugin.js";
|
|
5
5
|
import { ShadedGeometry } from "../../mesh-v2/ShadedGeometry.js";
|
|
6
|
+
import { build_three_object } from "../../mesh-v2/build_three_object.js";
|
|
6
7
|
|
|
7
8
|
class Supplier extends HighlightRenderElementSource {
|
|
8
9
|
/**
|
|
@@ -31,6 +32,13 @@ class Supplier extends HighlightRenderElementSource {
|
|
|
31
32
|
* @private
|
|
32
33
|
*/
|
|
33
34
|
this.__group = null;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @type {WeakMap<ShadedGeometry, THREE.Object3D>}
|
|
39
|
+
* @private
|
|
40
|
+
*/
|
|
41
|
+
this.__object_cache = new WeakMap();
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
collect(pool, group) {
|
|
@@ -77,13 +85,14 @@ class Supplier extends HighlightRenderElementSource {
|
|
|
77
85
|
return;
|
|
78
86
|
}
|
|
79
87
|
|
|
80
|
-
|
|
88
|
+
let object = this.__object_cache.get(sg);
|
|
81
89
|
|
|
82
|
-
if
|
|
83
|
-
|
|
84
|
-
return;
|
|
90
|
+
if(object === undefined){
|
|
91
|
+
object = build_three_object(sg);
|
|
85
92
|
}
|
|
86
93
|
|
|
94
|
+
object.matrixWorld.elements = sg.transform;
|
|
95
|
+
|
|
87
96
|
const renderElement = this.__pool.create();
|
|
88
97
|
|
|
89
98
|
renderElement.definitions = elements.asArray();
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Line, LineSegments, Mesh } from "three";
|
|
2
1
|
import { updateNodeByMatrix4AndBBB } from "../mesh/updateNodeByTransformAndBBB.js";
|
|
3
2
|
import { LeafNode } from "../../../../core/bvh2/LeafNode.js";
|
|
4
3
|
import { AABB3 } from "../../../../core/bvh2/aabb3/AABB3.js";
|
|
5
4
|
import { DrawMode } from "./DrawMode.js";
|
|
6
|
-
import { applyTransformToThreeObject } from "../mesh/applyTransformToThreeObject.js";
|
|
7
5
|
import { ShadedGeometryFlags } from "./ShadedGeometryFlags.js";
|
|
8
6
|
|
|
9
7
|
const _aabb3 = new AABB3();
|
|
@@ -12,42 +10,6 @@ const DEFAULT_FLAGS = ShadedGeometryFlags.CastShadow
|
|
|
12
10
|
| ShadedGeometryFlags.ReceiveShadow
|
|
13
11
|
;
|
|
14
12
|
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
* @param {ShadedGeometry} sg
|
|
18
|
-
* @returns {THREE.Object3D}
|
|
19
|
-
*/
|
|
20
|
-
export function build_three_object(sg) {
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @type {THREE.Object3D}
|
|
24
|
-
*/
|
|
25
|
-
let object;
|
|
26
|
-
|
|
27
|
-
const mode = sg.mode;
|
|
28
|
-
const shader = sg.material;
|
|
29
|
-
const geo = sg.geometry;
|
|
30
|
-
|
|
31
|
-
if (mode === DrawMode.Triangles) {
|
|
32
|
-
object = new Mesh(geo, shader);
|
|
33
|
-
} else if (mode === DrawMode.Lines) {
|
|
34
|
-
object = new Line(geo, shader);
|
|
35
|
-
} else if (mode === DrawMode.LineSegments) {
|
|
36
|
-
object = new LineSegments(geo, shader);
|
|
37
|
-
} else {
|
|
38
|
-
throw new Error(`Unsupported draw mode '${mode}'`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
object.matrixAutoUpdate = false;
|
|
42
|
-
object.frustumCulled = false;
|
|
43
|
-
object.matrixWorldNeedsUpdate = false;
|
|
44
|
-
|
|
45
|
-
object.castShadow = sg.getFlag(ShadedGeometryFlags.CastShadow);
|
|
46
|
-
object.receiveShadow = sg.getFlag(ShadedGeometryFlags.ReceiveShadow);
|
|
47
|
-
|
|
48
|
-
return object;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
13
|
export class ShadedGeometry {
|
|
52
14
|
constructor() {
|
|
53
15
|
/**
|
|
@@ -67,13 +29,6 @@ export class ShadedGeometry {
|
|
|
67
29
|
*/
|
|
68
30
|
this.mode = DrawMode.Triangles;
|
|
69
31
|
|
|
70
|
-
/**
|
|
71
|
-
*
|
|
72
|
-
* @type {THREE.Object3D|null}
|
|
73
|
-
* @private
|
|
74
|
-
*/
|
|
75
|
-
this.__cached_object = null;
|
|
76
|
-
|
|
77
32
|
/**
|
|
78
33
|
*
|
|
79
34
|
* @type {LeafNode<ShadedGeometry>}
|
|
@@ -88,13 +43,20 @@ export class ShadedGeometry {
|
|
|
88
43
|
*/
|
|
89
44
|
this.__entity = -1;
|
|
90
45
|
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @type {Transform|null}
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
this.__c_transform = null;
|
|
52
|
+
|
|
91
53
|
/**
|
|
92
54
|
* Transform matrix
|
|
93
55
|
* Transient, assigned in the system
|
|
94
56
|
* @type {number[]|null}
|
|
95
57
|
* @private
|
|
96
58
|
*/
|
|
97
|
-
this.__transform =
|
|
59
|
+
this.__transform = new Float32Array(16);
|
|
98
60
|
|
|
99
61
|
/**
|
|
100
62
|
* Transient property signifying how to render object
|
|
@@ -109,6 +71,14 @@ export class ShadedGeometry {
|
|
|
109
71
|
this.flags = DEFAULT_FLAGS;
|
|
110
72
|
}
|
|
111
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @deprecated
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
get __cached_object(){
|
|
79
|
+
throw new Error('Deprecated');
|
|
80
|
+
}
|
|
81
|
+
|
|
112
82
|
/**
|
|
113
83
|
*
|
|
114
84
|
* @param {number|ShadedGeometryFlags} flag
|
|
@@ -182,17 +152,7 @@ export class ShadedGeometry {
|
|
|
182
152
|
* @return {null|number[]}
|
|
183
153
|
*/
|
|
184
154
|
get transform() {
|
|
185
|
-
|
|
186
|
-
return this.__transform;
|
|
187
|
-
} else if (this.__cached_object !== null) {
|
|
188
|
-
return this.__cached_object.matrix.elements;
|
|
189
|
-
} else {
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
__build_object() {
|
|
195
|
-
this.__cached_object = build_three_object(this);
|
|
155
|
+
return this.__transform;
|
|
196
156
|
}
|
|
197
157
|
|
|
198
158
|
get bvh() {
|
|
@@ -214,13 +174,6 @@ export class ShadedGeometry {
|
|
|
214
174
|
if (geometry.boundingBox === null) {
|
|
215
175
|
geometry.computeBoundingBox();
|
|
216
176
|
}
|
|
217
|
-
|
|
218
|
-
if (this.__cached_object === null) {
|
|
219
|
-
this.__build_object();
|
|
220
|
-
} else {
|
|
221
|
-
this.__cached_object.material = material;
|
|
222
|
-
this.__cached_object.geometry = geometry;
|
|
223
|
-
}
|
|
224
177
|
}
|
|
225
178
|
|
|
226
179
|
/**
|
|
@@ -239,11 +192,8 @@ export class ShadedGeometry {
|
|
|
239
192
|
}
|
|
240
193
|
|
|
241
194
|
updateTransform() {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
// update matrix
|
|
245
|
-
object_3d.updateMatrix();
|
|
246
|
-
object_3d.updateMatrixWorld();
|
|
195
|
+
//
|
|
196
|
+
this.__c_transform.toMatrix4(this.__transform);
|
|
247
197
|
|
|
248
198
|
// update bounds
|
|
249
199
|
const gbb = this.geometry.boundingBox;
|
|
@@ -260,56 +210,7 @@ export class ShadedGeometry {
|
|
|
260
210
|
max.z
|
|
261
211
|
);
|
|
262
212
|
|
|
263
|
-
updateNodeByMatrix4AndBBB(this.__bvh_leaf, _aabb3,
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
*
|
|
268
|
-
* @param {number} x
|
|
269
|
-
* @param {number} y
|
|
270
|
-
* @param {number} z
|
|
271
|
-
*/
|
|
272
|
-
setPositionByComponents(x, y, z) {
|
|
273
|
-
|
|
274
|
-
this.__cached_object.position.set(x, y, z);
|
|
275
|
-
|
|
276
|
-
this.updateTransform();
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
*
|
|
281
|
-
* @param {number} x
|
|
282
|
-
* @param {number} y
|
|
283
|
-
* @param {number} z
|
|
284
|
-
* @param {number} w
|
|
285
|
-
*/
|
|
286
|
-
setRotationByComponents(x, y, z, w) {
|
|
287
|
-
|
|
288
|
-
this.__cached_object.quaternion.set(x, y, z, w);
|
|
289
|
-
|
|
290
|
-
this.updateTransform();
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
*
|
|
295
|
-
* @param {number} x
|
|
296
|
-
* @param {number} y
|
|
297
|
-
* @param {number} z
|
|
298
|
-
*/
|
|
299
|
-
setScaleByComponents(x, y, z) {
|
|
300
|
-
this.__cached_object.scale.set(x, y, z);
|
|
301
|
-
|
|
302
|
-
this.updateTransform();
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
*
|
|
307
|
-
* @param {Transform} t
|
|
308
|
-
*/
|
|
309
|
-
applyTransform(t) {
|
|
310
|
-
applyTransformToThreeObject(this.__cached_object, t);
|
|
311
|
-
|
|
312
|
-
this.updateTransform();
|
|
213
|
+
updateNodeByMatrix4AndBBB(this.__bvh_leaf, _aabb3, this.__transform);
|
|
313
214
|
}
|
|
314
215
|
}
|
|
315
216
|
|
|
@@ -133,11 +133,13 @@ export class ShadedGeometrySystem extends System {
|
|
|
133
133
|
* @param {number} entity
|
|
134
134
|
*/
|
|
135
135
|
link(sg, t, entity) {
|
|
136
|
-
|
|
137
|
-
t.rotation.onChanged.add(sg.setRotationByComponents, sg);
|
|
138
|
-
t.scale.onChanged.add(sg.setScaleByComponents, sg);
|
|
136
|
+
sg.__c_transform = t;
|
|
139
137
|
|
|
140
|
-
sg.
|
|
138
|
+
t.position.onChanged.add(sg.updateTransform, sg);
|
|
139
|
+
t.rotation.onChanged.add(sg.updateTransform, sg);
|
|
140
|
+
t.scale.onChanged.add(sg.updateTransform, sg);
|
|
141
|
+
|
|
142
|
+
sg.updateTransform();
|
|
141
143
|
|
|
142
144
|
const leaf_node = sg.bvh;
|
|
143
145
|
|
|
@@ -157,9 +159,9 @@ export class ShadedGeometrySystem extends System {
|
|
|
157
159
|
* @param {number} entity
|
|
158
160
|
*/
|
|
159
161
|
unlink(sg, t, entity) {
|
|
160
|
-
t.position.onChanged.remove(sg.
|
|
161
|
-
t.rotation.onChanged.remove(sg.
|
|
162
|
-
t.scale.onChanged.remove(sg.
|
|
162
|
+
t.position.onChanged.remove(sg.updateTransform, sg);
|
|
163
|
+
t.rotation.onChanged.remove(sg.updateTransform, sg);
|
|
164
|
+
t.scale.onChanged.remove(sg.updateTransform, sg);
|
|
163
165
|
|
|
164
166
|
sg.bvh.disconnect();
|
|
165
167
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { DrawMode } from "./DrawMode.js";
|
|
2
|
+
import { Line, LineSegments, Mesh } from "three";
|
|
3
|
+
import { ShadedGeometryFlags } from "./ShadedGeometryFlags.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {ShadedGeometry} sg
|
|
8
|
+
* @returns {THREE.Object3D}
|
|
9
|
+
*/
|
|
10
|
+
export function build_three_object(sg) {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @type {THREE.Object3D}
|
|
14
|
+
*/
|
|
15
|
+
let object;
|
|
16
|
+
|
|
17
|
+
const mode = sg.mode;
|
|
18
|
+
const shader = sg.material;
|
|
19
|
+
const geo = sg.geometry;
|
|
20
|
+
|
|
21
|
+
if (mode === DrawMode.Triangles) {
|
|
22
|
+
object = new Mesh(geo, shader);
|
|
23
|
+
} else if (mode === DrawMode.Lines) {
|
|
24
|
+
object = new Line(geo, shader);
|
|
25
|
+
} else if (mode === DrawMode.LineSegments) {
|
|
26
|
+
object = new LineSegments(geo, shader);
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error(`Unsupported draw mode '${mode}'`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
object.matrixAutoUpdate = false;
|
|
32
|
+
object.frustumCulled = false;
|
|
33
|
+
object.matrixWorldNeedsUpdate = false;
|
|
34
|
+
|
|
35
|
+
object.castShadow = sg.getFlag(ShadedGeometryFlags.CastShadow);
|
|
36
|
+
object.receiveShadow = sg.getFlag(ShadedGeometryFlags.ReceiveShadow);
|
|
37
|
+
|
|
38
|
+
return object;
|
|
39
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbstractRenderAdapter } from "./AbstractRenderAdapter.js";
|
|
2
|
-
import { build_three_object } from "../ShadedGeometry.js";
|
|
3
2
|
import { array_copy } from "../../../../../core/collection/array/copyArray.js";
|
|
3
|
+
import { build_three_object } from "../build_three_object.js";
|
|
4
4
|
|
|
5
5
|
export class GenericRendererAdapter extends AbstractRenderAdapter {
|
|
6
6
|
constructor() {
|
|
@@ -2,11 +2,42 @@ import { AbstractRenderAdapter } from "./AbstractRenderAdapter.js";
|
|
|
2
2
|
import { HashMap } from "../../../../../core/collection/HashMap.js";
|
|
3
3
|
import { InstancedMeshGroup } from "../../../geometry/instancing/InstancedMeshGroup.js";
|
|
4
4
|
import { ShadedGeometryFlags } from "../ShadedGeometryFlags.js";
|
|
5
|
+
import { DrawMode } from "../DrawMode.js";
|
|
5
6
|
|
|
6
7
|
const INSTANCED_EQUALITY_FLAGS = ShadedGeometryFlags.CastShadow
|
|
7
8
|
| ShadedGeometryFlags.ReceiveShadow
|
|
8
9
|
;
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @param {ShadedGeometry} a
|
|
14
|
+
* @param {ShadedGeometry} b
|
|
15
|
+
* @returns {number}
|
|
16
|
+
*/
|
|
17
|
+
function compare(a, b) {
|
|
18
|
+
const d_geometry = a.geometry.id - b.geometry.id;
|
|
19
|
+
if (d_geometry !== 0) {
|
|
20
|
+
return d_geometry;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const d_material = a.material.id - b.material.id;
|
|
24
|
+
if (d_material !== 0) {
|
|
25
|
+
return d_material;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const d_flags = (a.flags & INSTANCED_EQUALITY_FLAGS) - (b.flags & INSTANCED_EQUALITY_FLAGS);
|
|
29
|
+
if (d_flags !== 0) {
|
|
30
|
+
return d_flags;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const d_mode = a.mode - b.mode;
|
|
34
|
+
if (d_mode !== 0) {
|
|
35
|
+
return d_mode;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
10
41
|
export class InstancedRendererAdapter extends AbstractRenderAdapter {
|
|
11
42
|
constructor() {
|
|
12
43
|
super();
|
|
@@ -18,11 +49,12 @@ export class InstancedRendererAdapter extends AbstractRenderAdapter {
|
|
|
18
49
|
*/
|
|
19
50
|
this.__instanced_meshes = new HashMap({
|
|
20
51
|
keyHashFunction(sg) {
|
|
21
|
-
return sg.geometry.id ^ sg.material.id;
|
|
52
|
+
return sg.geometry.id ^ sg.material.id ^ sg.mode;
|
|
22
53
|
},
|
|
23
54
|
keyEqualityFunction(a, b) {
|
|
24
55
|
return a.material.id === b.material.id
|
|
25
56
|
&& a.geometry.id === b.geometry.id
|
|
57
|
+
&& a.mode === b.mode
|
|
26
58
|
&& (a.flags & INSTANCED_EQUALITY_FLAGS) === (b.flags & INSTANCED_EQUALITY_FLAGS)
|
|
27
59
|
;
|
|
28
60
|
}
|
|
@@ -45,7 +77,17 @@ export class InstancedRendererAdapter extends AbstractRenderAdapter {
|
|
|
45
77
|
__get_instanced_mesh(sg) {
|
|
46
78
|
let im = this.__instanced_meshes.get(sg);
|
|
47
79
|
|
|
48
|
-
|
|
80
|
+
|
|
81
|
+
if (im !== undefined) {
|
|
82
|
+
|
|
83
|
+
return im;
|
|
84
|
+
|
|
85
|
+
} else {
|
|
86
|
+
|
|
87
|
+
if (sg.mode !== DrawMode.Triangles) {
|
|
88
|
+
throw new Error(`Unsupported draw mode ${sg.mode}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
49
91
|
im = new InstancedMeshGroup();
|
|
50
92
|
im.shrinkFactor = 0; // prevent shrinking as we're essentially rebuilding this geometry frame
|
|
51
93
|
|
|
@@ -56,9 +98,10 @@ export class InstancedRendererAdapter extends AbstractRenderAdapter {
|
|
|
56
98
|
im.mesh.receiveShadow = sg.getFlag(ShadedGeometryFlags.ReceiveShadow);
|
|
57
99
|
|
|
58
100
|
this.__instanced_meshes.set(sg, im);
|
|
59
|
-
}
|
|
60
101
|
|
|
61
|
-
|
|
102
|
+
return im;
|
|
103
|
+
|
|
104
|
+
}
|
|
62
105
|
}
|
|
63
106
|
|
|
64
107
|
add(sg) {
|
|
@@ -66,7 +109,11 @@ export class InstancedRendererAdapter extends AbstractRenderAdapter {
|
|
|
66
109
|
|
|
67
110
|
const index = mesh.count;
|
|
68
111
|
|
|
69
|
-
|
|
112
|
+
const new_size = index + 1;
|
|
113
|
+
|
|
114
|
+
if (new_size > mesh.capacity) {
|
|
115
|
+
mesh.ensureCapacity(new_size);
|
|
116
|
+
}
|
|
70
117
|
|
|
71
118
|
mesh.setTransformAt(index, sg.transform);
|
|
72
119
|
|
|
@@ -80,13 +127,14 @@ export class InstancedRendererAdapter extends AbstractRenderAdapter {
|
|
|
80
127
|
}
|
|
81
128
|
|
|
82
129
|
build_end() {
|
|
130
|
+
const objects = this.__objects;
|
|
83
131
|
|
|
84
132
|
for (const activeMesh of this.__active_meshes) {
|
|
85
133
|
// force underlying geometry to update
|
|
86
134
|
activeMesh.setCount(activeMesh.getCount());
|
|
87
135
|
activeMesh.requestAttributeUpdate();
|
|
88
136
|
|
|
89
|
-
|
|
137
|
+
objects[this.__object_count++] = activeMesh.mesh;
|
|
90
138
|
}
|
|
91
139
|
|
|
92
140
|
}
|
|
@@ -16,6 +16,7 @@ import GUIElementSystem from "../../../../ecs/gui/GUIElementSystem.js";
|
|
|
16
16
|
import Vector3 from "../../../../../core/geom/Vector3.js";
|
|
17
17
|
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
18
18
|
import { ShadedGeometryFlags } from "../ShadedGeometryFlags.js";
|
|
19
|
+
import { randomFromArray } from "../../../../../core/math/random/randomFromArray.js";
|
|
19
20
|
|
|
20
21
|
const eh = new EngineHarness();
|
|
21
22
|
|
|
@@ -51,23 +52,31 @@ async function main(engine) {
|
|
|
51
52
|
|
|
52
53
|
window.material = material;
|
|
53
54
|
|
|
54
|
-
const geometry = new BoxBufferGeometry();
|
|
55
|
-
|
|
56
55
|
const random = seededRandom(0);
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
const INSTANCE_COUNT = 20000;
|
|
58
|
+
|
|
59
|
+
const geometries = [];
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < 1000; i++) {
|
|
62
|
+
geometries.push(new BoxBufferGeometry());
|
|
63
|
+
}
|
|
59
64
|
|
|
65
|
+
for (let i = 0; i < INSTANCE_COUNT; i++) {
|
|
66
|
+
const geometry = randomFromArray(random, geometries);
|
|
60
67
|
const sg = ShadedGeometry.from(geometry, material);
|
|
61
68
|
|
|
69
|
+
// sg.draw_method = DRAW_METHOD_PLAIN;
|
|
62
70
|
sg.draw_method = DRAW_METHOD_INSTANCED;
|
|
71
|
+
// sg.draw_method = random() > 0.01 ? DRAW_METHOD_INSTANCED : DRAW_METHOD_PLAIN;
|
|
63
72
|
sg.clearFlag(ShadedGeometryFlags.CastShadow | ShadedGeometryFlags.ReceiveShadow);
|
|
64
73
|
|
|
65
74
|
new EntityBuilder()
|
|
66
75
|
.add(Transform.fromJSON({
|
|
67
76
|
position: {
|
|
68
|
-
x: randomFloatBetween(random,
|
|
77
|
+
x: randomFloatBetween(random, 0, 20),
|
|
69
78
|
y: randomFloatBetween(random, 0, 10),
|
|
70
|
-
z: randomFloatBetween(random,
|
|
79
|
+
z: randomFloatBetween(random, 0, 20)
|
|
71
80
|
},
|
|
72
81
|
rotation: Quaternion.random(random),
|
|
73
82
|
scale: 0.05
|
|
@@ -11,6 +11,7 @@ import { StaticMaterialCache } from "../../../asset/loaders/material/StaticMater
|
|
|
11
11
|
import { composeCompile } from "../../material/composeCompile.js";
|
|
12
12
|
import { typed_array_copy } from "../../../../core/collection/array/typed/typed_array_copy.js";
|
|
13
13
|
import { rewriteMaterial } from "./rewriteMaterial.js";
|
|
14
|
+
import { max3 } from "../../../../core/math/max3.js";
|
|
14
15
|
|
|
15
16
|
export class InstancedMeshGroup {
|
|
16
17
|
/**
|
|
@@ -69,6 +70,13 @@ export class InstancedMeshGroup {
|
|
|
69
70
|
*/
|
|
70
71
|
this.__attributeTransform = null;
|
|
71
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Shortcut to buffer attribute data
|
|
75
|
+
* @type {Float32Array}
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
this.__attributeTransformArray = null;
|
|
79
|
+
|
|
72
80
|
/**
|
|
73
81
|
*
|
|
74
82
|
* @type {Material}
|
|
@@ -167,7 +175,7 @@ export class InstancedMeshGroup {
|
|
|
167
175
|
if (currentCapacity < size) {
|
|
168
176
|
// grow
|
|
169
177
|
|
|
170
|
-
const newCapacityRaw =
|
|
178
|
+
const newCapacityRaw = max3(
|
|
171
179
|
size,
|
|
172
180
|
currentCapacity * this.growFactor,
|
|
173
181
|
currentCapacity + this.growConstant
|
|
@@ -193,7 +201,7 @@ export class InstancedMeshGroup {
|
|
|
193
201
|
* @param {number[]|ArrayLike<number>|Float32Array} transform 4x4 transform matrix of the instance
|
|
194
202
|
*/
|
|
195
203
|
setTransformAt(index, transform) {
|
|
196
|
-
this.
|
|
204
|
+
this.__attributeTransformArray.set(transform, index * 16);
|
|
197
205
|
}
|
|
198
206
|
|
|
199
207
|
requestAttributeUpdate() {
|
|
@@ -357,6 +365,7 @@ export class InstancedMeshGroup {
|
|
|
357
365
|
}
|
|
358
366
|
|
|
359
367
|
//rewrite old attributes
|
|
368
|
+
this.__attributeTransformArray = newTransformArray;
|
|
360
369
|
this.__attributeTransform = new InstancedBufferAttribute(newTransformArray, 16);
|
|
361
370
|
this.__attributeTransform.setUsage(StreamDrawUsage);
|
|
362
371
|
|
|
@@ -189,12 +189,13 @@ export class VGThreeRenderer {
|
|
|
189
189
|
const ctx = instance_to_ctx.get(instance_id);
|
|
190
190
|
|
|
191
191
|
const target_address = ctx.__patch_count * 3;
|
|
192
|
+
ctx.__patch_count++;
|
|
192
193
|
|
|
193
|
-
ctx.__patches
|
|
194
|
-
ctx.__patches[target_address + 1] = geometry_id;
|
|
195
|
-
ctx.__patches[target_address + 2] = patch_id;
|
|
194
|
+
const ctx_patches = ctx.__patches;
|
|
196
195
|
|
|
197
|
-
|
|
196
|
+
ctx_patches[target_address] = instance_id;
|
|
197
|
+
ctx_patches[target_address + 1] = geometry_id;
|
|
198
|
+
ctx_patches[target_address + 2] = patch_id;
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
// build each context
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"productName": "Meep",
|
|
6
6
|
"description": "production-ready JavaScript game engine based on Entity Component System Architecture",
|
|
7
7
|
"author": "Alexander Goldring",
|
|
8
|
-
"version": "2.35.
|
|
8
|
+
"version": "2.35.2",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|