@woosh/meep-engine 2.33.2 → 2.33.6

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 (98) hide show
  1. package/core/bvh2/aabb3/AABB3.js +18 -0
  2. package/core/bvh2/aabb3/aabb3_intersects_frustum.js +38 -0
  3. package/core/collection/RingBuffer.js +40 -10
  4. package/core/collection/array/copyArray.js +2 -2
  5. package/core/collection/array/typed/typed_array_copy.js +2 -2
  6. package/core/collection/table/RowFirstTableSpec.js +8 -0
  7. package/core/geom/3d/aabb/aabb3_compute_projected_area.js +16 -14
  8. package/core/geom/3d/aabb/aabb3_estimate_projected_area2.js +59 -0
  9. package/core/geom/3d/aabb/aabb3_matrix4_project.js +33 -0
  10. package/core/geom/3d/aabb/aabb3_matrix4_project.spec.js +41 -0
  11. package/core/geom/3d/plane/plane3_lerp.js +2 -2
  12. package/core/geom/3d/topology/TopoTriangle.js +2 -2
  13. package/core/geom/AABB2.d.ts +2 -0
  14. package/core/geom/Matrix4.js +4 -4
  15. package/core/geom/Vector3.js +5 -5
  16. package/core/model/reactive/model/terminal/ReactiveReference.js +7 -1
  17. package/core/process/undo/ActionProcessor.d.ts +2 -0
  18. package/core/process/undo/ActionProcessor.js +59 -1
  19. package/core/process/undo/ActionProcessor.spec.js +59 -0
  20. package/core/process/undo/Mark.js +2 -1
  21. package/engine/asset/loaders/GLTFAssetLoader.js +3 -3
  22. package/engine/asset/loaders/material/TextureAttachmensByMaterialType.js +11 -1
  23. package/engine/asset/loaders/material/TextureAttachment.js +12 -1
  24. package/engine/asset/loaders/material/bitmap2sampler_gl.js +19 -0
  25. package/engine/asset/loaders/material/computeImageBitmapEquality.js +7 -19
  26. package/engine/asset/loaders/material/computeTextureEquality.js +1 -1
  27. package/engine/asset/loaders/material/computeTextureHash.js +16 -14
  28. package/engine/asset/loaders/material/traverseMaterialTextures.js +2 -2
  29. package/engine/ecs/animation/OneBoneSurfaceAlignmentSolver.js +2 -2
  30. package/engine/ecs/animation/TwoBoneInverseKinematicsSolver.js +4 -4
  31. package/engine/graphics/GraphicsEngine.d.ts +2 -2
  32. package/engine/graphics/GraphicsEngine.js +20 -62
  33. package/engine/graphics/filter/FlipArrayInPlace.js +25 -0
  34. package/engine/graphics/filter/FlipArrayViaCanvas.js +13 -0
  35. package/engine/graphics/filter/ImageFilter.js +20 -51
  36. package/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +2 -2
  37. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +25 -16
  38. package/engine/graphics/material/SplatMaterial.js +4 -97
  39. package/engine/graphics/material/optimization/MaterialOptimizationContext.js +598 -0
  40. package/engine/graphics/micron/build/PatchRepresentation.js +4 -43
  41. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +4 -75
  42. package/engine/graphics/micron/build/compute_buffer_geometry_byte_size.js +16 -0
  43. package/engine/graphics/micron/build/fill_patch_geometry_data.js +2 -0
  44. package/engine/graphics/micron/format/MicronGeometryBufferAttributeSpec.js +1 -1
  45. package/engine/graphics/micron/format/MicronGeometryPatch.js +17 -5
  46. package/engine/graphics/micron/format/MicronVertexDataSpec.js +25 -3
  47. package/engine/graphics/micron/prototypeVirtualGeometry.js +19 -12
  48. package/engine/graphics/micron/render/VirtualGeometryBuilder.js +34 -27
  49. package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +2 -4
  50. package/engine/graphics/micron/render/instanced/PatchDataTextures.js +1 -0
  51. package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +1 -29
  52. package/engine/graphics/micron/render/refinement/ActivePatchList.js +43 -159
  53. package/engine/graphics/micron/render/refinement/ActivePatchRecord.js +4 -2
  54. package/engine/graphics/micron/render/refinement/RefinementSpec.js +98 -0
  55. package/engine/graphics/micron/render/refinement/array_normalize_plane.js +25 -0
  56. package/engine/graphics/micron/render/refinement/array_setFromProjectionMatrix.js +60 -0
  57. package/engine/graphics/micron/render/refinement/is_patch_facing_back.js +43 -0
  58. package/engine/graphics/micron/render/refinement/is_patch_visible.js +37 -0
  59. package/engine/graphics/micron/render/v1/MaterialVertexSpec.js +21 -0
  60. package/engine/graphics/micron/render/v1/VGThreeRenderer.js +12 -9
  61. package/engine/graphics/micron/util/unit_hemioct.spec.js +2 -2
  62. package/engine/graphics/render/buffer/buffers/ColorAndDepthFrameBuffer.js +5 -3
  63. package/engine/graphics/render/buffer/buffers/NormalFrameBuffer.js +12 -2
  64. package/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +8 -10
  65. package/engine/graphics/render/forward_plus/LightManager.js +5 -7
  66. package/engine/graphics/render/forward_plus/data/NumericType.js +9 -0
  67. package/engine/graphics/render/forward_plus/{TextureBackedMemoryRegion.js → data/TextureBackedMemoryRegion.js} +11 -190
  68. package/engine/graphics/render/forward_plus/data/channelCountToThreIntegerTextureType.js +16 -0
  69. package/engine/graphics/render/forward_plus/data/computeDataType.js +36 -0
  70. package/engine/graphics/render/forward_plus/data/computeThreeTextureFormat.js +18 -0
  71. package/engine/graphics/render/forward_plus/data/computeThreeTextureInternalFormatFromDataType.js +63 -0
  72. package/engine/graphics/render/forward_plus/data/computeThreeTextureTypeFromDataType.js +41 -0
  73. package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +1 -1
  74. package/engine/graphics/render/forward_plus/prototypeLightManager.js +1 -1
  75. package/engine/graphics/render/utils/ThreeBypassRenderer.js +1 -3
  76. package/engine/graphics/render/visibility/hiz/buffer/HierarchicalZBuffer.js +198 -0
  77. package/engine/graphics/render/visibility/hiz/buffer/ReductionShader.js +51 -0
  78. package/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +179 -0
  79. package/engine/graphics/render/visibility/hiz/prototypeHiZ.js +435 -0
  80. package/engine/graphics/render/visibility/hiz/query/BatchOcclusionQuery.js +174 -0
  81. package/engine/graphics/render/visibility/hiz/query/QueryShader.js +173 -0
  82. package/engine/graphics/shadows/ShadowMapRenderer.js +12 -2
  83. package/engine/graphics/texture/atlas/TextureAtlas.js +1 -1
  84. package/engine/graphics/texture/cubemap/buildCubeURLs.js +13 -0
  85. package/engine/graphics/texture/cubemap/load_environment_map.d.ts +8 -0
  86. package/engine/graphics/texture/cubemap/load_environment_map.js +163 -0
  87. package/engine/graphics/texture/sampler/Sampler2D.js +18 -62
  88. package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +8 -4
  89. package/engine/graphics/texture/sampler/debug/paintSamplerOnHTML.js +3 -2
  90. package/engine/graphics/texture/sampler/differenceSampler.js +31 -0
  91. package/engine/graphics/texture/sampler/typedArrayConstructorByInstance.js +25 -0
  92. package/engine/graphics/texture/sampler/util/drawSamplerHTML.js +3 -2
  93. package/engine/graphics/texture/virtual/v2/ShaderUsage.js +6 -5
  94. package/engine/graphics/texture/virtual/v2/prototype.js +16 -6
  95. package/package.json +1 -1
  96. package/view/elements/progress/segmented/SegmentedResourceBarView.js +50 -15
  97. package/view/minimap/gl/MinimapMarkersGL.js +2 -2
  98. package/engine/graphics/micron/render/RefinementSpec.js +0 -110
