@woosh/meep-engine 2.34.49 → 2.35.0

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 (51) hide show
  1. package/core/bvh2/BinaryNode.js +19 -35
  2. package/core/bvh2/aabb3/aabb3_intersects_frustum_array.js +5 -5
  3. package/core/bvh2/aabb3_combined_surface_area.js +21 -0
  4. package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +24 -12
  5. package/core/cache/Cache.d.ts +2 -0
  6. package/core/cache/Cache.js +27 -23
  7. package/core/geom/3d/frustum/frustum_from_projection_matrix_array.js +2 -0
  8. package/core/math/max2.js +2 -6
  9. package/core/math/min2.js +2 -6
  10. package/engine/asset/loaders/geometry/geometry/computeGeometryEquality.js +1 -1
  11. package/engine/asset/loaders/geometry/geometry/computeGeometryHash.js +9 -1
  12. package/engine/ecs/EntityComponentDataset.js +7 -2
  13. package/engine/ecs/foliage/ViewState.js +13 -3
  14. package/engine/ecs/parent/EntityNode.js +23 -11
  15. package/engine/ecs/transform/Transform.js +15 -13
  16. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +63 -26
  17. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +63 -3
  18. package/engine/graphics/ecs/mesh-v2/render/AbstractRenderAdapter.js +67 -0
  19. package/engine/graphics/ecs/mesh-v2/render/GenericRendererAdapter.js +48 -0
  20. package/engine/graphics/ecs/mesh-v2/render/InstancedRendererAdapter.js +110 -0
  21. package/engine/graphics/ecs/mesh-v2/render/ShadedGeometryRendererContext.js +98 -0
  22. package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +5 -0
  23. package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +23 -5
  24. package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +8 -3
  25. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +23 -85
  26. package/engine/graphics/geometry/instancing/rewriteMaterial.js +9 -45
  27. package/engine/graphics/material/optimization/BUFFER_GEOMETRY_UVS.js +10 -0
  28. package/engine/graphics/material/optimization/MaterialDescriptor.js +46 -0
  29. package/engine/graphics/material/optimization/MaterialOptimizationContext.js +470 -201
  30. package/engine/graphics/material/optimization/UvContext.js +18 -0
  31. package/engine/graphics/material/optimization/is_compliant_mesh.js +71 -0
  32. package/engine/graphics/material/optimization/prepare_atlas_texture.js +23 -0
  33. package/engine/graphics/material/optimization/prototypeMaterialOptimizer.js +127 -0
  34. package/engine/graphics/micron/format/MicronGeometryPatch.js +1 -1
  35. package/engine/graphics/micron/format/VirtualGeometry.js +47 -11
  36. package/engine/graphics/micron/format/serialization/MicronGeometryBinarySerializationAdapter.js +16 -0
  37. package/engine/graphics/micron/prototypeVirtualGeometry.js +3 -2
  38. package/engine/graphics/micron/render/VirtualGeometryBuilder.js +5 -7
  39. package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +1 -45
  40. package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +18 -7
  41. package/engine/graphics/micron/render/refinement/RefinementSpec.js +0 -1
  42. package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +17 -24
  43. package/engine/graphics/micron/render/v1/MaterialContext.js +3 -2
  44. package/engine/graphics/micron/render/v1/VGThreeRenderer.js +19 -4
  45. package/engine/graphics/render/utils/ThreeBypassRenderer.js +3 -2
  46. package/engine/graphics/texture/normalized_internal_format.js +48 -0
  47. package/engine/graphics/texture/sampler/Sampler2D.js +6 -0
  48. package/engine/graphics/texture/sampler/sampler2d_copy_channel_data.js +25 -0
  49. package/engine/graphics/texture/sampler/scaleSampler2D.js +3 -0
  50. package/engine/graphics/texture/sampler/util/drawSamplerHTML.js +14 -1
  51. package/package.json +1 -1
