@woosh/meep-engine 2.33.37 → 2.33.41

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.
Files changed (46) hide show
  1. package/core/bvh2/binary/2/BinaryUint32BVH.js +3 -3
  2. package/core/collection/array/typed/typed_array_copy.js +2 -2
  3. package/core/geom/3d/aabb/aabb3_matrix4_project_by_corners.js +1 -1
  4. package/core/geom/3d/morton/mortonEncode_magicbits.js +7 -6
  5. package/core/geom/3d/morton/v3_morton_encode_transformed.js +15 -11
  6. package/core/geom/3d/plane/orient3d_fast.js +15 -9
  7. package/core/geom/3d/tetrahedra/GetDepthForTetrahedronProbe.glsl +43 -0
  8. package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.js +20 -169
  9. package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.spec.js +9 -0
  10. package/core/geom/3d/tetrahedra/tetrahedra_collection.js +454 -0
  11. package/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +2 -1
  12. package/core/process/undo/ActionProcessor.js +8 -5
  13. package/engine/asset/loaders/GLTFAssetLoader.js +4 -8
  14. package/engine/ecs/System.d.ts +24 -1
  15. package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +1 -1
  16. package/engine/graphics/micron/prototypeVirtualGeometry.js +4 -1
  17. package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +20 -24
  18. package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +1 -1
  19. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -2
  20. package/engine/graphics/render/buffer/simple-fx/DepthLimitedBlur.js +9 -4
  21. package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +7 -1
  22. package/engine/graphics/render/forward_plus/LightManager.js +295 -51
  23. package/engine/graphics/render/forward_plus/LightManager.spec.js +1 -1
  24. package/engine/graphics/render/forward_plus/PointLightData.js +9 -13
  25. package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +10 -1
  26. package/engine/graphics/render/forward_plus/debug/LightClusterVolumeMaterial.js +1 -1
  27. package/engine/graphics/render/forward_plus/debug/buildLightClusterWidget.js +3 -1
  28. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +31 -18
  29. package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +1 -0
  30. package/engine/graphics/render/forward_plus/model/AbstractLight.js +50 -0
  31. package/engine/graphics/render/forward_plus/model/Decal.js +68 -0
  32. package/engine/graphics/render/forward_plus/{PointLight.js → model/PointLight.js} +19 -11
  33. package/engine/graphics/render/forward_plus/{SpotLight.js → model/SpotLight.js} +20 -12
  34. package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +6 -5
  35. package/engine/graphics/render/forward_plus/{prototypeLightManager.js → prototype/prototypeLightManager.js} +100 -25
  36. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +29 -20
  37. package/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts +2 -0
  38. package/engine/graphics/render/visibility/IncrementalDeltaSet.js +1 -0
  39. package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +19 -0
  40. package/engine/graphics/texture/atlas/CachingTextureAtlas.js +99 -0
  41. package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +19 -39
  42. package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +75 -0
  43. package/engine/graphics/texture/atlas/TextureAtlas.js +22 -2
  44. package/engine/reference/v2/Reference.d.ts +4 -0
  45. package/engine/reference/v2/Reference.js +3 -1
  46. package/package.json +1 -1