@@ -1,102 +1,8 @@
1
1
  import { ActivePatchRecord } from "./ActivePatchRecord.js";
2
2
  import { ActivePatchFlags } from "./ActivePatchFlags.js";
3
- import { PI_HALF } from "../../../../../core/math/MathUtils.js";
4
- import { v3_angleBetween } from "../../../../../core/geom/Vector3.js";
5
3
  import { aabb3_project_to_2d } from "../../../../../core/geom/3d/aabb/aabb3_compute_projected_area.js";
6
- import AABB2 from "../../../../../core/geom/AABB2.js";
7
- import { approximateTriangleArea } from "../approximateTriangleArea.js";
8
4
  import { BitSet } from "../../../../../core/binary/BitSet.js";
9
-
10
- const scratch_aabb2 = new AABB2();
11
-
12
- /**
13
- *
14
- * @param {RefinementSpec} refinement_spec
15
- * @param {MicronGeometryPatch} patch
16
- * @returns {boolean}
17
- */
18
- function is_patch_facing_back(refinement_spec, patch) {
19
-
20
- const normal_cone = patch.normal_cone;
21
- const normal_cone_angle = normal_cone.angle;
22
-
23
- // Do normal cone check against view angle
24
- if (normal_cone_angle < PI_HALF) {
25
- // compute view direction
26
- // TODO position might be way off from the surface center, as well as patch might curve a lot more than expected, need to account for that
27
-
28
- const bounds_center_x = patch.bounding_sphere[0];
29
- const bounds_center_y = patch.bounding_sphere[1];
30
- const bounds_center_z = patch.bounding_sphere[2];
31
-
32
- const view_direction_x = refinement_spec.view_position[0] - bounds_center_x;
33
- const view_direction_y = refinement_spec.view_position[1] - bounds_center_y;
34
- const view_direction_z = refinement_spec.view_position[2] - bounds_center_z;
35
-
36
- // compute view angle of the bounding sphere
37
- const normal_cone_direction = normal_cone.direction;
38
-
39
- const angle = v3_angleBetween(
40
- view_direction_x, view_direction_y, view_direction_z,
41
- normal_cone_direction.x, normal_cone_direction.y, normal_cone_direction.z
42
- );
43
-
44
- if (angle > normal_cone_angle + PI_HALF) {
45
- return false;
46
- }
47
-
48
- }
49
-
50
- return true;
51
- }
52
-
53
- /**
54
- *
55
- * @param {RefinementSpec} refinement_spec
56
- * @param {MicronGeometryPatch} node
57
- * @returns {boolean}
58
- */
59
- function is_patch_visible(refinement_spec, node) {
60
-
61
- // check if node is in view frustum
62
- const bounding_box = node.bounding_box;
63
- const in_view_frustum = bounding_box.intersectFrustum(refinement_spec.frustum);
64
-
65
- if (!in_view_frustum) {
66
- // outside of view frustum, cull
67
- return false;
68
- }
69
-
70
-
71
- // compute projected bounds of the patch
72
- aabb3_project_to_2d(scratch_aabb2, bounding_box, refinement_spec.projection_matrix);
73
-
74
- // Cull by screen area
75
- const normalized_screen_area = scratch_aabb2.computeArea();
76
- const patch_screen_area = normalized_screen_area * refinement_spec.viewport_area;
77
-
78
- if (patch_screen_area < refinement_spec.error_threshold) {
79
- // the whole patch is too small, cull
80
- return false;
81
- }
82
-
83
- return true;
84
- }
85
-
86
- /**
87
- *
88
- * @param {AABB3} bounding_box
89
- * @param {RefinementSpec} spec
90
- * @returns {number}
91
- */
92
- function compute_projected_area(bounding_box, spec) {
93
- aabb3_project_to_2d(scratch_aabb2, bounding_box, spec.projection_matrix);
94
-
95
- // Cull by screen area
96
- const normalized_screen_area = scratch_aabb2.computeArea();
97
- const patch_screen_area = normalized_screen_area * spec.viewport_area;
98
- return patch_screen_area;
99
- }
5
+ import { aabb3_intersects_frustum } from "../../../../../core/bvh2/aabb3/aabb3_intersects_frustum.js";
100
6
 