@@ -0,0 +1,18 @@
1
+ import Vector2 from "../../../../core/geom/Vector2.js";
2
+ import AABB2 from "../../../../core/geom/AABB2.js";
3
+
4
+ export class UvContext {
5
+ constructor() {
6
+ /**
7
+ * Resolution of texture
8
+ * @type {Vector2}
9
+ */
10
+ this.resolution = new Vector2(1, 1);
11
+
12
+ /**
13
+ *
14
+ * @type {AABB2}
15
+ */
16
+ this.atlas_patch = new AABB2();
17
+ }
18
+ }
@@ -0,0 +1,71 @@
1
+ import { TextureAttachmentsByMaterialType } from "../../../asset/loaders/material/TextureAttachmensByMaterialType.js";
2
+ import { max2 } from "../../../../core/math/max2.js";
3
+ import { BUFFER_GEOMETRY_UVS } from "./BUFFER_GEOMETRY_UVS.js";
4
+
5
+ /**
6
+ * Is this mesh qualified to be optimized?
7
+ * @param {THREE.Mesh} mesh
8
+ * @returns {boolean}
9
+ */
10
+ export function is_compliant_mesh(mesh) {
11
+ const material = mesh.material;
12
+
13
+ const attachments = TextureAttachmentsByMaterialType[material.type];
14
+
15
+ const uv_scales = [1, 1, 1, 1];
16
+
17
+ const texture_attachment_count = attachments.length;
18
+
19
+ for (let i = 0; i < texture_attachment_count; i++) {
20
+ const attachment = attachments[i];
21
+
22
+ const texture = attachment.read(material);
23
+ if (texture === undefined || texture === null) {
24
+ continue;
25
+ }
26
+
27
+ const uv_index = attachment.uv_index;
28
+
29
+ uv_scales[uv_index * 2] = max2(uv_scales[uv_index * 2], texture.repeat.x)
30
+ uv_scales[uv_index * 2 + 1] = max2(uv_scales[uv_index * 2 + 1], texture.repeat.y)
31
+ }
32
+
33
+ const geometry = mesh.geometry;
34
+
35
+ for (let i = 0; i < BUFFER_GEOMETRY_UVS.length; i++) {
36
+ const uv_metadata = BUFFER_GEOMETRY_UVS[i];
37
+
38
+ /**
39
+ *
40
+ * @type {THREE.BufferAttribute }
41
+ */
42
+ const attribute = geometry.attributes[uv_metadata.name];
43
+
44
+ if (attribute === undefined) {
45
+ continue;
46
+ }
47
+
48
+ const attribute_data = attribute.array;
49
+ const n = attribute_data.length;
50
+
51
+ const uv_index = uv_metadata.index;
52
+ const uv_index_2 = uv_index * 2;
53
+
54
+ for (let j = 0; j < n; j += 2) {
55
+ const x = attribute_data[j];
56
+ const y = attribute_data[j + 1];
57
+
58
+ const scaled_u = x * uv_scales[uv_index_2];
59
+ const scaled_v = y * uv_scales[uv_index_2 + 1];
60
+
61
+ if (scaled_u > 1 || scaled_u < 0 || scaled_v > 1 || scaled_v < 0) {
62
+ // repeating/negative UV value
63
+ return false;
64
+ }
65
+
66
+ }
67
+
68
+ }
69
+
70
+ return true;
71
+ }
@@ -0,0 +1,23 @@
1
+ import { LinearEncoding, LinearFilter, LinearMipmapLinearFilter, sRGBEncoding } from "three";
2
+
3
+ /**
4
+ *
5
+ * @param {Texture} texture
6
+ * @param {string} attachment_name
7
+ */
8
+ export function prepare_atlas_texture(texture, attachment_name) {
9
+
10
+ switch (attachment_name) {
11
+ case 'diffuse':
12
+ texture.encoding = sRGBEncoding;
13
+ break;
14
+ default:
15
+ texture.encoding = LinearEncoding;
16
+ }
17
+
18
+ texture.anisotropy = 4;
19
+ texture.minFilter = LinearMipmapLinearFilter;
20
+ texture.magFilter = LinearFilter;
21
+
22
+ texture.generateMipmaps = true;
23
+ }
@@ -0,0 +1,127 @@
1
+ import { EngineHarness } from "../../../EngineHarness.js";
2
+ import { EngineConfiguration } from "../../../EngineConfiguration.js";
3
+ import { ShadedGeometrySystem } from "../../ecs/mesh-v2/ShadedGeometrySystem.js";
4
+ import { AttachmentSystem } from "../../../ecs/attachment/AttachmentSystem.js";
5
+ import { TransformAttachmentSystem } from "../../../ecs/transform-attachment/TransformAttachmentSystem.js";
6
+ import { GameAssetType } from "../../../asset/GameAssetType.js";
7
+ import { GLTFAssetLoader } from "../../../asset/loaders/GLTFAssetLoader.js";
8
+ import { three_object_to_entity_composition } from "../../ecs/mesh-v2/three_object_to_entity_composition.js";
9
+ import { MaterialOptimizationContext } from "./MaterialOptimizationContext.js";
10
+ import { bvh_traverse_pre_order_using_stack } from "../../../../core/bvh2/traversal/bvh_traverse_pre_order_using_stack.js";
11
+
12
+ const eh = new EngineHarness();
13
+
14
+
15
+ /**
16
+ *
17
+ * @param {Engine} engine
18
+ */
19
+ function optimize(engine) {
20
+ MaterialOptimizationContext.MAX_TEXTURE_SIZE = engine.graphics.renderer.capabilities.maxTextureSize;
21
+
22
+ const optimizer = new MaterialOptimizationContext();
23
+
24
+ engine.graphics.layers.layers.forEach(l => {
25
+ bvh_traverse_pre_order_using_stack(l.bvh, node => {
26
+ if (node.isLeafNode) {
27
+ const object = l.extractRenderable(node.object);
28
+
29
+ if (object) {
30
+ optimizer.addObject(object);
31
+ }
32
+ }
33
+ });
34
+ });
35
+
36
+ optimizer.update();
37
+
38
+ console.log(optimizer);
39
+
40
+ // drawSamplerHTML(document.body, optimizer.atlases.get('roughness'), 20, 20, 1, 0, 512);
41
+ // drawSamplerHTML(document.body, optimizer.atlases.get('metalness'), 532, 20, 1, 0, 512);
42
+ // drawSamplerHTML(document.body, optimizer.atlases.get('ao'), 20, 532, 1, 0, 512);
43
+ // drawSamplerHTML(document.body, optimizer.atlases.get('normal'), 532, 20, 1, 0, 512);
44
+ // drawSamplerHTML(document.body, optimizer.atlases.get('diffuse'), 20, 20, 1, 0, 1024);
45
+ // drawSamplerHTML(document.body, optimizer.atlases.get('normal'), 552, 20, 1, 0, 512);
46
+ }
47
+
48
+ /**
49
+ *
50
+ * @param {EngineHarness} harness
51
+ * @return {Promise<void>}
52
+ */
53
+ async function init(harness) {
54
+ const engine = harness.engine;
55
+
56
+ const config = new EngineConfiguration();
57
+
58
+ config.addSystem(new ShadedGeometrySystem(engine));
59
+ config.addSystem(new AttachmentSystem());
60
+ config.addSystem(new TransformAttachmentSystem());
61
+
62
+ const gltf_loader = new GLTFAssetLoader();
63
+
64
+ config.addLoader(GameAssetType.ModelGLTF_JSON, gltf_loader);
65
+
66
+ await config.apply(engine);
67
+
68
+ eh.initialize().then(main);
69
+ }
70
+
71
+ /**
72
+ *
73
+ * @param {string} path
74
+ * @param {Engine} engine
75
+ */
76
+ async function load_gltf(path, engine) {
77
+ const em = engine.entityManager;
78
+
79
+ const ecd = em.dataset;
80
+
81
+ const asset = await engine.assetManager.promise(path, GameAssetType.ModelGLTF_JSON);
82
+
83
+ const three_object = asset.create();
84
+
85
+ console.time('composition conversion');
86
+ const composition = three_object_to_entity_composition(three_object);
87
+ console.timeEnd('composition conversion');
88
+
89
+ console.time('composition build');
90
+ // console.profile('composition build');
91
+ composition.build(ecd);
92
+ // console.profileEnd('composition build');
93
+ console.timeEnd('composition build');
94
+ }
95
+
96
+ async function timeout(t = 1) {
97
+ await new Promise((resolve, reject) => setTimeout(resolve, t));
98
+ }
99
+
100
+ /**
101
+ *
102
+ * @param {Engine} engine
103
+ */
104
+ async function main(engine) {
105
+
106
+ EngineHarness.buildBasics({
107
+ engine,
108
+ enableWater: false,
109
+ enableTerrain: true
110
+ });
111
+
112
+ // a small delay to let background tasks finish, so we can get better performance reading later on
113
+ timeout(2000);
114
+
115
+ await load_gltf('moicon/06_04_hapro/08-clickable-assets-new/model.gltf', engine);
116
+ // await load_gltf('moicon/06_04_hapro/05-ground-floor/model.gltf', engine);
117
+
118
+ optimize(engine);
119
+
120
+ // load_gltf('moicon/06_04_hapro/07-1st-basement/model.gltf', engine);
121
+ // load_gltf('moicon/06_04_hapro/06-lower-ground/model.gltf', engine);
122
+ // load_gltf('moicon/06_04_hapro/05-ground-floor/model.gltf', engine);
123
+ // load_gltf('moicon/06_04_hapro/04-1st-floor/model.gltf', engine);
124
+ // load_gltf('moicon/06_04_hapro/03-2nd-floor/model.gltf', engine);
125
+ }
126
+
127
+ init(eh);
@@ -23,7 +23,7 @@ export class MicronGeometryPatch {
23
23
  *
24
24
  * @type {vec4|number[]}
25
25
  */
26
- this.bounding_sphere = vec4.create()
26
+ this.bounding_sphere = vec4.create();
27
27
 
28
28
  /**
29
29
  *
@@ -1,12 +1,31 @@
1
+ import { MicronGeometryPatchOccurrence } from "./MicronGeometryPatchOccurance.js";
2
+
1
3
  export class VirtualGeometry {
2
4
  constructor() {
5
+ /**
6
+ * pack patch instance as [INSTANCE_ID, GEOMETRY_ID, PATCH_ID]
7
+ * @type {number[]}
8
+ */
9
+ this.patches = new Uint32Array(300000);
10
+
3
11
  /**
4
12
  *
5
- * @type {MicronGeometryPatchOccurrence[]}
13
+ * @type {number}
6
14
  */
7
- this.patches = [];
8
15
  this.patch_count = 0;
9
16
 
17
+ /**
18
+ * Lookup table of matrix transforms
19
+ * @type {number[][]}
20
+ */
21
+ this.lookup_instance_transforms = [];
22
+
23
+ /**
24
+ * Lookup table of geometries
25
+ * @type {MicronGeometry[]}
26
+ */
27
+ this.loolup_geometries = [];
28
+
10
29
  /**
11
30
  *
12
31
  * @type {number}
@@ -30,11 +49,20 @@ export class VirtualGeometry {
30
49
  */
31
50
  computeFaceCount() {
32
51
  let r = 0;
33
- const patchCount = this.patch_count;
34
- for (let i = 0; i < patchCount; i++) {
35
- const occurrence = this.patches[i];
52
+ const patch_count = this.patch_count;
53
+ const patches = this.patches;
54
+
55
+ for (let i = 0; i < patch_count; i++) {
56
+ const i3 = i * 3;
57
+
58
+ const geometry_id = patches[i3 + 1];
59
+ const patch_id = patches[i3 + 2];
60
+
61
+ const geometry = this.loolup_geometries[geometry_id];
36
62
 
37
- r += occurrence.patch.polygon_count;
63
+ const patch = geometry.patches[patch_id];
64
+
65
+ r += patch.polygon_count;
38
66
  }
39
67
 
40
68
  return r;
@@ -46,11 +74,19 @@ export class VirtualGeometry {
46
74
  */
47
75
  computeVertexCount() {
48
76
  let r = 0;
49
- const patchCount = this.patch_count;
50
- for (let i = 0; i < patchCount; i++) {
51
- const occurrence = this.patches[i];
77
+ const patch_count = this.patch_count;
78
+ const patches = this.patches;
79
+ for (let i = 0; i < patch_count; i++) {
80
+ const i3 = i * 3;
81
+
82
+ const geometry_id = patches[i3 + 1];
83
+ const patch_id = patches[i3 + 2];
84
+
85
+ const geometry = this.loolup_geometries[geometry_id];
86
+
87
+ const patch = geometry.patches[patch_id];
52
88
 
53
- r += occurrence.patch.vertex_count;
89
+ r += patch.vertex_count;
54
90
  }
55
91
 
56
92
  return r;
@@ -61,7 +97,7 @@ export class VirtualGeometry {
61
97
  * @param {MicronGeometryPatchOccurrence} patch
62
98
  */
63
99
  add(patch) {
64
- this.patches[this.patch_count++] = patch;
100
+ throw new Error('Deprecated');
65
101
  }
66
102
 
67
103
  clear() {
@@ -77,6 +77,10 @@ export class MicronGeometryBinarySerializationAdapter extends BinaryClassSeriali
77
77
 
78
78
  const patch_count = buffer.readUintVar();
79
79
 
80
+ /**
81
+ *
82
+ * @type {MicronGeometryPatch[]}
83
+ */
80
84
  const patches = [];
81
85
 
82
86
  // for the sake of speed, we will allocate all metadata in the same piece of memory to make traversal of patch hierarchy faster
@@ -94,14 +98,26 @@ export class MicronGeometryBinarySerializationAdapter extends BinaryClassSeriali
94
98
  patches[i] = patch;
95
99
  }
96
100
 
101
+ let source_triangle_count = 0;
102
+ // NOTE: we can't easily find out source vertex count as vertices are duplicated across patches
103
+
104
+
97
105
  //read patches
98
106
  for (let i = 0; i < patch_count; i++) {
99
107
  const patch = patches[i];
100
108
 
101
109
  deserialize_patch(buffer, patch, vertex_spec, patches);
110
+
111
+ // collect source metadata
112
+ if (patch.lod === 0) {
113
+ source_triangle_count += patch.polygon_count;
114
+ }
102
115
  }
103
116
 
104
117
  value.patches = patches;
105
118
  value.root = patches[root_patch_index];
119
+
120
+ // write source metadata
121
+ value.source_triangle_count = source_triangle_count;
106
122
  }
107
123
  }
@@ -481,8 +481,9 @@ function init() {
481
481
  // gltf_sample('moicon/03_Jan_22_Demo/8-assets/model.gltf');
482
482
  // gltf_sample('moicon/03_Jan_22_Demo/worker_test/model.gltf');
483
483
  // gltf_sample('moicon/A4/A4/model.gltf');
484
- gltf_sample('moicon/ztest_object_many_pieces/model.gltf');
485
- // gltf_grid('moicon/ztest_object_many_pieces/model.gltf', 10, 10);
484
+ gltf_sample('moicon/06_04_hapro/08-clickable-assets-new/model.gltf');
485
+ // gltf_sample('moicon/ztest_object_many_pieces/model.gltf');
486
+ // gltf_grid('moicon/ztest_object_many_pieces/model.gltf', 3, 3);
486
487
 
487
488
  document.addEventListener("mousemove", onDocumentMouseMove);
488
489
 
@@ -157,19 +157,17 @@ export class VirtualGeometryBuilder {
157
157
  output.stats_source_triangle_count += geometry.source_triangle_count;
158
158
  output.stats_source_vertex_count += geometry.source_vertex_count;
159
159
 
160
- // build up occurances
161
- const output_patches = output.patches;
160
+ output.loolup_geometries[geometry.id] = geometry;
161
+ output.lookup_instance_transforms[instance_id] = transform;
162
162
 
163
- const added_patch_count = get_geometry_patch_cut(
164
- output_patches,
165
- output.patch_count,
163
+ // build up occurances
164
+ get_geometry_patch_cut(
165
+ output,
166
166
  refinement_spec,
167
167
  geometry,
168
168
  instance_id,
169
169
  transform
170
170
  );
171
-
172
- output.patch_count += added_patch_count;
173
171
  }
174
172
 
175
173
  clearScene() {
@@ -3,55 +3,11 @@ import { MICRON_PATCH_SIZE_MAX } from "../../build/MICRON_PATCH_SIZE_MAX.js";
3
3
  import { typed_array_copy } from "../../../../../core/collection/array/typed/typed_array_copy.js";
4
4
  import { channelCountToThreeTextureFormat } from "../../../texture/channelCountToThreeTextureFormat.js";
5
5
  import { DataTexture, NearestFilter } from "three";
6
- import { DataType } from "../../../../../core/collection/table/DataType.js";
7
6
  import { compute_micron_buffer_array_constructor } from "../../build/compute_micron_buffer_array_constructor.js";
8
7
  import { computeThreeTextureTypeFromDataType } from "../../../render/forward_plus/data/computeThreeTextureTypeFromDataType.js";
9
8
  import { computeThreeTextureInternalFormatFromDataType } from "../../../render/forward_plus/data/computeThreeTextureInternalFormatFromDataType.js";
10
9
  import { DataTypeByteSizes } from "../../../../../core/collection/table/DataTypeByteSizes.js";
11
-
12
- /**
13
- *
14
- * @returns {string}
15
- * @param {DataType} dt
16
- * @param {number} channel_count
17
- */
18
- function normalized_internal_format(dt, channel_count) {
19
- let suffix = '';
20
- switch (dt) {
21
- case DataType.Uint8:
22
- suffix = '8';
23
- break;
24
- case DataType.Int8:
25
- suffix = '8_SNORM';
26
- break;
27
- case DataType.Uint16:
28
- suffix = '16UI';
29
- break;
30
- default:
31
- throw new Error(`Unsupported data type '${dt}'`);
32
- }
33
-
34
- let prefix = '';
35
-
36
- switch (channel_count) {
37
- case 1:
38
- prefix = 'R';
39
- break;
40
- case 2:
41
- prefix = 'RG';
42
- break;
43
- case 3:
44
- prefix = 'RGB';
45
- break;
46
- case 4:
47
- prefix = 'RGBA';
48
- break;
49
- default:
50
- throw new Error(`Unsupported channel count '${channel_count}'`);
51
- }
52
-
53
- return prefix + suffix;
54
- }
10
+ import { normalized_internal_format } from "../../../texture/normalized_internal_format.js";
55
11
 
56
12
  export class AttributeDataTexture {
57
13
  /**
@@ -132,15 +132,16 @@ export class ThreeInstancedAdapter {
132
132
 
133
133
  /**
134
134
  *
135
- * @param {MicronGeometryPatchOccurrence[]} patches
135
+ * @param {Uint32Array[]} patches
136
136
  * @param {number} patch_count
137
+ * @param {VirtualGeometry} virtual_geometry
137
138
  */
138
- build(patches, patch_count) {
139
+ build(patches, patch_count, virtual_geometry) {
139
140
  this.__prepare_capacity(patch_count);
140
141
 
141
142
  const geo = this.__buffer_geometry;
142
143
 
143
- const patch_transform_attribute = geo.getAttribute(ATTRIBUTE_NAME_TRANSFORM);
144
+ const patch_transform_attribute = geo.attributes[ATTRIBUTE_NAME_TRANSFORM];
144
145
  /**
145
146
  *
146
147
  * @type {Float32Array}
@@ -149,21 +150,31 @@ export class ThreeInstancedAdapter {
149
150
 
150
151
  patch_transform_attribute.needsUpdate = true;
151
152
 
152
- const patch_address_attribute = geo.getAttribute(ATTRIBUTE_NAME_ADDRESS);
153
+ const patch_address_attribute = geo.attributes[ATTRIBUTE_NAME_ADDRESS];
153
154
  const patch_address_array = patch_address_attribute.array;
154
155
 
155
156
  patch_address_attribute.needsUpdate = true;
156
157
 
157
158
  const patch_data = this.__patch_data;
159
+ const transforms = virtual_geometry.lookup_instance_transforms;
160
+ const geometries = virtual_geometry.loolup_geometries;
158
161
 
159
162
  for (let i = 0; i < patch_count; i++) {
160
- const occurrence = patches[i];
163
+ const i3 = i * 3;
164
+
165
+ const instance_id = patches[i3];
166
+ const geometry_id = patches[i3 + 1];
167
+ const patch_id = patches[i3 + 2];
168
+
169
+ const transform = transforms[instance_id];
170
+ const micron_geometry = geometries[geometry_id];
171
+ const patch = micron_geometry.patches[patch_id];
161
172
 
162
173
  const i16 = i * 16;
163
174
 
164
- patch_transform_array.set(occurrence.transform, i16);
175
+ patch_transform_array.set(transform, i16);
165
176
 
166
- const patch_slot_id = patch_data.ensure(occurrence.patch);
177
+ const patch_slot_id = patch_data.ensure(patch);
167
178
 
168
179
  patch_address_array[i] = patch_slot_id;
169
180
  }
@@ -37,7 +37,6 @@ export class RefinementSpec {
37
37
  */
38
38
  const array_buffer = new ArrayBuffer(160);
39
39
 
40
-
41
40
  /**
42
41
  * Contains transformation from camera space to object space
43
42
  * @type {Float32Array|number[]|mat4}
@@ -1,6 +1,5 @@
1
1
  import { BitSet } from "../../../../../core/binary/BitSet.js";
2
2
  import { aabb3_intersects_frustum_array } from "../../../../../core/bvh2/aabb3/aabb3_intersects_frustum_array.js";
3
- import { MicronGeometryPatchOccurrence } from "../../format/MicronGeometryPatchOccurance.js";
4
3
  import { aabb3_estimate_projected_area2 } from "../../../../../core/geom/3d/aabb/aabb3_estimate_projected_area2.js";
5
4
 
6
5
 
@@ -12,24 +11,22 @@ const scratch_traversal_bitset = new BitSet();
12
11
  scratch_traversal_bitset.preventShrink();
13
12
 
14
13
  /**
14
+ * Using a pre-allocated continuous chunk of memory gets us better cache coherence
15
15
  * @readonly
16
- * @type {MicronGeometryPatch[]}
16
+ * @type {number[]}
17
17
  */
18
- const scratch_traversal_stack = [];
18
+ const scratch_traversal_stack = new Uint32Array(781250);
19
19
 
20
20
  /**
21
21
  *
22
- * @param {MicronGeometryPatchOccurrence[]} destination
23
- * @param {number} destination_offset
22
+ * @param {VirtualGeometry} destination
24
23
  * @param {RefinementSpec} spec
25
24
  * @param {MicronGeometry} geometry
26
25
  * @param instance_id
27
26
  * @param transform
28
- * @returns {number}
29
27
  */
30
28
  export function get_geometry_patch_cut(
31
29
  destination,
32
- destination_offset,
33
30
  spec,
34
31
  geometry,
35
32
  instance_id,
@@ -42,26 +39,29 @@ export function get_geometry_patch_cut(
42
39
 
43
40
  const geometry_id = geometry.id;
44
41
 
45
- let output_patch_cursor = destination_offset;
42
+ let output_patch_cursor = destination.patch_count;
46
43
 
47
44
  let i;
48
45
  let stack_cursor = 1;
49
- let patch_instance;
50
46
 
51
47
  // initialize stack
52
48
  const stack = scratch_traversal_stack;
53
49
  const root = geometry.root;
54
- stack[0] = root;
50
+ stack[0] = root.id;
55
51
 
56
52
  const included_set = scratch_traversal_bitset;
57
53
  included_set.reset();
58
54
 
59
55
  included_set.set(root.id, true);
60
56
 
57
+ const patches = geometry.patches;
58
+ const destination_patches = destination.patches;
59
+
61
60
  while (stack_cursor > 0) {
62
61
  stack_cursor--;
63
62
 
64
- const patch = stack[stack_cursor];
63
+ const patch_id = stack[stack_cursor];
64
+ const patch = patches[patch_id];
65
65
 
66
66
  /*
67
67
  check if node is in view frustum
@@ -96,7 +96,7 @@ export function get_geometry_patch_cut(
96
96
  continue;
97
97
  }
98
98
 
99
- stack[stack_cursor++] = child;
99
+ stack[stack_cursor++] = child.id;
100
100
  }
101
101
 
102
102
  continue;
@@ -104,22 +104,15 @@ export function get_geometry_patch_cut(
104
104
  }
105
105
 
106
106
 
107
- patch_instance = destination[output_patch_cursor];
108
-
109
- if (patch_instance === undefined) {
110
- // no instance available for reuse - create a new one
111
- patch_instance = new MicronGeometryPatchOccurrence();
112
- destination[output_patch_cursor] = patch_instance;
113
- }
107
+ const target_address = output_patch_cursor * 3;
114
108
 
115
- patch_instance.instance_id = instance_id;
116
- patch_instance.geometry_id = geometry_id;
117
- patch_instance.patch = patch;
118
- patch_instance.transform = transform;
109
+ destination_patches[target_address] = instance_id;
110
+ destination_patches[target_address + 1] = geometry_id;
111
+ destination_patches[target_address + 2] = patch_id;
119
112
 
120
113
  output_patch_cursor++;
121
114
 
122
115
  }
123
116
 
124
- return output_patch_cursor - destination_offset;
117
+ destination.patch_count = output_patch_cursor;
125
118
  }
@@ -144,8 +144,9 @@ export class MaterialContext {
144
144
 
145
145
  /**
146
146
  *
147
+ * @param {VirtualGeometry} virtual_geometry
147
148
  */
148
- build() {
149
+ build(virtual_geometry) {
149
150
 
150
151
  if (this.__patch_count === 0) {
151
152
  this.mesh.visible = false;
@@ -154,7 +155,7 @@ export class MaterialContext {
154
155
  this.mesh.visible = true;
155
156
  }
156
157
 
157
- this.adapter.build(this.__patches, this.__patch_count);
158
+ this.adapter.build(this.__patches, this.__patch_count, virtual_geometry);
158
159
 
159
160
  }
160
161
  }