@@ -434,11 +434,11 @@ export class BinaryUint32BVH {
434
434
  * Assemble leaf nodes into hierarchy, set binary node bounds iteratively bottom up
435
435
  */
436
436
  build() {
437
- const nodeCount = this.__node_count_binary;
437
+ const binary_node_count = this.__node_count_binary;
438
438
 
439
- const leaf_node_block_address = this.__node_count_binary * BVH_BINARY_NODE_SIZE;
439
+ const leaf_node_block_address = binary_node_count * BVH_BINARY_NODE_SIZE;
440
440
 
441
- let level = Math.floor(Math.log(nodeCount) / Math.log(2));
441
+ let level = Math.floor(Math.log(binary_node_count) / Math.log(2));
442
442
 
443
443
  let i, offset, level_node_count;
444
444
  //NOTE: building first level separately allows to avoid some switching logic needed to determine what is the type of lower level node
@@ -3,8 +3,8 @@ import { array_copy } from "../copyArray.js";
3
3
 
4
4
  /**
5
5
  * Assumes arrays have the same type
6
- * @param {TypedArray|Float32Array} source
7
- * @param {TypedArray|Float32Array} destination
6
+ * @param {TypedArray|Float32Array|Uint8Array} source
7
+ * @param {TypedArray|Float32Array|Uint8Array} destination
8
8
  */
9
9
  export function typed_array_copy(source, destination) {
10
10
  const destination_size = destination.length;
@@ -4,7 +4,7 @@ import { assert } from "../../../assert.js";
4
4
  *
5
5
  * @param {number[]|Float32Array} result
6
6
  * @param {number[]|Float32Array|Float64Array} aabb_corners
7
- * @param {number[]|Float32Array} projection_matrix
7
+ * @param {number[]|Float32Array|mat4} projection_matrix
8
8
  */
9
9
  export function aabb3_matrix4_project_by_corners(result, aabb_corners, projection_matrix) {
10
10
  assert.greaterThanOrEqual(result.length, 6, 'result.length must >= 6');
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * method to separate bits from a given integer 3 positions apart
3
3
  * we only look at the first 10 bits
4
+ *
5
+ * @example when input is ABC, output bits are A00B00C
4
6
  * @param {number} a
5
7
  * @returns {number}
6
8
  */
7
- function splitBy3(a) {
9
+ function split_by_3(a) {
8
10
  let x = a;
9
11
  x = (x | x << 16) & 0x30000ff;
10
12
  x = (x | x << 8) & 0x0300f00f;
@@ -25,10 +27,9 @@ function splitBy3(a) {
25
27
  */
26
28
  export function mortonEncode_magicbits(x, y, z) {
27
29
 
28
- const x_bits = splitBy3(x);
29
- const y_bits = splitBy3(y) << 1;
30
- const z_bit = splitBy3(z) << 2;
31
-
32
- return x_bits | y_bits | z_bit;
30
+ const x_bits = split_by_3(x);
31
+ const y_bits = split_by_3(y) << 1;
32
+ const z_bits = split_by_3(z) << 2;
33
33
 
34
+ return x_bits | y_bits | z_bits;
34
35
  }
@@ -1,4 +1,5 @@
1
1
  import { mortonEncode_magicbits } from "./mortonEncode_magicbits.js";
2
+ import { clamp } from "../../../math/clamp.js";
2
3
 
3
4
  /**
4
5
  * Assumes that coordinates will be mapped to -1..1 range after transform
@@ -16,18 +17,21 @@ export function v3_morton_encode_transformed(x, y, z, matrix) {
16
17
  const _z = matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14];
17
18
  const _w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
18
19
 
19
- const d = 1 / _w;
20
+ const d = 511.5 / _w;
20
21
 
21
- // apply perspective divide, values are now in Normalized Coordinate system (-1,1)
22
- const px = _x * d;
23
- const py = _y * d;
24
- const pz = _z * d;
22
+ // apply perspective divide as well as scaling to 10 bits
23
+ const ndc_x = _x * d;
24
+ const ndc_y = _y * d;
25
+ const ndc_z = _z * d;
25
26
 
26
- // scale each value up to 10 bits (for 10 bits, the multiplier = 1024. As we have -1,1 range, we do (v+1)/2. 1024/2 = 512)
27
+ // Normalize values (0,1023) and clamp to prevent wrapping
28
+ const px = clamp(ndc_x + 511.5, 0, 1023);
29
+ const py = clamp(ndc_y + 511.5, 0, 1023);
30
+ const pz = clamp(ndc_z + 511.5, 0, 1023);
27
31
 
28
- const cx = ((px + 1) * 512) | 0;
29
- const cy = ((py + 1) * 512) | 0;
30
- const cz = ((pz + 1) * 512) | 0;
31
-
32
- return mortonEncode_magicbits(cx, cy, cz);
32
+ return mortonEncode_magicbits(
33
+ Math.round(px),
34
+ Math.round(py),
35
+ Math.round(pz)
36
+ );
33
37
  }
@@ -21,23 +21,29 @@ export function orient3d_fast(points, a, b, c, d) {
21
21
  const a3 = a * 3;
22
22
  const d3 = d * 3;
23
23
 
24
- const adx = points[a3] - points[d3];
24
+ const d_x = points[d3];
25
+
26
+ const adx = points[a3] - d_x;
25
27
 
26
28
  const b3 = b * 3;
27
29
 
28
- const bdx = points[b3] - points[d3];
30
+ const bdx = points[b3] - d_x;
29
31
 
30
32
  const c3 = c * 3;
31
33
 
32
- const cdx = points[c3] - points[d3];
34
+ const cdx = points[c3] - d_x;
35
+
36
+ const d_y = points[d3 + 1];
37
+
38
+ const ady = points[a3 + 1] - d_y;
39
+ const bdy = points[b3 + 1] - d_y;
40
+ const cdy = points[c3 + 1] - d_y;
33
41
 
34
- const ady = points[a3 + 1] - points[d3 + 1];
35
- const bdy = points[b3 + 1] - points[d3 + 1];
36
- const cdy = points[c3 + 1] - points[d3 + 1];
42
+ const d_z = points[d3 + 2];
37
43
 
38
- const adz = points[a3 + 2] - points[d3 + 2];
39
- const bdz = points[b3 + 2] - points[d3 + 2];
40
- const cdz = points[c3 + 2] - points[d3 + 2];
44
+ const adz = points[a3 + 2] - d_z;
45
+ const bdz = points[b3 + 2] - d_z;
46
+ const cdz = points[c3 + 2] - d_z;
41
47
 
42
48
  return adx * (bdy * cdz - bdz * cdy)
43
49
  + bdx * (cdy * adz - cdz * ady)
@@ -0,0 +1,43 @@
1
+ // Sample triangular depth map
2
+ // see CoD SIGGRAPH 2017 "Advances in Real-Time Graphics in Games" course
3
+ float GetDepthForTetrahedronProbe(float2 bary, uint4 encodedDepth)
4
+ {
5
+ float sampleY = floor(bary.y * 4.0f);
6
+ float sampleX = floor(bary.x * 4.0f);
7
+
8
+ int baseIndex = (int)(((11.0f - sampleY) * sampleY) * 0.5f + sampleX + 0.5f);
9
+ int lineLength = 5 - (int)sampleY;
10
+
11
+ float2 baseBary = float2(sampleX * 0.25f, sampleY * 0.25f);
12
+
13
+ int3 indices = int3(baseIndex + 1, baseIndex + lineLength, baseIndex);
14
+
15
+ float3 sampleBary;
16
+ sampleBary.x = (bary.x - baseBary.x) * 4.0f;
17
+ sampleBary.y = (bary.y - baseBary.y) * 4.0f;
18
+
19
+ if (sampleBary.x + sampleBary.y > 1.0f)
20
+ {
21
+ // above the diagonal
22
+ indices = int3(baseIndex + lineLength, baseIndex + 1, baseIndex + lineLength + 1);
23
+
24
+ float3 newSampleBary;
25
+ newSampleBary.x = -(sampleBary.y - 1.0f);
26
+ newSampleBary.y = -(sampleBary.x - 1.0f);
27
+ sampleBary = newSampleBary;
28
+ }
29
+
30
+ sampleBary.z = 1.0f - sampleBary.x - sampleBary.y;
31
+
32
+ float result = 0.0f;
33
+ for (int i=0; i<3; ++i)
34
+ {
35
+ uint currIndex = indices[i];
36
+ int intDepth = (encodedDepth[currIndex / 4] >> ((currIndex % 4) * 8)) & 0xFF;
37
+ float depth = (float)intDepth / 255.0f;
38
+
39
+ result += sampleBary[i] * depth;
40
+ }
41
+
42
+ return result;
43
+ }
@@ -1,199 +1,50 @@
1
1
  //
2
2
 
3
3
  import { compute_bounding_simplex_3d } from "./compute_bounding_simplex_3d.js";
4
- import { point_in_tetrahedron_circumsphere } from "./point_in_tetrahedron_circumsphere.js";
5
- import { tetrahedron_contains_point } from "./tetrahedron_contains_point.js";
6
- import { assert } from "../../../assert.js";
7
-
8
- /**
9
- * @readonly
10
- * @type {number}
11
- */
12
- const LAYOUT_TETRA_BYTE_SIZE = 9 * 4;
13
- const INVALID_NEIGHBOUR = 0xFFFFFFFF;
14
-
15
- /**
16
- *
17
- * Layout:
18
- * vertex_id_a :: uint
19
- * vertex_id_b :: uint
20
- * vertex_id_c :: uint
21
- * vertex_id_d :: uint
22
- * neighbour_a :: uint - neighbour tetrahedron, opposite to vertex A
23
- * neighbour_b :: uint - neighbour tetrahedron, opposite to vertex B
24
- * neighbour_c :: uint - neighbour tetrahedron, opposite to vertex C
25
- * neighbour_d :: uint - neighbour tetrahedron, opposite to vertex D
26
- * sub_determinant :: float - ?
27
- * Layout is similar to [1], but is interleaved for better cache locality
28
- */
29
- class TetrahedraCollection {
30
- constructor(initial_size) {
31
- this.__buffer = new ArrayBuffer(initial_size * 4 * 9);
32
-
33
- this.__view = new DataView(this.__buffer);
34
-
35
- this.__capacity = initial_size;
36
- this.__length = 0;
37
- }
38
-
39
- /**
40
- *
41
- * @param {number} tetra_index
42
- * @param {number} neighbour_index
43
- * @returns {number}
44
- */
45
- getNeighbour(tetra_index, neighbour_index) {
46
- const tetra_address = LAYOUT_TETRA_BYTE_SIZE * tetra_index;
47
- return this.__view.getUint32(tetra_address + (4 + neighbour_index) * 4);
48
- }
49
-
50
- /**
51
- *
52
- * @param {number[]|Float32Array} points
53
- * @param {number} a
54
- * @param {number} b
55
- * @param {number} c
56
- * @param {number} d
57
- */
58
- append(points, a, b, c, d) {
59
- const address = this.__length * LAYOUT_TETRA_BYTE_SIZE;
60
-
61
- // TODO check if there's enough room
62
-
63
- const view = this.__view;
64
-
65
- view.setUint32(address, a);
66
- view.setUint32(address + 4, b);
67
- view.setUint32(address + 8, c);
68
- view.setUint32(address + 12, d);
69
-
70
- // set neighbours
71
- view.setUint32(address + 16, INVALID_NEIGHBOUR);
72
- view.setUint32(address + 20, INVALID_NEIGHBOUR);
73
- view.setUint32(address + 24, INVALID_NEIGHBOUR);
74
- view.setUint32(address + 28, INVALID_NEIGHBOUR);
75
-
76
- this.__length++;
77
- }
78
-
79
- /**
80
- *
81
- * @param {number[]} points
82
- * @param {number} index
83
- * @returns {number} index of tetra or -1 if no containing tetra found
84
- */
85
- findTetraContainingPoint(points, index) {
86
- const data_view = this.__view;
87
-
88
- // TODO improve this
89
- const n = this.__length;
90
- for (let i = 0; i < n; i++) {
91
-
92
- const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
93
-
94
- const a = data_view.getUint32(tet_address);
95
- const b = data_view.getUint32(tet_address + 4);
96
- const c = data_view.getUint32(tet_address + 8);
97
- const d = data_view.getUint32(tet_address + 12);
98
-
99
- if (tetrahedron_contains_point(points, a, b, c, d, index)) {
100
- return i;
101
- }
102
- }
103
-
104
- return -1;
105
- }
106
-
107
- /**
108
- *
109
- * @param {number[]|Float32Array} points
110
- * @param {number} index
111
- */
112
- insertPoint(points, index) {
113
-
114
- // 1. walk to tetrahedron that contains this point
115
- const containing_tetra = this.findTetraContainingPoint(points, index);
116
-
117
- assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
118
-
119
- const cavity = [];
120
- const open_set = [
121
- containing_tetra
122
- ];
123
-
124
- const data_view = this.__view;
125
-
126
- // 2. find the Delaunay "cavity", a set of tetrahedrons who's circumsphere overlarlaps the point
127
- // perform breadth-first expansion on the containing tetra to identify the cavity
128
- while (open_set.length > 0) {
129
- const tetra = open_set.pop();
130
- cavity.push(tetra);
131
-
132
- // get neighbours
133
- for (let i = 0; i < 4; i++) {
134
- const neighbour = this.getNeighbour(tetra, i);
135
-
136
- if (
137
- (neighbour === INVALID_NEIGHBOUR) // no neighbour
138
- || cavity.includes(neighbour) // already visited
139
- || open_set.includes(neighbour) // already in open set
140
- ) {
141
-
142
- continue;
143
- }
144
-
145
- const neighbour_address = neighbour * LAYOUT_TETRA_BYTE_SIZE;
146
- const a = data_view.getUint32(neighbour_address);
147
- const b = data_view.getUint32(neighbour_address + 4);
148
- const c = data_view.getUint32(neighbour_address + 8);
149
- const d = data_view.getUint32(neighbour_address + 12);
150
-
151
- // check neighbour
152
- const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, index);
153
-
154
- if (is_in_sphere) {
155
- open_set.push(neighbour);
156
- }
157
- }
158
- }
159
-
160
- // 3. remove the cavity tetrahedrons
161
-
162
- // 4. fill the cavity by creating new tetrahedrons connecting the point to the faces of cavity boundary
163
- }
164
- }
4
+ import { TetrahedraCollection } from "./tetrahedra_collection.js";
165
5
 
166
6
  /**
167
7
  * @see https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm
168
8
  * @see [1] "One machine, one minute, three billion tetrahedra" by Célestin Marot et al
169
9
  * @param {number[]} input serialized set of 3d points (x,y,z)
170
- * @param {number} input_point_count
10
+ * @param {number} n number of points in the input
171
11
  */
172
- export function compute_delaunay_tetrahedral_mesh(input, input_point_count) {
12
+ export function compute_delaunay_tetrahedral_mesh(input, n) {
13
+ if (n < 4) {
14
+ // no mesh can be created, too few points
15
+ return;
16
+ }
17
+
173
18
  /**
174
19
  * According to [1] number of tetrahedra is around 6 times greater than number of input vertices, we use that fact to pre-allocate memory
20
+ * From the book of Cheng et al. 'Delaunay Mesh Generation' A triangulation of n vertices in R^3 has at most `ntet=(n^2 − 3n − 2)/2` tetrahedra,
21
+ * at most nedg=(n^2 − n)/2` edges (this is simply the 2-combination of n)
22
+ * and at most `ntri=n^2 − 3n = 2*ntet+2` triangles
23
+ *
24
+ * The +7 is for the initial "super" tetrahedron and 6 tetras for intermediate triangulation
175
25
  */
176
- const tetrahedrons = new TetrahedraCollection(input_point_count * 6.01);
26
+ const tetrahedron_count_upper_bound = Math.ceil((n * n - 3 * n - 2) / 2) + 7;
27
+ const tetrahedrons = new TetrahedraCollection(tetrahedron_count_upper_bound);
177
28
  // TODO apply spatial sort to point, to get better cache locality
178
29
 
179
30
  // compute bounds over the input
180
- const points = new Float32Array((input_point_count + 4) * 3);
31
+ const points = new Float32Array((n + 4) * 3);
181
32
 
182
33
  points.set(input);
183
34
 
184
35
  /*
185
36
  create super bounding volume
186
37
  */
187
- compute_bounding_simplex_3d(points, input_point_count * 3, points, input_point_count, 1);
38
+ compute_bounding_simplex_3d(points, n * 3, points, n, 1);
188
39
 
189
- tetrahedrons.append(points, input_point_count, input_point_count + 1, input_point_count + 2, input_point_count + 3);
40
+ tetrahedrons.append(points, n, n + 1, n + 2, n + 3);
190
41
 
191
42
  // add all points to the mesh
192
- for (let i = 0; i < input_point_count; i++) {
43
+ for (let i = 0; i < n; i++) {
193
44
  tetrahedrons.insertPoint(points, i);
194
45
  }
195
46
 
196
47
  // remove tetras formed by with the super bounding volume
197
- // TODO implement
48
+ tetrahedrons.removeTetrasConnectedToPoints(points, n, n + 3);
198
49
  }
199
50
 
@@ -3,3 +3,12 @@ import { compute_delaunay_tetrahedral_mesh } from "./compute_delaunay_tetrahedra
3
3
  test('single point', () => {
4
4
  compute_delaunay_tetrahedral_mesh([1, 2, 3], 1);
5
5
  });
6
+
7
+ test('exactly 4 points', () => {
8
+ compute_delaunay_tetrahedral_mesh([
9
+ -1, 0, 0,
10
+ 1, 0, 0,
11
+ 0.5, 1, 0,
12
+ 0.5, 0, 1
13
+ ], 4);
14
+ });