101
7
  export class ActivePatchList {
102
8
  constructor() {
@@ -117,6 +23,19 @@ export class ActivePatchList {
117
23
  * @type {BitSet}
118
24
  */
119
25
  this.unfolded = new BitSet();
26
+
27
+ // prevent re-allocation related thrashing
28
+ this.unfolded.preventShrink();
29
+ }
30
+
31
+ clear() {
32
+ const unfolded = this.unfolded;
33
+
34
+ unfolded.reset();
35
+
36
+ ActivePatchRecord.pool_release_all(this.records);
37
+
38
+ this.records = null;
120
39
  }
121
40
 
122
41
  /**
@@ -124,13 +43,16 @@ export class ActivePatchList {
124
43
  * @param {MicronGeometry} geometry
125
44
  */
126
45
  initializeFromGeometry(geometry) {
127
- const record = ActivePatchRecord.fromPatch(geometry.root);
46
+ this.clear();
128
47
 
48
+ const record = ActivePatchRecord.pool_get();
49
+
50
+ record.patch = geometry.root;
129
51
  record.link_next = null;
130
52
  record.link_previous = null;
131
53
 
132
- this.unfolded.reset();
133
- this.unfolded.set(record.patch.id, true);
54
+ const unfolded = this.unfolded;
55
+ unfolded.set(record.patch.id, true);
134
56
 
135
57
  this.records = record;
136
58
  }
@@ -138,6 +60,7 @@ export class ActivePatchList {
138
60
  /**
139
61
  *
140
62
  * @param {ActivePatchRecord} record
63
+ * @returns {ActivePatchRecord}
141
64
  */
142
65
  node_split(record) {
143
66
 
@@ -150,19 +73,24 @@ export class ActivePatchList {
150
73
 
151
74
  const child_id = child.id;
152
75
 
153
- if (unfolded.get(child_id)) {
76
+ if (unfolded.getAndSet(child_id)) {
154
77
  // already unfolded, skip
155
78
  continue;
156
79
  }
157
80
 
158
- const child_record = ActivePatchRecord.fromPatch(child);
81
+ const child_record = ActivePatchRecord.pool_get();
82
+ child_record.patch = child;
159
83
 
160
84
  this.record_insert_after(record, child_record);
161
-
162
- unfolded.set(child_id, true);
163
85
  }
164
86
 
165
87
  this.record_remove(record);
88
+
89
+ const next = record.link_next;
90
+
91
+ ActivePatchRecord.pool_release(record);
92
+
93
+ return next;
166
94
  }
167
95
 
168
96
  /**
@@ -226,36 +154,6 @@ export class ActivePatchList {
226
154
  this.record_remove(b);
227
155
  }
228
156
 
229
- /**
230
- *
231
- * @param {ActivePatchRecord} record
232
- * @param {RefinementSpec} spec
233
- */
234
- node_try_merge(record, spec) {
235
- const next = record.link_next;
236
- if (next === null) {
237
- // no next record
238
- return;
239
- }
240
-
241
- return;
242
-
243
- const parent = record.patch.parent;
244
-
245
- if (parent !== next.patch.parent) {
246
- // not a sibling
247
- return;
248
- }
249
-
250
- const patch_screen_area = compute_projected_area(parent.bounding_box, spec);
251
-
252
- const approximate_triangle_area = patch_screen_area * approximateTriangleArea(parent);
253
-
254
- if (approximate_triangle_area <= spec.error_threshold) {
255
- this.node_merge(record, next);
256
- }
257
-
258
- }
259
157
 
260
158
  /**
261
159
  * Populate with LOD-X of a given geometry
@@ -286,7 +184,13 @@ export class ActivePatchList {
286
184
  */
287
185
  refine(spec) {
288
186
 
289
- for (let record = this.records; record !== null; record = record.link_next) {
187
+ const frustum_planes = spec.frustum_f32;
188
+ const projection_matrix = spec.projection_matrix;
189
+ const error_threshold = spec.error_threshold_normalized;
190
+
191
+ let record = this.records
192
+
193
+ for (; record !== null;) {
290
194
 
291
195
  const node = record.patch;
292
196
 
@@ -297,32 +201,17 @@ export class ActivePatchList {
297
201
  check if node is in view frustum
298
202
  NOTE: following suggestion in "FastMesh: Efficient View-dependent Meshing" by Renato Pajarola et al, we can do a more coarse frustum test approximating frustum as a cone initially
299
203
  */
300
- const bounding_box = node.bounding_box;
301
- const in_view_frustum = bounding_box.intersectFrustum(spec.frustum);
204
+ const in_view_frustum = aabb3_intersects_frustum(node.bounding_box, frustum_planes);
302
205
 
303
206
  if (!in_view_frustum) {
304
207
  // outside of view frustum, cull
305
208
  if (prev_is_visible) {
306
209
  record.clearFlag(ActivePatchFlags.Visible);
307
210
  }
211
+ record = record.link_next;
308
212
  continue;
309
213
  }
310
214
 
311
- // compute projected bounds of the patch
312
- // const patch_screen_area = compute_projected_area(bounding_box, spec);
313
-
314
- // const patch_is_too_small_to_be_seen = patch_screen_area < spec.error_threshold;
315
- //
316
- // if (patch_is_too_small_to_be_seen) {
317
- // // the whole patch is too small, cull
318
- // if (prev_is_visible) {
319
- // record.clearFlag(ActivePatchFlags.Visible);
320
- // }
321
- //
322
- // // try to merge with sibling
323
- // continue;
324
- // }
325
-
326
215
  if (!prev_is_visible) {
327
216
  record.setFlag(ActivePatchFlags.Visible);
328
217
  }
@@ -340,22 +229,17 @@ export class ActivePatchList {
340
229
  // not the lowest level of LOD, see if subdivision might be necessary
341
230
 
342
231
  // compute average triangle area
343
- const group_screen_area = compute_projected_area(node.group_bounding_box, spec);
232
+ const group_screen_area = aabb3_project_to_2d(node.group_bounding_box_corners, projection_matrix);
344
233
  const screen_space_error = node.group_error * group_screen_area;
345
234
 
346
-
347
- if (screen_space_error > spec.error_threshold) {
235
+ if (screen_space_error > error_threshold) {
348
236
  // error too large, needs to be split
349
- this.node_split(record);
237
+ record = this.node_split(record);
350
238
  continue;
351
239
  }
352
240
  }
353
241
 
354
-
355
- // check if record and its sibling can be merged
356
- // if (approximate_triangle_area < spec.error_threshold) {
357
- // this.node_try_merge(record, spec);
358
- // }
242
+ record = record.link_next;
359
243
  }
360
244
  }
361
245
  }
@@ -60,8 +60,6 @@ export class ActivePatchRecord {
60
60
  patch_pool_size--;
61
61
 
62
62
  // reset record
63
- r.link_next = null;
64
-
65
63
  r.flags = 0;
66
64
 
67
65
  return r;
@@ -91,6 +89,10 @@ export class ActivePatchRecord {
91
89
  * @param {ActivePatchRecord} r
92
90
  */
93
91
  static pool_release_all(r) {
92
+ if (r === null) {
93
+ return;
94
+ }
95
+
94
96
  let p = r;
95
97
 
96
98
  for (; patch_pool_size < patch_limit;) {
@@ -0,0 +1,98 @@
1
+ import Vector2 from "../../../../../core/geom/Vector2.js";
2
+ import { mat4 } from "gl-matrix";
3
+ import { array_setFromProjectionMatrix } from "./array_setFromProjectionMatrix.js";
4
+
5
+ export class RefinementSpec {
6
+ constructor() {
7
+
8
+ /**
9
+ * Viewport resolution
10
+ * @type {Vector2}
11
+ */
12
+ this.resolution = new Vector2();
13
+
14
+ /**
15
+ * Number of pixels in the viewport
16
+ * @type {number}
17
+ */
18
+ this.viewport_area = 0;
19
+
20
+ /**
21
+ * How much error to accept when deciding to subdivide a cluster
22
+ * Measured in pixels
23
+ * Higher value will result in better performance but more visible artifacts
24
+ * @type {number}
25
+ */
26
+ this.error_threshold = 1;
27
+
28
+ /**
29
+ * Error threshold as a fraction of the screen area instead of pixels, derived internally from pixel value
30
+ * @type {number}
31
+ */
32
+ this.error_threshold_normalized = 1;
33
+
34
+ /**
35
+ * Continuous memory region for faster access
36
+ * @type {ArrayBuffer}
37
+ */
38
+ const array_buffer = new ArrayBuffer(160);
39
+
40
+ /**
41
+ * Object-space camera frustum
42
+ * Frustum planes in compact form
43
+ * @type {Float32Array}
44
+ */
45
+ this.frustum_f32 = new Float32Array(array_buffer, 0, 24);
46
+
47
+
48
+ /**
49
+ * Contains transformation from camera space to object space
50
+ * @type {Float32Array|number[]|mat4}
51
+ */
52
+ this.projection_matrix = new Float32Array(array_buffer, 24 * 4, 16);
53
+
54
+ /**
55
+ * Model world transform
56
+ * @type {Float32Array|number[]|mat4}
57
+ */
58
+ // this.transform = new Float32Array(16);
59
+
60
+ /**
61
+ * Object-space camera position
62
+ * @type {Float32Array}
63
+ */
64
+ this.view_position = new Float32Array(3);
65
+ }
66
+
67
+ get frustum() {
68
+ throw new Error('deprecated, use .frustum_f32 instead');
69
+ }
70
+
71
+ setResolution(x, y) {
72
+ this.resolution.set(x, y);
73
+
74
+ this.viewport_area = x * y;
75
+
76
+ this.error_threshold_normalized = this.error_threshold / this.viewport_area;
77
+ }
78
+
79
+ /**
80
+ *
81
+ * @param {number[]|mat4|Float32Array|ArrayLike<number>} transform world-space object transform
82
+ * @param {number[]|mat4|Float32Array|ArrayLike<number>} matrix_world_inverse camera's world inverse matrix
83
+ * @param {number[]|mat4|Float32Array|ArrayLike<number>} matrix_projection camera's projection matrix
84
+ */
85
+ build(transform, matrix_world_inverse, matrix_projection) {
86
+ // const _transform = this.transform;
87
+ // _transform.set(transform);
88
+
89
+ // build projection matrix
90
+ const projection_matrix = this.projection_matrix;
91
+
92
+ mat4.multiply(projection_matrix, matrix_world_inverse, transform);
93
+ mat4.multiply(projection_matrix, matrix_projection, projection_matrix);
94
+
95
+ // compute view frustum in model-space
96
+ array_setFromProjectionMatrix(this.frustum_f32, projection_matrix);
97
+ }
98
+ }
@@ -0,0 +1,25 @@
1
+ import { v3_length } from "../../../../../core/geom/Vector3.js";
2
+
3
+ /**
4
+ * Normalize a plane in-place
5
+ * @param {number[]} source
6
+ * @param {number} source_offset
7
+ */
8
+ function array_normalize_plane(source, source_offset) {
9
+ const _x = source[source_offset];
10
+ const _y = source[source_offset + 1];
11
+ const _z = source[source_offset + 2];
12
+
13
+ const length = v3_length(_x, _y, _z);
14
+
15
+ const inverseNormalLength = 1.0 / length;
16
+
17
+ /*
18
+ By re-using values already in the registers instead of using *= we save a few extra READ ops
19
+ */
20
+ source[source_offset] = _x * inverseNormalLength;
21
+ source[source_offset + 1] = _y * inverseNormalLength;
22
+ source[source_offset + 2] = _z * inverseNormalLength;
23
+
24
+ source[source_offset + 3] *= inverseNormalLength;
25
+ }
@@ -0,0 +1,60 @@
1
+ import { v3_length } from "../../../../../core/geom/Vector3.js";
2
+
3
+ /**
4
+ *
5
+ * @param {number[]} destination
6
+ * @param {number} destination_offset
7
+ * @param {number} x
8
+ * @param {number} y
9
+ * @param {number} z
10
+ * @param {number} w
11
+ */
12
+ function array_set_plane_normalized(destination, destination_offset, x, y, z, w) {
13
+ const length = v3_length(x, y, z);
14
+
15
+ const inverseNormalLength = 1.0 / length;
16
+
17
+ destination[destination_offset] = x * inverseNormalLength;
18
+ destination[destination_offset + 1] = y * inverseNormalLength;
19
+ destination[destination_offset + 2] = z * inverseNormalLength;
20
+ destination[destination_offset + 3] = w * inverseNormalLength;
21
+ }
22
+
23
+ /**
24
+ *
25
+ * @param {number[]|Float32Array} frustum_planes
26
+ * @param {number[]} me
27
+ */
28
+ export function array_setFromProjectionMatrix(frustum_planes, me) {
29
+
30
+ const me0 = me[0];
31
+ const me3 = me[3];
32
+
33
+ const me4 = me[4];
34
+ const me7 = me[7];
35
+
36
+ const me8 = me[8];
37
+ const me11 = me[11];
38
+
39
+ const me12 = me[12];
40
+ const me15 = me[15];
41
+
42
+ array_set_plane_normalized(frustum_planes, 0, me3 - me0, me7 - me4, me11 - me8, me15 - me12);
43
+ array_set_plane_normalized(frustum_planes, 4, me3 + me0, me7 + me4, me11 + me8, me15 + me12);
44
+
45
+ const me1 = me[1];
46
+ const me5 = me[5];
47
+ const me9 = me[9];
48
+ const me13 = me[13];
49
+
50
+ array_set_plane_normalized(frustum_planes, 8, me3 + me1, me7 + me5, me11 + me9, me15 + me13);
51
+ array_set_plane_normalized(frustum_planes, 12, me3 - me1, me7 - me5, me11 - me9, me15 - me13);
52
+
53
+ const me2 = me[2];
54
+ const me6 = me[6];
55
+ const me10 = me[10];
56
+ const me14 = me[14];
57
+
58
+ array_set_plane_normalized(frustum_planes, 16, me3 - me2, me7 - me6, me11 - me10, me15 - me14);
59
+ array_set_plane_normalized(frustum_planes, 20, me3 + me2, me7 + me6, me11 + me10, me15 + me14);
60
+ }
@@ -0,0 +1,43 @@
1
+ import { PI_HALF } from "../../../../../core/math/MathUtils.js";
2
+ import { v3_angleBetween } from "../../../../../core/geom/Vector3.js";
3
+
4
+ /**
5
+ *
6
+ * @param {RefinementSpec} refinement_spec
7
+ * @param {MicronGeometryPatch} patch
8
+ * @returns {boolean}
9
+ */
10
+ function is_patch_facing_back(refinement_spec, patch) {
11
+
12
+ const normal_cone = patch.normal_cone;
13
+ const normal_cone_angle = normal_cone.angle;
14
+
15
+ // Do normal cone check against view angle
16
+ if (normal_cone_angle < PI_HALF) {
17
+ // compute view direction
18
+ // TODO position might be way off from the surface center, as well as patch might curve a lot more than expected, need to account for that
19
+
20
+ const bounds_center_x = patch.bounding_sphere[0];
21
+ const bounds_center_y = patch.bounding_sphere[1];
22
+ const bounds_center_z = patch.bounding_sphere[2];
23
+
24
+ const view_direction_x = refinement_spec.view_position[0] - bounds_center_x;
25
+ const view_direction_y = refinement_spec.view_position[1] - bounds_center_y;
26
+ const view_direction_z = refinement_spec.view_position[2] - bounds_center_z;
27
+
28
+ // compute view angle of the bounding sphere
29
+ const normal_cone_direction = normal_cone.direction;
30
+
31
+ const angle = v3_angleBetween(
32
+ view_direction_x, view_direction_y, view_direction_z,
33
+ normal_cone_direction.x, normal_cone_direction.y, normal_cone_direction.z
34
+ );
35
+
36
+ if (angle > normal_cone_angle + PI_HALF) {
37
+ return false;
38
+ }
39
+
40
+ }
41
+
42
+ return true;
43
+ }
@@ -0,0 +1,37 @@
1
+ import AABB2 from "../../../../../core/geom/AABB2.js";
2
+ import { aabb3_project_to_2d } from "../../../../../core/geom/3d/aabb/aabb3_compute_projected_area.js";
3
+
4
+ const scratch_aabb2 = new AABB2();
5
+
6
+ /**
7
+ *
8
+ * @param {RefinementSpec} refinement_spec
9
+ * @param {MicronGeometryPatch} node
10
+ * @returns {boolean}
11
+ */
12
+ function is_patch_visible(refinement_spec, node) {
13
+
14
+ // check if node is in view frustum
15
+ const bounding_box = node.bounding_box;
16
+ const in_view_frustum = bounding_box.intersectFrustum(refinement_spec.frustum);
17
+
18
+ if (!in_view_frustum) {
19
+ // outside of view frustum, cull
20
+ return false;
21
+ }
22
+
23
+
24
+ // compute projected bounds of the patch
25
+ aabb3_project_to_2d(scratch_aabb2, bounding_box, refinement_spec.projection_matrix);
26
+
27
+ // Cull by screen area
28
+ const normalized_screen_area = scratch_aabb2.computeArea();
29
+ const patch_screen_area = normalized_screen_area * refinement_spec.viewport_area;
30
+
31
+ if (patch_screen_area < refinement_spec.error_threshold) {
32
+ // the whole patch is too small, cull
33
+ return false;
34
+ }
35
+
36
+ return true;
37
+ }
@@ -12,6 +12,27 @@ export class MaterialVertexSpec {
12
12
  this.material = null;
13
13
  }
14
14
 
15
+ /**
16
+ *
17
+ * @param {MaterialVertexSpec} other
18
+ */
19
+ copy(other) {
20
+ this.spec = other.spec;
21
+ this.material = other.material;
22
+ }
23
+
24
+ /**
25
+ *
26
+ * @return {MaterialVertexSpec}
27
+ */
28
+ clone() {
29
+ const r = new MaterialVertexSpec();
30
+
31
+ r.copy(this);
32
+
33
+ return r;
34
+ }
35
+
15
36
  /**
16
37
  * @param {MicronVertexDataSpec} spec
17
38
  * @param {Material} material
@@ -7,6 +7,12 @@ import { HashMap } from "../../../../../core/collection/HashMap.js";
7
7
  import Signal from "../../../../../core/events/signal/Signal.js";
8
8
  import { array_copy } from "../../../../../core/collection/array/copyArray.js";
9
9
 
10
+ /**
11
+ *
12
+ * @type {MaterialVertexSpec}
13
+ */
14
+ const scratch_mvc = new MaterialVertexSpec();
15
+
10
16
  export class VGThreeRenderer {
11
17
  constructor() {
12
18
  this.geometry = new VirtualGeometry();
@@ -32,13 +38,6 @@ export class VGThreeRenderer {
32
38
  */
33
39
  this.__contexts_array = [];
34
40
 
35
- /**
36
- *
37
- * @type {Scene|null}
38
- * @private
39
- */
40
- this.__scene = null;
41
-
42
41
  /**
43
42
  *
44
43
  * @type {Object3D[]}
@@ -75,14 +74,18 @@ export class VGThreeRenderer {
75
74
  * @private
76
75
  */
77
76
  __obtain_material(spec, m) {
78
- const key = MaterialVertexSpec.from(spec, m);
77
+ scratch_mvc.material = m;
78
+ scratch_mvc.spec = spec;
79
79
 
80
- const existing = this.material_contexts.get(key);
80
+ const existing = this.material_contexts.get(scratch_mvc);
81
81
 
82
82
  if (existing !== undefined) {
83
83
  return existing;
84
84
  }
85
85
 
86
+ // create a separate instance to be stored alongside the context
87
+ const key = scratch_mvc.clone();
88
+
86
89
  const ctx = new MaterialContext(spec, m);
87
90
 
88
91
  ctx.init(this.__gl_context);
@@ -1,5 +1,5 @@
1
1
  import { decode_hemioct_to_unit, encode_unit_to_hemioct } from "./encode_unit3_hemioct.js";
2
- import { v3Length_i } from "../../../../core/geom/Vector3.js";
2
+ import { v3_length } from "../../../../core/geom/Vector3.js";
3
3
 
4
4
  test('encode-decode', () => {
5
5
  const v0 = [];
@@ -7,7 +7,7 @@ test('encode-decode', () => {
7
7
 
8
8
  function validate(x, y, z) {
9
9
  // normalize input
10
- const l = 1 / v3Length_i(x, y, z);
10
+ const l = 1 / v3_length(x, y, z);
11
11
 
12
12
  const _x = x * l;
13
13
  const _y = y * l;