@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.
- package/core/bvh2/aabb3/AABB3.js +18 -0
- package/core/bvh2/aabb3/aabb3_intersects_frustum.js +38 -0
- package/core/collection/RingBuffer.js +40 -10
- package/core/collection/array/copyArray.js +2 -2
- package/core/collection/array/typed/typed_array_copy.js +2 -2
- package/core/collection/table/RowFirstTableSpec.js +8 -0
- package/core/geom/3d/aabb/aabb3_compute_projected_area.js +16 -14
- package/core/geom/3d/aabb/aabb3_estimate_projected_area2.js +59 -0
- package/core/geom/3d/aabb/aabb3_matrix4_project.js +33 -0
- package/core/geom/3d/aabb/aabb3_matrix4_project.spec.js +41 -0
- package/core/geom/3d/plane/plane3_lerp.js +2 -2
- package/core/geom/3d/topology/TopoTriangle.js +2 -2
- package/core/geom/AABB2.d.ts +2 -0
- package/core/geom/Matrix4.js +4 -4
- package/core/geom/Vector3.js +5 -5
- package/core/model/reactive/model/terminal/ReactiveReference.js +7 -1
- package/core/process/undo/ActionProcessor.d.ts +2 -0
- package/core/process/undo/ActionProcessor.js +59 -1
- package/core/process/undo/ActionProcessor.spec.js +59 -0
- package/core/process/undo/Mark.js +2 -1
- package/engine/asset/loaders/GLTFAssetLoader.js +3 -3
- package/engine/asset/loaders/material/TextureAttachmensByMaterialType.js +11 -1
- package/engine/asset/loaders/material/TextureAttachment.js +12 -1
- package/engine/asset/loaders/material/bitmap2sampler_gl.js +19 -0
- package/engine/asset/loaders/material/computeImageBitmapEquality.js +7 -19
- package/engine/asset/loaders/material/computeTextureEquality.js +1 -1
- package/engine/asset/loaders/material/computeTextureHash.js +16 -14
- package/engine/asset/loaders/material/traverseMaterialTextures.js +2 -2
- package/engine/ecs/animation/OneBoneSurfaceAlignmentSolver.js +2 -2
- package/engine/ecs/animation/TwoBoneInverseKinematicsSolver.js +4 -4
- package/engine/graphics/GraphicsEngine.d.ts +2 -2
- package/engine/graphics/GraphicsEngine.js +20 -62
- package/engine/graphics/filter/FlipArrayInPlace.js +25 -0
- package/engine/graphics/filter/FlipArrayViaCanvas.js +13 -0
- package/engine/graphics/filter/ImageFilter.js +20 -51
- package/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +2 -2
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +25 -16
- package/engine/graphics/material/SplatMaterial.js +4 -97
- package/engine/graphics/material/optimization/MaterialOptimizationContext.js +598 -0
- package/engine/graphics/micron/build/PatchRepresentation.js +4 -43
- package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +4 -75
- package/engine/graphics/micron/build/compute_buffer_geometry_byte_size.js +16 -0
- package/engine/graphics/micron/build/fill_patch_geometry_data.js +2 -0
- package/engine/graphics/micron/format/MicronGeometryBufferAttributeSpec.js +1 -1
- package/engine/graphics/micron/format/MicronGeometryPatch.js +17 -5
- package/engine/graphics/micron/format/MicronVertexDataSpec.js +25 -3
- package/engine/graphics/micron/prototypeVirtualGeometry.js +19 -12
- package/engine/graphics/micron/render/VirtualGeometryBuilder.js +34 -27
- package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +2 -4
- package/engine/graphics/micron/render/instanced/PatchDataTextures.js +1 -0
- package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +1 -29
- package/engine/graphics/micron/render/refinement/ActivePatchList.js +43 -159
- package/engine/graphics/micron/render/refinement/ActivePatchRecord.js +4 -2
- package/engine/graphics/micron/render/refinement/RefinementSpec.js +98 -0
- package/engine/graphics/micron/render/refinement/array_normalize_plane.js +25 -0
- package/engine/graphics/micron/render/refinement/array_setFromProjectionMatrix.js +60 -0
- package/engine/graphics/micron/render/refinement/is_patch_facing_back.js +43 -0
- package/engine/graphics/micron/render/refinement/is_patch_visible.js +37 -0
- package/engine/graphics/micron/render/v1/MaterialVertexSpec.js +21 -0
- package/engine/graphics/micron/render/v1/VGThreeRenderer.js +12 -9
- package/engine/graphics/micron/util/unit_hemioct.spec.js +2 -2
- package/engine/graphics/render/buffer/buffers/ColorAndDepthFrameBuffer.js +5 -3
- package/engine/graphics/render/buffer/buffers/NormalFrameBuffer.js +12 -2
- package/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +8 -10
- package/engine/graphics/render/forward_plus/LightManager.js +5 -7
- package/engine/graphics/render/forward_plus/data/NumericType.js +9 -0
- package/engine/graphics/render/forward_plus/{TextureBackedMemoryRegion.js → data/TextureBackedMemoryRegion.js} +11 -190
- package/engine/graphics/render/forward_plus/data/channelCountToThreIntegerTextureType.js +16 -0
- package/engine/graphics/render/forward_plus/data/computeDataType.js +36 -0
- package/engine/graphics/render/forward_plus/data/computeThreeTextureFormat.js +18 -0
- package/engine/graphics/render/forward_plus/data/computeThreeTextureInternalFormatFromDataType.js +63 -0
- package/engine/graphics/render/forward_plus/data/computeThreeTextureTypeFromDataType.js +41 -0
- package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +1 -1
- package/engine/graphics/render/forward_plus/prototypeLightManager.js +1 -1
- package/engine/graphics/render/utils/ThreeBypassRenderer.js +1 -3
- package/engine/graphics/render/visibility/hiz/buffer/HierarchicalZBuffer.js +198 -0
- package/engine/graphics/render/visibility/hiz/buffer/ReductionShader.js +51 -0
- package/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +179 -0
- package/engine/graphics/render/visibility/hiz/prototypeHiZ.js +435 -0
- package/engine/graphics/render/visibility/hiz/query/BatchOcclusionQuery.js +174 -0
- package/engine/graphics/render/visibility/hiz/query/QueryShader.js +173 -0
- package/engine/graphics/shadows/ShadowMapRenderer.js +12 -2
- package/engine/graphics/texture/atlas/TextureAtlas.js +1 -1
- package/engine/graphics/texture/cubemap/buildCubeURLs.js +13 -0
- package/engine/graphics/texture/cubemap/load_environment_map.d.ts +8 -0
- package/engine/graphics/texture/cubemap/load_environment_map.js +163 -0
- package/engine/graphics/texture/sampler/Sampler2D.js +18 -62
- package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +8 -4
- package/engine/graphics/texture/sampler/debug/paintSamplerOnHTML.js +3 -2
- package/engine/graphics/texture/sampler/differenceSampler.js +31 -0
- package/engine/graphics/texture/sampler/typedArrayConstructorByInstance.js +25 -0
- package/engine/graphics/texture/sampler/util/drawSamplerHTML.js +3 -2
- package/engine/graphics/texture/virtual/v2/ShaderUsage.js +6 -5
- package/engine/graphics/texture/virtual/v2/prototype.js +16 -6
- package/package.json +1 -1
- package/view/elements/progress/segmented/SegmentedResourceBarView.js +50 -15
- package/view/minimap/gl/MinimapMarkersGL.js +2 -2
- 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
|
-
|
|
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
|
|
133
|
-
|
|
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.
|
|
76
|
+
if (unfolded.getAndSet(child_id)) {
|
|
154
77
|
// already unfolded, skip
|
|
155
78
|
continue;
|
|
156
79
|
}
|
|
157
80
|
|
|
158
|
-
const child_record = ActivePatchRecord.
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
77
|
+
scratch_mvc.material = m;
|
|
78
|
+
scratch_mvc.spec = spec;
|
|
79
79
|
|
|
80
|
-
const existing = this.material_contexts.get(
|
|
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 {
|
|
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 /
|
|
10
|
+
const l = 1 / v3_length(x, y, z);
|
|
11
11
|
|
|
12
12
|
const _x = x * l;
|
|
13
13
|
const _y = y * l;
|