@woosh/meep-engine 2.37.13 → 2.37.16
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.d.ts +20 -0
- package/core/bvh2/aabb3/AABB3.js +53 -12
- package/core/bvh2/aabb3/AABB3.spec.js +19 -0
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +55 -17
- package/core/geom/3d/decompose_matrix_4_array.js +7 -3
- package/core/geom/Quaternion.js +32 -18
- package/core/geom/Vector3.js +11 -0
- package/engine/ecs/transform/Transform.js +5 -2
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +8 -13
- package/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +27 -3
- package/engine/graphics/ecs/mesh-v2/aggregate/prototypeSGMesh.js +102 -23
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +128 -1
- package/engine/graphics/geometry/instancing/rewriteMaterial.js +20 -1
- package/engine/graphics/micron/format/MicronGeometryPatch.js +4 -1
- package/engine/graphics/micron/format/serialization/collection/geometry_collection_serialization.spec.js +27 -0
- package/engine/graphics/render/gizmo/GizmoRenderingPlugin.js +20 -0
- package/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.js +78 -10
- package/engine/graphics/render/visibility/IncrementalDeltaSet.spec.js +17 -1
- package/engine/intelligence/behavior/primitive/ActionBehavior.js +1 -1
- package/package.json +1 -1
|
@@ -8,12 +8,26 @@ export class AABB3 {
|
|
|
8
8
|
y1: number
|
|
9
9
|
z1: number
|
|
10
10
|
|
|
11
|
+
constructor(x0?: number, y0?: number, z0?: number, x1?: number, y1?: number, z1?: number)
|
|
12
|
+
|
|
11
13
|
setBounds(x0: number, y0: number, z0: number, x1: number, y1: number, z1: number): void
|
|
12
14
|
|
|
13
15
|
getCenter(target: Vector3): void
|
|
14
16
|
|
|
17
|
+
getCenterX(): number
|
|
18
|
+
|
|
19
|
+
getCenterY(): number
|
|
20
|
+
|
|
21
|
+
getCenterZ(): number
|
|
22
|
+
|
|
15
23
|
getExtents(target: Vector3): void
|
|
16
24
|
|
|
25
|
+
getExtentsX(): number
|
|
26
|
+
|
|
27
|
+
getExtentsY(): number
|
|
28
|
+
|
|
29
|
+
getExtentsZ(): number
|
|
30
|
+
|
|
17
31
|
expandToFit(box: AABB3): void
|
|
18
32
|
|
|
19
33
|
_expandToFitPoint(x: number, y: number, z: number): boolean
|
|
@@ -23,4 +37,10 @@ export class AABB3 {
|
|
|
23
37
|
setInfiniteBounds(): void
|
|
24
38
|
|
|
25
39
|
distanceToBox(other: AABB3): number
|
|
40
|
+
|
|
41
|
+
applyMatrix4(matrix: ArrayLike<number>): void
|
|
42
|
+
|
|
43
|
+
equals(other: AABB3): boolean
|
|
44
|
+
|
|
45
|
+
copy(other: AABB3): void
|
|
26
46
|
}
|
package/core/bvh2/aabb3/AABB3.js
CHANGED
|
@@ -13,6 +13,7 @@ import { aabb3_intersects_line_segment } from "./aabb3_intersects_line_segment.j
|
|
|
13
13
|
import { aabb3_intersects_ray } from "./aabb3_intersects_ray.js";
|
|
14
14
|
import { aabb3_compute_surface_area } from "./aabb3_compute_surface_area.js";
|
|
15
15
|
import { aabb3_intersects_frustum_array } from "./aabb3_intersects_frustum_array.js";
|
|
16
|
+
import { aabb3_matrix4_project } from "../../geom/3d/aabb/aabb3_matrix4_project.js";
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
export class AABB3 {
|
|
@@ -504,17 +505,6 @@ export class AABB3 {
|
|
|
504
505
|
return this.getExtentsZ() / 2;
|
|
505
506
|
}
|
|
506
507
|
|
|
507
|
-
/**
|
|
508
|
-
* Get center position of the box
|
|
509
|
-
* @param {Vector3} target where to write result
|
|
510
|
-
*/
|
|
511
|
-
getCenter(target) {
|
|
512
|
-
const x = (this.x0 + this.x1) / 2;
|
|
513
|
-
const y = (this.y0 + this.y1) / 2;
|
|
514
|
-
const z = (this.z0 + this.z1) / 2;
|
|
515
|
-
target.set(x, y, z);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
508
|
/**
|
|
519
509
|
*
|
|
520
510
|
* @param {Vector3} target
|
|
@@ -527,6 +517,42 @@ export class AABB3 {
|
|
|
527
517
|
target.set(x, y, z);
|
|
528
518
|
}
|
|
529
519
|
|
|
520
|
+
/**
|
|
521
|
+
*
|
|
522
|
+
* @returns {number}
|
|
523
|
+
*/
|
|
524
|
+
getCenterX() {
|
|
525
|
+
return (this.x0 + this.x1) * 0.5;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
*
|
|
530
|
+
* @returns {number}
|
|
531
|
+
*/
|
|
532
|
+
getCenterY() {
|
|
533
|
+
return (this.y0 + this.y1) * 0.5;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
*
|
|
538
|
+
* @returns {number}
|
|
539
|
+
*/
|
|
540
|
+
getCenterZ() {
|
|
541
|
+
return (this.z0 + this.z1) * 0.5;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Get center position of the box
|
|
546
|
+
* @param {Vector3} target where to write result
|
|
547
|
+
*/
|
|
548
|
+
getCenter(target) {
|
|
549
|
+
const x = this.getCenterX();
|
|
550
|
+
const y = this.getCenterY();
|
|
551
|
+
const z = this.getCenterZ();
|
|
552
|
+
target.set(x, y, z);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
|
|
530
556
|
/**
|
|
531
557
|
* Accepts ray description, first set of coordinates is origin (oX,oY,oZ) and second is direction (dX,dY,dZ). Algorithm from GraphicsGems by Andrew Woo
|
|
532
558
|
* @param oX
|
|
@@ -736,7 +762,7 @@ export class AABB3 {
|
|
|
736
762
|
* @param {number[]|Float32Array|Float64Array} result
|
|
737
763
|
* @param {number} offset
|
|
738
764
|
*/
|
|
739
|
-
writeToArray(result, offset) {
|
|
765
|
+
writeToArray(result, offset = 0) {
|
|
740
766
|
assert.isNonNegativeInteger(offset, 'offset');
|
|
741
767
|
|
|
742
768
|
result[offset] = this.x0;
|
|
@@ -906,6 +932,21 @@ export class AABB3 {
|
|
|
906
932
|
return aabb3_intersects_frustum_array(x0, y0, z0, x1, y1, z1, frustum);
|
|
907
933
|
}
|
|
908
934
|
|
|
935
|
+
/**
|
|
936
|
+
*
|
|
937
|
+
* @param {number[]|ArrayLike<number>|Float32Array} matrix
|
|
938
|
+
*/
|
|
939
|
+
applyMatrix4(matrix) {
|
|
940
|
+
const a = [];
|
|
941
|
+
const b = [];
|
|
942
|
+
|
|
943
|
+
this.writeToArray(a, 0);
|
|
944
|
+
|
|
945
|
+
aabb3_matrix4_project(b, a, matrix);
|
|
946
|
+
|
|
947
|
+
this.readFromArray(b, 0);
|
|
948
|
+
}
|
|
949
|
+
|
|
909
950
|
/**
|
|
910
951
|
*
|
|
911
952
|
* @param {number} v
|
|
@@ -206,3 +206,22 @@ test('readFrom/writeTo Array consistency', () => {
|
|
|
206
206
|
expect(s.y1).toEqual(5);
|
|
207
207
|
expect(s.z1).toEqual(6);
|
|
208
208
|
});
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
test("getExtentsX", () => {
|
|
212
|
+
expect(new AABB3(0, 0, 0, 0, 0, 0).getExtentsX()).toBe(0);
|
|
213
|
+
expect(new AABB3(0, 0, 0, 1, 0, 0).getExtentsX()).toBeCloseTo(1);
|
|
214
|
+
expect(new AABB3(-1, 0, 0, 1, 0, 0).getExtentsX()).toBeCloseTo(2);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("getExtentsY", () => {
|
|
218
|
+
expect(new AABB3(0, 0, 0, 0, 0, 0).getExtentsY()).toBe(0);
|
|
219
|
+
expect(new AABB3(0, 0, 0, 0, 1, 0).getExtentsY()).toBeCloseTo(1);
|
|
220
|
+
expect(new AABB3(0, -1, 0, 0, 1, 0).getExtentsY()).toBeCloseTo(2);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test("getExtentsZ", () => {
|
|
224
|
+
expect(new AABB3(0, 0, 0, 0, 0, 0).getExtentsZ()).toBe(0);
|
|
225
|
+
expect(new AABB3(0, 0, 0, 0, 0, 1).getExtentsZ()).toBeCloseTo(1);
|
|
226
|
+
expect(new AABB3(0, 0, -1, 0, 0, 1).getExtentsZ()).toBeCloseTo(2);
|
|
227
|
+
});
|
|
@@ -35,11 +35,25 @@ const CAPACITY_GROW_MULTIPLIER = 1.2;
|
|
|
35
35
|
const CAPACITY_GROW_MIN_STEP = 64;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
+
* How many words are used for a single NODE in the tree
|
|
39
|
+
* One "word" is 4 bytes for the sake of alignment
|
|
38
40
|
* @readonly
|
|
39
41
|
* @type {number}
|
|
40
42
|
*/
|
|
41
43
|
const ELEMENT_WORD_COUNT = 10;
|
|
42
44
|
|
|
45
|
+
/**
|
|
46
|
+
* How many nodes can be stored in the newly constructed tree before allocation needs to take place
|
|
47
|
+
* @readonly
|
|
48
|
+
* @type {number}
|
|
49
|
+
*/
|
|
50
|
+
const INITIAL_CAPACITY = 128;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Bounding Volume Hierarchy implementation. Stores unsigned integer values at leaves, these are typically IDs or Index values.
|
|
54
|
+
* Highly optimized both in terms of memory usage and CPU. Most of the code inlined. No allocation are performed during usage (except for growing the tree capacity).
|
|
55
|
+
* RAM usage: 40 bytes per node. Compared with V8s per-object allocation size of 80 bytes (see https://blog.dashlane.com/how-is-data-stored-in-v8-js-engine-memory)
|
|
56
|
+
*/
|
|
43
57
|
export class ExplicitBinaryBoundingVolumeHierarchy {
|
|
44
58
|
constructor() {
|
|
45
59
|
/**
|
|
@@ -47,7 +61,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
|
|
|
47
61
|
* @type {ArrayBuffer}
|
|
48
62
|
* @private
|
|
49
63
|
*/
|
|
50
|
-
this.__data_buffer = new ArrayBuffer(
|
|
64
|
+
this.__data_buffer = new ArrayBuffer(INITIAL_CAPACITY * ELEMENT_WORD_COUNT * 4);
|
|
51
65
|
|
|
52
66
|
/**
|
|
53
67
|
*
|
|
@@ -64,28 +78,34 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
|
|
|
64
78
|
this.__data_uint32 = new Uint32Array(this.__data_buffer);
|
|
65
79
|
|
|
66
80
|
/**
|
|
67
|
-
*
|
|
81
|
+
* How many nodes are currently reserved, this will grow automatically through {@link #allocate_node} method usage
|
|
68
82
|
* @type {number}
|
|
69
83
|
* @private
|
|
70
84
|
*/
|
|
71
|
-
this.__capacity =
|
|
85
|
+
this.__capacity = INITIAL_CAPACITY;
|
|
72
86
|
|
|
73
87
|
/**
|
|
74
|
-
*
|
|
88
|
+
* Number of used nodes. These are either live nodes, or node sitting in the {@link #__free} pool
|
|
75
89
|
* @type {number}
|
|
76
90
|
* @private
|
|
77
91
|
*/
|
|
78
92
|
this.__size = 0;
|
|
79
93
|
|
|
80
94
|
/**
|
|
81
|
-
*
|
|
95
|
+
* Indices of released nodes. Nodes are pulled from here first if available, before the whole tree gets resized
|
|
82
96
|
* @type {number[]}
|
|
83
97
|
* @private
|
|
84
98
|
*/
|
|
85
99
|
this.__free = [];
|
|
100
|
+
/**
|
|
101
|
+
* Pointer into __free array that's used as a stack, so this pointer represents top of the stack
|
|
102
|
+
* @type {number}
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
this.__free_pointer = 0;
|
|
86
106
|
|
|
87
107
|
/**
|
|
88
|
-
*
|
|
108
|
+
* Root node of the hierarchy
|
|
89
109
|
* @type {number}
|
|
90
110
|
* @private
|
|
91
111
|
*/
|
|
@@ -134,12 +154,19 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
|
|
|
134
154
|
* @returns {number}
|
|
135
155
|
*/
|
|
136
156
|
allocate_node() {
|
|
137
|
-
const free = this.__free;
|
|
138
|
-
|
|
139
157
|
let result;
|
|
140
|
-
|
|
158
|
+
const free_stack_top = this.__free_pointer;
|
|
159
|
+
|
|
160
|
+
if (free_stack_top > 0) {
|
|
161
|
+
|
|
141
162
|
// nodes in the free pool
|
|
142
|
-
|
|
163
|
+
|
|
164
|
+
const free_index = free_stack_top - 1;
|
|
165
|
+
|
|
166
|
+
result = this.__free[free_index];
|
|
167
|
+
|
|
168
|
+
this.__free_pointer = free_index;
|
|
169
|
+
|
|
143
170
|
} else {
|
|
144
171
|
|
|
145
172
|
result = this.__size;
|
|
@@ -180,13 +207,14 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
|
|
|
180
207
|
}
|
|
181
208
|
|
|
182
209
|
/**
|
|
183
|
-
* Release memory used by the node
|
|
210
|
+
* Release memory used by the node back into the pool
|
|
211
|
+
* NOTE: Make sure that the node is not "live" (not attached to the hierarchy), otherwise this operation may corrupt the tree
|
|
184
212
|
* @param {number} id
|
|
185
213
|
*/
|
|
186
214
|
release_node(id) {
|
|
187
215
|
assert.isNonNegativeInteger(id, 'id');
|
|
188
216
|
// no reset required as that's handled in the allocation method
|
|
189
|
-
this.__free.
|
|
217
|
+
this.__free[this.__free_pointer++] = id;
|
|
190
218
|
}
|
|
191
219
|
|
|
192
220
|
/**
|
|
@@ -561,19 +589,21 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
|
|
|
561
589
|
|
|
562
590
|
const uint32 = this.__data_uint32;
|
|
563
591
|
|
|
564
|
-
|
|
592
|
+
do {
|
|
565
593
|
index = this.balance(index);
|
|
566
594
|
|
|
567
|
-
const
|
|
568
|
-
|
|
595
|
+
const address = index * ELEMENT_WORD_COUNT;
|
|
596
|
+
|
|
597
|
+
const child1 = uint32[address + COLUMN_CHILD_1];
|
|
598
|
+
const child2 = uint32[address + COLUMN_CHILD_2];
|
|
569
599
|
|
|
570
600
|
assert.notEqual(child1, NULL_NODE, 'child1 is null');
|
|
571
601
|
assert.notEqual(child2, NULL_NODE, 'child2 is null');
|
|
572
602
|
|
|
573
603
|
this.node_set_combined_aabb(index, child1, child2);
|
|
574
604
|
|
|
575
|
-
index = uint32[
|
|
576
|
-
}
|
|
605
|
+
index = uint32[address + COLUMN_PARENT];
|
|
606
|
+
} while (index !== NULL_NODE)
|
|
577
607
|
}
|
|
578
608
|
|
|
579
609
|
/**
|
|
@@ -895,4 +925,12 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
|
|
|
895
925
|
|
|
896
926
|
return i - destination_offset;
|
|
897
927
|
}
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* Sort live nodes in the traversal order.
|
|
931
|
+
* This makes most queries have linear access, resulting in near-optimal cache usage
|
|
932
|
+
*/
|
|
933
|
+
sort_for_traversal_depth_first() {
|
|
934
|
+
throw new Error('Not Implemented');
|
|
935
|
+
}
|
|
898
936
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const hypot = Math.hypot;
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
*
|
|
3
5
|
* @param {number[]} m
|
|
@@ -10,17 +12,19 @@ export function decompose_matrix_4_array(m, position, rotation, scale) {
|
|
|
10
12
|
const m12 = m[1];
|
|
11
13
|
const m13 = m[2];
|
|
12
14
|
|
|
15
|
+
const scale_x = hypot(m11, m12, m13);
|
|
16
|
+
|
|
13
17
|
const m21 = m[4];
|
|
14
18
|
const m22 = m[5];
|
|
15
19
|
const m23 = m[6];
|
|
16
20
|
|
|
21
|
+
const scale_y = hypot(m21, m22, m23);
|
|
22
|
+
|
|
17
23
|
const m31 = m[8];
|
|
18
24
|
const m32 = m[9];
|
|
19
25
|
const m33 = m[10];
|
|
20
26
|
|
|
21
|
-
const
|
|
22
|
-
const scale_y = Math.hypot(m21, m22, m23);
|
|
23
|
-
const scale_z = Math.hypot(m31, m32, m33);
|
|
27
|
+
const scale_z = hypot(m31, m32, m33);
|
|
24
28
|
|
|
25
29
|
// extract rotation
|
|
26
30
|
const is1 = 1 / scale_x;
|
package/core/geom/Quaternion.js
CHANGED
|
@@ -1047,7 +1047,9 @@ class Quaternion {
|
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
1049
1049
|
/**
|
|
1050
|
-
*
|
|
1050
|
+
* This algorithm comes from "Quaternion Calculus and Fast Animation",
|
|
1051
|
+
* Ken Shoemake, 1987 SIGGRAPH course notes
|
|
1052
|
+
* @see https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Geometry/Quaternion.h#L813
|
|
1051
1053
|
* @param {number} m11
|
|
1052
1054
|
* @param {number} m12
|
|
1053
1055
|
* @param {number} m13
|
|
@@ -1066,39 +1068,51 @@ class Quaternion {
|
|
|
1066
1068
|
|
|
1067
1069
|
if (trace > 0) {
|
|
1068
1070
|
|
|
1069
|
-
s =
|
|
1071
|
+
s = Math.sqrt(trace + 1.0);
|
|
1072
|
+
|
|
1073
|
+
w = 0.5 * s;
|
|
1074
|
+
|
|
1075
|
+
s = 0.5 / s;
|
|
1070
1076
|
|
|
1071
|
-
w = 0.25 / s;
|
|
1072
1077
|
x = (m32 - m23) * s;
|
|
1073
1078
|
y = (m13 - m31) * s;
|
|
1074
1079
|
z = (m21 - m12) * s;
|
|
1075
1080
|
|
|
1076
1081
|
} else if (m11 > m22 && m11 > m33) {
|
|
1077
1082
|
|
|
1078
|
-
s =
|
|
1083
|
+
s = Math.sqrt(1.0 + m11 - m22 - m33);
|
|
1084
|
+
|
|
1085
|
+
x = 0.5 * s;
|
|
1086
|
+
|
|
1087
|
+
s = 0.5 / s;
|
|
1079
1088
|
|
|
1080
|
-
w = (m32 - m23)
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
z = (m13 + m31) / s;
|
|
1089
|
+
w = (m32 - m23) * s;
|
|
1090
|
+
y = (m12 + m21) * s;
|
|
1091
|
+
z = (m13 + m31) * s;
|
|
1084
1092
|
|
|
1085
1093
|
} else if (m22 > m33) {
|
|
1086
1094
|
|
|
1087
|
-
s =
|
|
1095
|
+
s = Math.sqrt(1.0 + m22 - m11 - m33);
|
|
1088
1096
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1097
|
+
y = 0.5 * s;
|
|
1098
|
+
|
|
1099
|
+
s = 0.5 / s;
|
|
1100
|
+
|
|
1101
|
+
w = (m13 - m31) * s;
|
|
1102
|
+
x = (m12 + m21) * s;
|
|
1103
|
+
z = (m23 + m32) * s;
|
|
1093
1104
|
|
|
1094
1105
|
} else {
|
|
1095
1106
|
|
|
1096
|
-
s =
|
|
1107
|
+
s = Math.sqrt(1.0 + m33 - m11 - m22);
|
|
1108
|
+
|
|
1109
|
+
z = 0.5 * s;
|
|
1110
|
+
|
|
1111
|
+
s = 0.5 / s;
|
|
1097
1112
|
|
|
1098
|
-
w = (m21 - m12)
|
|
1099
|
-
x = (m13 + m31)
|
|
1100
|
-
y = (m23 + m32)
|
|
1101
|
-
z = 0.25 * s;
|
|
1113
|
+
w = (m21 - m12) * s;
|
|
1114
|
+
x = (m13 + m31) * s;
|
|
1115
|
+
y = (m23 + m32) * s;
|
|
1102
1116
|
|
|
1103
1117
|
}
|
|
1104
1118
|
|
package/core/geom/Vector3.js
CHANGED
|
@@ -77,6 +77,8 @@ class Vector3 {
|
|
|
77
77
|
const oldZ = this.z;
|
|
78
78
|
|
|
79
79
|
if (x !== oldX || y !== oldY || z !== oldZ) {
|
|
80
|
+
// change has occurred
|
|
81
|
+
|
|
80
82
|
this.x = x;
|
|
81
83
|
this.y = y;
|
|
82
84
|
this.z = z;
|
|
@@ -942,6 +944,15 @@ class Vector3 {
|
|
|
942
944
|
input[offset + 2]
|
|
943
945
|
);
|
|
944
946
|
}
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
*
|
|
950
|
+
* @param {number} value
|
|
951
|
+
* @returns {Vector3}
|
|
952
|
+
*/
|
|
953
|
+
static fromScalar(value) {
|
|
954
|
+
return new Vector3(value, value, value);
|
|
955
|
+
}
|
|
945
956
|
}
|
|
946
957
|
|
|
947
958
|
Vector3.prototype.lengthSq = Vector3.prototype.lengthSqr;
|
|
@@ -171,12 +171,15 @@ export class Transform {
|
|
|
171
171
|
* @param {Transform} other
|
|
172
172
|
*/
|
|
173
173
|
copy(other) {
|
|
174
|
+
// prevent matrix from being overriden
|
|
175
|
+
this.clearFlag(TransformFlags.AutomaticChangeDetection);
|
|
176
|
+
|
|
177
|
+
this.matrix.set(other.matrix);
|
|
178
|
+
|
|
174
179
|
this.position.copy(other.position);
|
|
175
180
|
this.rotation.copy(other.rotation);
|
|
176
181
|
this.scale.copy(other.scale);
|
|
177
182
|
|
|
178
|
-
this.matrix.set(other.matrix);
|
|
179
|
-
|
|
180
183
|
this.flags = other.flags;
|
|
181
184
|
}
|
|
182
185
|
|
|
@@ -238,21 +238,16 @@ export class ShadedGeometry {
|
|
|
238
238
|
const gbb = this.geometry.boundingBox;
|
|
239
239
|
|
|
240
240
|
const min = gbb.min;
|
|
241
|
+
|
|
242
|
+
scratch_aabb3_array[0] = min.x;
|
|
243
|
+
scratch_aabb3_array[1] = min.y;
|
|
244
|
+
scratch_aabb3_array[2] = min.z;
|
|
245
|
+
|
|
241
246
|
const max = gbb.max;
|
|
242
247
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const x1 = max.x;
|
|
247
|
-
const y1 = max.y;
|
|
248
|
-
const z1 = max.z;
|
|
249
|
-
|
|
250
|
-
scratch_aabb3_array[0] = x0;
|
|
251
|
-
scratch_aabb3_array[1] = y0;
|
|
252
|
-
scratch_aabb3_array[2] = z0;
|
|
253
|
-
scratch_aabb3_array[3] = x1;
|
|
254
|
-
scratch_aabb3_array[4] = y1;
|
|
255
|
-
scratch_aabb3_array[5] = z1;
|
|
248
|
+
scratch_aabb3_array[3] = max.x;
|
|
249
|
+
scratch_aabb3_array[4] = max.y;
|
|
250
|
+
scratch_aabb3_array[5] = max.z;
|
|
256
251
|
|
|
257
252
|
aabb3_matrix4_project(this.__bvh_aabb, scratch_aabb3_array, this.transform);
|
|
258
253
|
}
|
|
@@ -53,6 +53,13 @@ export class SGMeshSystem extends System {
|
|
|
53
53
|
* @private
|
|
54
54
|
*/
|
|
55
55
|
this.__wait_queue_process_index = 0;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Cache THREE.js objects as we don't use them directly, so we can just keep 1 copy instead of calling {@link Asset#create} every time
|
|
59
|
+
* @type {Map<Asset, THREE.Object3D>}
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
this.__asset_object_cache = new Map();
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
/**
|
|
@@ -88,11 +95,28 @@ export class SGMeshSystem extends System {
|
|
|
88
95
|
|
|
89
96
|
if (asset.boundingBox !== undefined) {
|
|
90
97
|
mesh.__initial_bounds.copy(asset.boundingBox);
|
|
98
|
+
|
|
99
|
+
if (asset.has_root_transform) {
|
|
100
|
+
// TODO potentially move this to the GLTF Asset Loader to skip matrix operations here
|
|
101
|
+
mesh.__initial_bounds.applyMatrix4(asset.root_transform.matrix);
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
} else {
|
|
92
105
|
console.error(`No bounds for asset: ${asset.description}`);
|
|
93
106
|
}
|
|
94
107
|
|
|
95
|
-
let
|
|
108
|
+
let object;
|
|
109
|
+
const cached_object = this.__asset_object_cache.get(asset);
|
|
110
|
+
|
|
111
|
+
if (cached_object !== undefined) {
|
|
112
|
+
object = cached_object;
|
|
113
|
+
} else {
|
|
114
|
+
object = asset.create();
|
|
115
|
+
|
|
116
|
+
this.__asset_object_cache.set(asset, object);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let entity_node = three_object_to_entity_composition(object);
|
|
96
120
|
|
|
97
121
|
if (asset.has_root_transform) {
|
|
98
122
|
// apply root transform
|
|
@@ -230,12 +254,12 @@ export class SGMeshSystem extends System {
|
|
|
230
254
|
continue;
|
|
231
255
|
}
|
|
232
256
|
|
|
257
|
+
waiting.splice(index, 1);
|
|
258
|
+
|
|
233
259
|
const transform = dataset.getComponent(entity, Transform);
|
|
234
260
|
|
|
235
261
|
this.process(entity, mesh, transform);
|
|
236
262
|
|
|
237
|
-
waiting.splice(index, 1);
|
|
238
|
-
|
|
239
263
|
}
|
|
240
264
|
|
|
241
265
|
this.__wait_queue_process_index = pointer;
|
|
@@ -17,6 +17,14 @@ import Highlight from "../../highlight/Highlight.js";
|
|
|
17
17
|
import { ShadedGeometryHighlightSystem } from "../../highlight/system/ShadedGeometryHighlightSystem.js";
|
|
18
18
|
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
19
19
|
import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
|
|
20
|
+
import { BehaviorComponent } from "../../../../intelligence/behavior/ecs/BehaviorComponent.js";
|
|
21
|
+
import { OrbitingBehavior } from "../../../../../../model/game/util/behavior/OrbitingBehavior.js";
|
|
22
|
+
import Vector2 from "../../../../../core/geom/Vector2.js";
|
|
23
|
+
import { GizmoRenderingPlugin } from "../../../render/gizmo/GizmoRenderingPlugin.js";
|
|
24
|
+
import { Gizmo } from "../../../render/gizmo/Gizmo.js";
|
|
25
|
+
import { AABB3 } from "../../../../../core/bvh2/aabb3/AABB3.js";
|
|
26
|
+
import { MicronRenderPlugin } from "../../../micron/plugin/MicronRenderPlugin.js";
|
|
27
|
+
import { randomFloatBetween } from "../../../../../core/math/random/randomFloatBetween.js";
|
|
20
28
|
|
|
21
29
|
new EngineHarness().initialize({
|
|
22
30
|
configuration(config, engine) {
|
|
@@ -30,23 +38,113 @@ new EngineHarness().initialize({
|
|
|
30
38
|
new ShadedGeometryHighlightSystem(engine)
|
|
31
39
|
);
|
|
32
40
|
|
|
33
|
-
config.
|
|
41
|
+
config.addPlugin(GizmoRenderingPlugin);
|
|
42
|
+
config.addPlugin(MicronRenderPlugin);
|
|
43
|
+
|
|
44
|
+
const gltfAssetLoader = new GLTFAssetLoader();
|
|
45
|
+
|
|
46
|
+
config.addLoader(GameAssetType.ModelGLTF_JSON, gltfAssetLoader);
|
|
47
|
+
config.addLoader(GameAssetType.ModelGLTF, gltfAssetLoader);
|
|
34
48
|
}
|
|
35
49
|
}).then(main);
|
|
36
50
|
|
|
51
|
+
/**
|
|
52
|
+
*
|
|
53
|
+
* @param {EntityComponentDataset} ecd
|
|
54
|
+
* @param {Engine} engine
|
|
55
|
+
*/
|
|
56
|
+
function make_grid(ecd, engine) {
|
|
57
|
+
const random = seededRandom(1);
|
|
58
|
+
|
|
59
|
+
const GRID_SIZE = 20;
|
|
60
|
+
const GRID_FREQUENCY_SIZE = 7;
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < GRID_SIZE; i++) {
|
|
63
|
+
for (let j = 0; j < GRID_SIZE; j++) {
|
|
64
|
+
const quaternion = new Quaternion();
|
|
65
|
+
|
|
66
|
+
quaternion.__setFromEuler(0, random() * Math.PI, 0);
|
|
67
|
+
|
|
68
|
+
const center = new Vector3(i * 8, 0, j * 8);
|
|
69
|
+
|
|
70
|
+
const transform = Transform.fromJSON({
|
|
71
|
+
position: center,
|
|
72
|
+
rotation: quaternion,
|
|
73
|
+
scale: randomFloatBetween(random, 0.5, 2)
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const orbitingBehavior = OrbitingBehavior.from({
|
|
77
|
+
center: center,
|
|
78
|
+
rate: 1,
|
|
79
|
+
radius: 5
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const ctx = {
|
|
83
|
+
time: Math.sin(i * Math.PI / (GRID_FREQUENCY_SIZE - 1)) + Math.cos(j * Math.PI / (GRID_FREQUENCY_SIZE - 1))
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const color = [random(), random(), random(), 1];
|
|
87
|
+
|
|
88
|
+
engine.graphics.on.preRender.add(() => {
|
|
89
|
+
|
|
90
|
+
const bounds = new AABB3();
|
|
91
|
+
mesh.getUntransformedBoundingBox(bounds);
|
|
92
|
+
bounds.applyMatrix4(transform.matrix);
|
|
93
|
+
|
|
94
|
+
// mesh.getBoundingBox(bounds);
|
|
95
|
+
|
|
96
|
+
Gizmo.color = color;
|
|
97
|
+
|
|
98
|
+
Gizmo.draw_wire_cube(
|
|
99
|
+
[
|
|
100
|
+
bounds.getCenterX(), bounds.getCenterY(), bounds.getCenterZ()
|
|
101
|
+
],
|
|
102
|
+
[
|
|
103
|
+
bounds.getExtentsX(), bounds.getExtentsY(), bounds.getExtentsZ()
|
|
104
|
+
]
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
// const mesh = SGMesh.fromURL("data/models/RTS_Buildings_Humans/18/Building_R_18_out/Building_R_18.gltf");
|
|
110
|
+
const mesh = SGMesh.fromURL("data/models/samples/transform-hierarchy.glb");
|
|
111
|
+
new EntityBuilder()
|
|
112
|
+
.add(mesh)
|
|
113
|
+
.add(transform)
|
|
114
|
+
.add(BehaviorComponent.fromOne(
|
|
115
|
+
orbitingBehavior
|
|
116
|
+
// RepeatBehavior.from(
|
|
117
|
+
// new ActionBehavior((t) => {
|
|
118
|
+
// ctx.time += t;
|
|
119
|
+
//
|
|
120
|
+
// const f = smoothStep(0, 1, pingpong(ctx.time / 2.5, 1));
|
|
121
|
+
//
|
|
122
|
+
// transform.position.set(center.x, center.y + f * 5, center.z);
|
|
123
|
+
//
|
|
124
|
+
// })
|
|
125
|
+
// )
|
|
126
|
+
))
|
|
127
|
+
.build(ecd);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
37
132
|
/**
|
|
38
133
|
*
|
|
39
134
|
* @param {Engine} engine
|
|
40
135
|
*/
|
|
41
136
|
function main(engine) {
|
|
42
137
|
EngineHarness.buildBasics({
|
|
43
|
-
engine
|
|
138
|
+
engine,
|
|
139
|
+
terrainResolution: 1,
|
|
140
|
+
terrainSize: new Vector2(100, 100)
|
|
44
141
|
});
|
|
45
142
|
|
|
46
143
|
const ecd = engine.entityManager.dataset;
|
|
47
144
|
|
|
48
145
|
// const mesh = SGMesh.fromURL("data/models/RTS_Buildings_Humans/18/Building_R_18_out/Building_R_18.gltf");
|
|
49
|
-
const mesh = SGMesh.fromURL("moicon/ztest_object_many_pieces/model.gltf");
|
|
146
|
+
// const mesh = SGMesh.fromURL("moicon/ztest_object_many_pieces/model.gltf");
|
|
147
|
+
const mesh = SGMesh.fromURL("moicon/2022_04_20__Micron_from_Philippe/model.gltf");
|
|
50
148
|
// const mesh = Mesh.fromURL("moicon/ztest_object_many_pieces/model.gltf");
|
|
51
149
|
|
|
52
150
|
new EntityBuilder()
|
|
@@ -74,25 +172,6 @@ function main(engine) {
|
|
|
74
172
|
});
|
|
75
173
|
})
|
|
76
174
|
// .build(ecd);
|
|
77
|
-
const r = seededRandom(1);
|
|
78
|
-
|
|
79
|
-
for (let i = 0; i < 10; i++) {
|
|
80
|
-
for (let j = 0; j < 10; j++) {
|
|
81
|
-
const quaternion = new Quaternion();
|
|
82
|
-
|
|
83
|
-
quaternion.__setFromEuler(0, r() * Math.PI, 0);
|
|
84
175
|
|
|
85
|
-
|
|
86
|
-
.add(SGMesh.fromURL("data/models/RTS_Buildings_Humans/18/Building_R_18_out/Building_R_18.gltf"))
|
|
87
|
-
.add(Transform.fromJSON({
|
|
88
|
-
position: {
|
|
89
|
-
x: i * 8,
|
|
90
|
-
y: 0,
|
|
91
|
-
z: j * 8
|
|
92
|
-
},
|
|
93
|
-
rotation: quaternion
|
|
94
|
-
}))
|
|
95
|
-
.build(ecd);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
176
|
+
make_grid(ecd, engine);
|
|
98
177
|
}
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
DynamicDrawUsage,
|
|
4
4
|
InstancedBufferAttribute,
|
|
5
5
|
InstancedBufferGeometry,
|
|
6
|
+
Line,
|
|
7
|
+
LineSegments,
|
|
8
|
+
Mesh,
|
|
6
9
|
MeshDepthMaterial,
|
|
7
10
|
RGBADepthPacking
|
|
8
11
|
} from 'three';
|
|
@@ -13,6 +16,7 @@ import { typed_array_copy } from "../../../../core/collection/array/typed/typed_
|
|
|
13
16
|
import { rewriteMaterial } from "./rewriteMaterial.js";
|
|
14
17
|
import { max3 } from "../../../../core/math/max3.js";
|
|
15
18
|
import { min2 } from "../../../../core/math/min2.js";
|
|
19
|
+
import { DrawMode } from "../../ecs/mesh-v2/DrawMode.js";
|
|
16
20
|
|
|
17
21
|
export class InstancedMeshGroup {
|
|
18
22
|
/**
|
|
@@ -111,7 +115,64 @@ export class InstancedMeshGroup {
|
|
|
111
115
|
this.indices = [];
|
|
112
116
|
this.references = [];
|
|
113
117
|
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
* @type {DrawMode}
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
this.__draw_mode = DrawMode.Triangles;
|
|
124
|
+
|
|
114
125
|
this.mesh = ThreeFactory.createMesh();
|
|
126
|
+
|
|
127
|
+
this.use_color = true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
__build_mesh() {
|
|
131
|
+
|
|
132
|
+
let new_object;
|
|
133
|
+
switch (this.__draw_mode) {
|
|
134
|
+
case DrawMode.Triangles:
|
|
135
|
+
new_object = new Mesh(this.mesh.geometry, this.mesh.material);
|
|
136
|
+
break;
|
|
137
|
+
case DrawMode.Lines:
|
|
138
|
+
new_object = new Line(this.mesh.geometry, this.mesh.material);
|
|
139
|
+
break;
|
|
140
|
+
case DrawMode.LineSegments:
|
|
141
|
+
new_object = new LineSegments(this.mesh.geometry, this.mesh.material);
|
|
142
|
+
break;
|
|
143
|
+
|
|
144
|
+
default:
|
|
145
|
+
throw new Error(`Unsupported DrawMode '${this.__draw_mode}'`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
new_object.matrixAutoUpdate = false;
|
|
149
|
+
new_object.frustumCulled = false;
|
|
150
|
+
new_object.matrixWorldNeedsUpdate = false;
|
|
151
|
+
|
|
152
|
+
if (this.mesh !== null) {
|
|
153
|
+
new_object.castShadow = this.mesh.castShadow;
|
|
154
|
+
new_object.receiveShadow = this.mesh.receiveShadow;
|
|
155
|
+
|
|
156
|
+
new_object.customDepthMaterial = this.mesh.customDepthMaterial;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this.mesh = new_object;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
*
|
|
164
|
+
* @param {DrawMode} v
|
|
165
|
+
*/
|
|
166
|
+
set draw_mode(v) {
|
|
167
|
+
if (v === this.__draw_mode) {
|
|
168
|
+
// no change
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.__draw_mode = v;
|
|
173
|
+
|
|
174
|
+
this.__build_mesh();
|
|
175
|
+
|
|
115
176
|
}
|
|
116
177
|
|
|
117
178
|
/**
|
|
@@ -128,6 +189,10 @@ export class InstancedMeshGroup {
|
|
|
128
189
|
if (this.__attributeTransform !== null) {
|
|
129
190
|
this.__attributeTransform.setUsage(v);
|
|
130
191
|
}
|
|
192
|
+
|
|
193
|
+
if (this.__attributeColor !== null) {
|
|
194
|
+
this.__attributeColor.setUsage(v);
|
|
195
|
+
}
|
|
131
196
|
}
|
|
132
197
|
|
|
133
198
|
/**
|
|
@@ -254,10 +319,41 @@ export class InstancedMeshGroup {
|
|
|
254
319
|
this.__attributeTransformArray.set(transform, index * 16);
|
|
255
320
|
}
|
|
256
321
|
|
|
322
|
+
/**
|
|
323
|
+
*
|
|
324
|
+
* @param {number} index
|
|
325
|
+
* @param {number[]|ArrayLike<number>|Float32Array} color RGBA color in uint8 format (0...255), LDR
|
|
326
|
+
*/
|
|
327
|
+
setColorAt(index, color) {
|
|
328
|
+
this.__attributeColorArray.set(color, index * 4);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
*
|
|
333
|
+
* @param {number} index
|
|
334
|
+
* @param {number} r
|
|
335
|
+
* @param {number} g
|
|
336
|
+
* @param {number} b
|
|
337
|
+
* @param {number} a
|
|
338
|
+
*/
|
|
339
|
+
setColorByComponentAt(index, r, g, b, a) {
|
|
340
|
+
const color_array = this.__attributeColorArray;
|
|
341
|
+
|
|
342
|
+
const i4 = index * 4;
|
|
343
|
+
|
|
344
|
+
color_array[i4] = r;
|
|
345
|
+
color_array[i4 + 1] = g;
|
|
346
|
+
color_array[i4 + 2] = b;
|
|
347
|
+
color_array[i4 + 3] = a;
|
|
348
|
+
}
|
|
349
|
+
|
|
257
350
|
requestAttributeUpdate() {
|
|
258
351
|
this.__attributeTransform.needsUpdate = true;
|
|
259
|
-
}
|
|
260
352
|
|
|
353
|
+
if (this.__attributeColor !== null) {
|
|
354
|
+
this.__attributeColor.needsUpdate = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
261
357
|
|
|
262
358
|
/**
|
|
263
359
|
* Swap position in attribute arrays of two elements
|
|
@@ -356,6 +452,13 @@ export class InstancedMeshGroup {
|
|
|
356
452
|
a_transform.array.copyWithin(index * 16, lastIndex * 16, lastIndex * 16 + 16);
|
|
357
453
|
a_transform.needsUpdate = true;
|
|
358
454
|
|
|
455
|
+
const a_color = this.__attributeColor;
|
|
456
|
+
|
|
457
|
+
if (a_color !== null) {
|
|
458
|
+
a_color.array.copyWithin(index * 4, lastIndex * 4, lastIndex * 4 + 4);
|
|
459
|
+
a_color.needsUpdate = true;
|
|
460
|
+
}
|
|
461
|
+
|
|
359
462
|
|
|
360
463
|
//update moved reference index
|
|
361
464
|
const movedReference = references[lastIndex];
|
|
@@ -422,6 +525,30 @@ export class InstancedMeshGroup {
|
|
|
422
525
|
//add attributes to newly created geometry
|
|
423
526
|
geometry.setAttribute("instanceMatrix", this.__attributeTransform);
|
|
424
527
|
|
|
528
|
+
if (this.use_color) {
|
|
529
|
+
|
|
530
|
+
// color attribute
|
|
531
|
+
const newColorArray = new Uint8Array(this.capacity * 4);
|
|
532
|
+
|
|
533
|
+
if (this.__attributeColor !== null) {
|
|
534
|
+
const oldColorArray = this.__attributeColor.array;
|
|
535
|
+
typed_array_copy(oldColorArray, newColorArray);
|
|
536
|
+
|
|
537
|
+
if (newColorArray.length > oldColorArray.length) {
|
|
538
|
+
newColorArray.fill(255, oldColorArray.length);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
this.__attributeColorArray = newColorArray;
|
|
543
|
+
this.__attributeColor = new InstancedBufferAttribute(newColorArray, 4);
|
|
544
|
+
this.__attributeColor.normalized = true;
|
|
545
|
+
this.__attributeColor.setUsage(this.__instanceUsage);
|
|
546
|
+
|
|
547
|
+
geometry.setAttribute("instanceColor", this.__attributeColor);
|
|
548
|
+
} else {
|
|
549
|
+
this.__attributeColorArray = null;
|
|
550
|
+
this.__attributeColor = null;
|
|
551
|
+
}
|
|
425
552
|
|
|
426
553
|
this.mesh.geometry = geometry;
|
|
427
554
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const SHADER_PREAMBLE = `
|
|
2
|
+
#define USE_COLOR_ALPHA
|
|
3
|
+
#define USE_INSTANCING_COLOR
|
|
4
|
+
|
|
2
5
|
attribute mat4 instanceMatrix;
|
|
6
|
+
attribute vec4 instanceColor;
|
|
3
7
|
\n`;
|
|
4
8
|
|
|
5
9
|
export function rewriteMaterial(shader) {
|
|
@@ -28,7 +32,22 @@ export function rewriteMaterial(shader) {
|
|
|
28
32
|
vec3 objectTangent = vec3( tangent.xyz );
|
|
29
33
|
#endif
|
|
30
34
|
`
|
|
31
|
-
)
|
|
35
|
+
)
|
|
36
|
+
.replace(
|
|
37
|
+
'#include <color_vertex>',
|
|
38
|
+
`
|
|
39
|
+
#if defined( USE_COLOR_ALPHA )
|
|
40
|
+
vColor = instanceColor;
|
|
41
|
+
#else
|
|
42
|
+
vColor = instanceColor.xyz;
|
|
43
|
+
#endif
|
|
44
|
+
`
|
|
45
|
+
);
|
|
32
46
|
|
|
33
47
|
shader.vertexShader = newVertexShader;
|
|
48
|
+
|
|
49
|
+
shader.fragmentShader = `
|
|
50
|
+
#define USE_COLOR_ALPHA
|
|
51
|
+
#define USE_INSTANCING_COLOR
|
|
52
|
+
`+shader.fragmentShader;
|
|
34
53
|
}
|
|
@@ -2,6 +2,9 @@ import { ConicRay } from "../../../../core/geom/ConicRay.js";
|
|
|
2
2
|
import { vec4 } from "gl-matrix";
|
|
3
3
|
import { assert } from "../../../../core/assert.js";
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
const EMPTY_ARRAY_UINT8 = new Uint8Array(0);
|
|
7
|
+
|
|
5
8
|
/**
|
|
6
9
|
* Patches are organized into a tree hierarchy
|
|
7
10
|
*/
|
|
@@ -97,7 +100,7 @@ export class MicronGeometryPatch {
|
|
|
97
100
|
*
|
|
98
101
|
* @type {Uint8Array|Uint16Array|null}
|
|
99
102
|
*/
|
|
100
|
-
this.face_indices =
|
|
103
|
+
this.face_indices = EMPTY_ARRAY_UINT8;
|
|
101
104
|
|
|
102
105
|
/**
|
|
103
106
|
* Bounding cone of all of the face normals
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { deserialize_geometry_collection, serialize_geometry_collection } from "./geometry_collection_serialization.js";
|
|
2
2
|
import { BinaryBuffer } from "../../../../../../core/binary/BinaryBuffer.js";
|
|
3
|
+
import { MicronGeometry } from "../../MicronGeometry.js";
|
|
4
|
+
import { MicronGeometryPatch } from "../../MicronGeometryPatch.js";
|
|
5
|
+
|
|
6
|
+
function sample_geo() {
|
|
7
|
+
|
|
8
|
+
const geometry = new MicronGeometry();
|
|
9
|
+
|
|
10
|
+
geometry.root = new MicronGeometryPatch();
|
|
11
|
+
geometry.patches.push(geometry.root);
|
|
12
|
+
|
|
13
|
+
return geometry;
|
|
14
|
+
}
|
|
3
15
|
|
|
4
16
|
test('serialize empty', () => {
|
|
5
17
|
const bb = new BinaryBuffer();
|
|
@@ -22,3 +34,18 @@ test('serialize/deserialize empty', () => {
|
|
|
22
34
|
|
|
23
35
|
expect(destination.length).toBe(0);
|
|
24
36
|
});
|
|
37
|
+
|
|
38
|
+
test('serialize/deserialize 1', () => {
|
|
39
|
+
const bb = new BinaryBuffer();
|
|
40
|
+
|
|
41
|
+
const geometry = sample_geo();
|
|
42
|
+
|
|
43
|
+
serialize_geometry_collection([geometry], bb);
|
|
44
|
+
|
|
45
|
+
bb.position = 0;
|
|
46
|
+
|
|
47
|
+
const destination = [];
|
|
48
|
+
deserialize_geometry_collection(destination, bb);
|
|
49
|
+
|
|
50
|
+
expect(destination.length).toBe(1);
|
|
51
|
+
});
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { EnginePlugin } from "../../../plugin/EnginePlugin.js";
|
|
2
|
+
import { Gizmo } from "./Gizmo.js";
|
|
2
3
|
|
|
3
4
|
export class GizmoRenderingPlugin extends EnginePlugin {
|
|
5
|
+
async startup() {
|
|
6
|
+
this.__layer = this.engine.graphics.layers.create('debug');
|
|
7
|
+
|
|
8
|
+
this.__layer.buildVisibleSet = (destination, destination_offset, view) => {
|
|
9
|
+
return Gizmo.collect(destination, destination_offset, view);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
this.engine.graphics.on.postRender.add(Gizmo.clear, Gizmo);
|
|
13
|
+
|
|
14
|
+
return super.startup();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async shutdown() {
|
|
18
|
+
this.engine.graphics.layers.remove(this.__layer);
|
|
19
|
+
|
|
20
|
+
this.engine.graphics.on.postRender.remove(Gizmo.clear, Gizmo);
|
|
21
|
+
|
|
22
|
+
return super.shutdown();
|
|
23
|
+
}
|
|
4
24
|
|
|
5
25
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
2
2
|
import { assert } from "../../../../core/assert.js";
|
|
3
3
|
import { InstancedMeshGroup } from "../../geometry/instancing/InstancedMeshGroup.js";
|
|
4
|
-
import { BoxBufferGeometry, MeshBasicMaterial } from "three";
|
|
4
|
+
import { BoxBufferGeometry, LineBasicMaterial, MeshBasicMaterial, OctahedronBufferGeometry } from "three";
|
|
5
5
|
import { compose_matrix4_array } from "../../../../core/geom/3d/compose_matrix4_array.js";
|
|
6
6
|
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
7
7
|
import Quaternion from "../../../../core/geom/Quaternion.js";
|
|
8
|
+
import { makeHelperBoxGeometry } from "../../../../editor/process/symbolic/makeHelperBoxGeometry.js";
|
|
9
|
+
import { DrawMode } from "../../ecs/mesh-v2/DrawMode.js";
|
|
10
|
+
import { makeHelperSphereGeometry } from "../../../../editor/process/symbolic/makeHelperSphereGeometry.js";
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
*
|
|
@@ -12,6 +15,27 @@ import Quaternion from "../../../../core/geom/Quaternion.js";
|
|
|
12
15
|
*/
|
|
13
16
|
const scratch_m4 = [];
|
|
14
17
|
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @param {InstancedMeshGroup} group
|
|
21
|
+
* @param {number[]} matrix
|
|
22
|
+
* @param {number[]} color
|
|
23
|
+
*/
|
|
24
|
+
function add_instance(group, matrix, color) {
|
|
25
|
+
const i = group.count;
|
|
26
|
+
|
|
27
|
+
group.setCount(i + 1);
|
|
28
|
+
group.setTransformAt(i, matrix);
|
|
29
|
+
|
|
30
|
+
group.setColorByComponentAt(
|
|
31
|
+
i,
|
|
32
|
+
Math.round(color[0] * 255),
|
|
33
|
+
Math.round(color[1] * 255),
|
|
34
|
+
Math.round(color[2] * 255),
|
|
35
|
+
Math.round(color[3] * 255)
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
15
39
|
export class GizmoShapeRenderingInterface {
|
|
16
40
|
constructor() {
|
|
17
41
|
|
|
@@ -23,6 +47,50 @@ export class GizmoShapeRenderingInterface {
|
|
|
23
47
|
this.__color = [1, 1, 1, 1];
|
|
24
48
|
|
|
25
49
|
this.__boxes_solid = InstancedMeshGroup.from(new BoxBufferGeometry(), new MeshBasicMaterial());
|
|
50
|
+
this.__boxes_wire = InstancedMeshGroup.from(makeHelperBoxGeometry(), new LineBasicMaterial());
|
|
51
|
+
|
|
52
|
+
this.__boxes_wire.draw_mode = DrawMode.LineSegments;
|
|
53
|
+
|
|
54
|
+
this.__sphere_solid = InstancedMeshGroup.from(new OctahedronBufferGeometry(1, 10), new MeshBasicMaterial());
|
|
55
|
+
this.__sphere_wire = InstancedMeshGroup.from(makeHelperSphereGeometry(), new LineBasicMaterial());
|
|
56
|
+
|
|
57
|
+
this.__sphere_wire.draw_mode = DrawMode.Lines;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
__get_groups() {
|
|
61
|
+
return [
|
|
62
|
+
this.__boxes_wire,
|
|
63
|
+
this.__boxes_solid,
|
|
64
|
+
this.__sphere_wire,
|
|
65
|
+
this.__sphere_solid
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
*
|
|
71
|
+
* @param {THREE.Object3D[]} destination
|
|
72
|
+
* @param {number} destination_offset
|
|
73
|
+
* @param {number[]} frustum
|
|
74
|
+
*/
|
|
75
|
+
collect(destination, destination_offset, frustum) {
|
|
76
|
+
let i = destination_offset;
|
|
77
|
+
|
|
78
|
+
const groups = this.__get_groups();
|
|
79
|
+
|
|
80
|
+
for (let j = 0; j < groups.length; j++) {
|
|
81
|
+
destination[i++] = groups[j].mesh;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return i - destination_offset;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
clear() {
|
|
88
|
+
const groups = this.__get_groups();
|
|
89
|
+
|
|
90
|
+
for (let j = 0; j < groups.length; j++) {
|
|
91
|
+
groups[j].setCount(0);
|
|
92
|
+
}
|
|
93
|
+
|
|
26
94
|
}
|
|
27
95
|
|
|
28
96
|
/**
|
|
@@ -44,10 +112,7 @@ export class GizmoShapeRenderingInterface {
|
|
|
44
112
|
*/
|
|
45
113
|
draw_solid_cube(center, size) {
|
|
46
114
|
compose_matrix4_array(scratch_m4, Vector3.fromArray(center), Quaternion.identity, Vector3.fromArray(size));
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.__boxes_solid.setCount(i + 1);
|
|
50
|
-
this.__boxes_solid.setTransformAt(i, scratch_m4);
|
|
115
|
+
add_instance(this.__boxes_solid, scratch_m4, this.__color);
|
|
51
116
|
}
|
|
52
117
|
|
|
53
118
|
/**
|
|
@@ -56,7 +121,8 @@ export class GizmoShapeRenderingInterface {
|
|
|
56
121
|
* @param {number[]} size
|
|
57
122
|
*/
|
|
58
123
|
draw_wire_cube(center, size) {
|
|
59
|
-
|
|
124
|
+
compose_matrix4_array(scratch_m4, Vector3.fromArray(center), Quaternion.identity, Vector3.fromArray(size));
|
|
125
|
+
add_instance(this.__boxes_wire, scratch_m4, this.__color);
|
|
60
126
|
}
|
|
61
127
|
|
|
62
128
|
/**
|
|
@@ -65,7 +131,7 @@ export class GizmoShapeRenderingInterface {
|
|
|
65
131
|
* @param {number[]} to
|
|
66
132
|
*/
|
|
67
133
|
draw_line(from, to) {
|
|
68
|
-
|
|
134
|
+
throw new Error('Not Implemented');
|
|
69
135
|
}
|
|
70
136
|
|
|
71
137
|
|
|
@@ -75,7 +141,8 @@ export class GizmoShapeRenderingInterface {
|
|
|
75
141
|
* @param {number} radius
|
|
76
142
|
*/
|
|
77
143
|
draw_solid_sphere(center, radius) {
|
|
78
|
-
|
|
144
|
+
compose_matrix4_array(scratch_m4, Vector3.fromArray(center), Quaternion.identity, Vector3.fromScalar(radius));
|
|
145
|
+
add_instance(this.__sphere_solid, scratch_m4, this.__color);
|
|
79
146
|
}
|
|
80
147
|
|
|
81
148
|
/**
|
|
@@ -83,8 +150,9 @@ export class GizmoShapeRenderingInterface {
|
|
|
83
150
|
* @param {number[]} center
|
|
84
151
|
* @param {number} radius
|
|
85
152
|
*/
|
|
86
|
-
draw_wire_sphere() {
|
|
87
|
-
|
|
153
|
+
draw_wire_sphere(center, radius) {
|
|
154
|
+
compose_matrix4_array(scratch_m4, Vector3.fromArray(center), Quaternion.identity, Vector3.fromScalar(radius));
|
|
155
|
+
add_instance(this.__sphere_wire, scratch_m4, this.__color);
|
|
88
156
|
}
|
|
89
157
|
}
|
|
90
158
|
|
|
@@ -4,8 +4,12 @@ import { compareNumbersAscending } from "../../../../core/function/Functions.js"
|
|
|
4
4
|
test('set is sorted after insert, push 1,2', () => {
|
|
5
5
|
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
6
6
|
|
|
7
|
+
set.initializeUpdate();
|
|
8
|
+
|
|
7
9
|
set.push(1);
|
|
8
|
-
set.push(2)
|
|
10
|
+
set.push(2)
|
|
11
|
+
|
|
12
|
+
set.finalizeUpdate();
|
|
9
13
|
|
|
10
14
|
expect(set.elements[0]).toBe(1);
|
|
11
15
|
expect(set.elements[1]).toBe(2);
|
|
@@ -14,9 +18,13 @@ test('set is sorted after insert, push 1,2', () => {
|
|
|
14
18
|
test('set is sorted after insert, push 2,1', () => {
|
|
15
19
|
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
16
20
|
|
|
21
|
+
set.initializeUpdate();
|
|
22
|
+
|
|
17
23
|
set.push(2);
|
|
18
24
|
set.push(1);
|
|
19
25
|
|
|
26
|
+
set.finalizeUpdate();
|
|
27
|
+
|
|
20
28
|
expect(set.elements[0]).toBe(1);
|
|
21
29
|
expect(set.elements[1]).toBe(2);
|
|
22
30
|
});
|
|
@@ -24,10 +32,14 @@ test('set is sorted after insert, push 2,1', () => {
|
|
|
24
32
|
test('set is sorted after insert, push 1,2,3', () => {
|
|
25
33
|
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
26
34
|
|
|
35
|
+
set.initializeUpdate();
|
|
36
|
+
|
|
27
37
|
set.push(1);
|
|
28
38
|
set.push(2);
|
|
29
39
|
set.push(3);
|
|
30
40
|
|
|
41
|
+
set.finalizeUpdate();
|
|
42
|
+
|
|
31
43
|
expect(set.elements[0]).toBe(1);
|
|
32
44
|
expect(set.elements[1]).toBe(2);
|
|
33
45
|
expect(set.elements[2]).toBe(3);
|
|
@@ -36,10 +48,14 @@ test('set is sorted after insert, push 1,2,3', () => {
|
|
|
36
48
|
test('set is sorted after insert, push 3,2,1', () => {
|
|
37
49
|
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
38
50
|
|
|
51
|
+
set.initializeUpdate();
|
|
52
|
+
|
|
39
53
|
set.push(3);
|
|
40
54
|
set.push(2);
|
|
41
55
|
set.push(1);
|
|
42
56
|
|
|
57
|
+
set.finalizeUpdate();
|
|
58
|
+
|
|
43
59
|
expect(set.elements[0]).toBe(1);
|
|
44
60
|
expect(set.elements[1]).toBe(2);
|
|
45
61
|
expect(set.elements[2]).toBe(3);
|
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.37.
|
|
8
|
+
"version": "2.37.16",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|