@woosh/meep-engine 2.35.15 → 2.35.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ /**
2
+ *
3
+ * @param {number} count
4
+ * @returns {function}
5
+ */
6
+ export function UintArrayForCount(count) {
7
+
8
+ if (count <= 256) {
9
+ return Uint8Array;
10
+ } else if (count <= 65536) {
11
+ return Uint16Array;
12
+ } else if (count <= 4294967295) {
13
+ return Uint32Array;
14
+ } else {
15
+ throw new Error(`Unsupported size ${count}`)
16
+ }
17
+ }
@@ -1,10 +1,3 @@
1
- /**
2
- *
3
- * @param {number} count
4
- * @returns {Function}
5
- * @constructor
6
- */
7
-
8
1
  import { DataType } from "../../../../core/collection/table/DataType.js";
9
2
  import { passThrough } from "../../../../core/function/Functions.js";
10
3
  import { to_half_float_uint16 } from "../../../../core/binary/to_half_float_uint16.js";
@@ -12,17 +5,7 @@ import { compute_micron_buffer_array_constructor } from "./compute_micron_buffer
12
5
  import { typedArrayToDataType } from "../../../../core/collection/array/typedArrayToDataType.js";
13
6
  import { dataTypeByteSize } from "../../../../core/collection/table/DataTypeByteSizes.js";
14
7
  import { clamp } from "../../../../core/math/clamp.js";
15
-
16
- function UintArrayForCount(count) {
17
-
18
- if (count <= 256) {
19
- return Uint8Array;
20
- } else if (count <= 65536) {
21
- return Uint16Array;
22
- } else {
23
- throw new Error(`Unsupported size ${count}`)
24
- }
25
- }
8
+ import { UintArrayForCount } from "../../../../core/collection/array/typed/uint_array_for_count.js";
26
9
 
27
10
  /**
28
11
  * @param {number} vertex_count
@@ -5,6 +5,7 @@ import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
5
5
  import { aabb3_array_intersects_ray } from "../../../../core/bvh2/aabb3/aabb3_array_intersects_ray.js";
6
6
  import { sphere_array_intersects_ray } from "../../../../core/geom/3d/sphere/sphere_array_intersects_ray.js";
7
7
  import { BitSet } from "../../../../core/binary/BitSet.js";
8
+ import { micron_build_proxy_geometry } from "./micron_build_proxy_geometry.js";
8
9
 
9
10
  let id_counter = 0;
10
11
 
@@ -286,11 +287,13 @@ export class MicronGeometry {
286
287
 
287
288
  /**
288
289
  * Build geometry proxy from the patches
289
- * @param {number} fraction percentage of the original geometry to keep
290
- * @param {number} min minimum number of triangles to keep, this will be respected first before percentage value
290
+ * @param {number} [fraction] percentage of the original geometry to keep
291
+ * @param {number} [min] minimum number of triangles to keep, this will be respected first before percentage value
291
292
  */
292
- buildProxy(fraction, min) {
293
- throw new Error('Not Implemented');
293
+ buildProxy(fraction = 0.05, min = 2048) {
294
+ const bufferGeometry = micron_build_proxy_geometry(this, fraction, min);
295
+
296
+ this.__proxy = bufferGeometry;
294
297
  }
295
298
 
296
299
  computeByteSize() {
@@ -0,0 +1,203 @@
1
+ //
2
+
3
+ import BinaryHeap from "../../../navigation/grid/FastBinaryHeap.js";
4
+ import { BufferAttribute, BufferGeometry } from "three";
5
+ import { UintArrayForCount } from "../../../../core/collection/array/typed/uint_array_for_count.js";
6
+ import { compute_typed_array_constructor_from_data_type } from "../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
7
+ import { BitSet } from "../../../../core/binary/BitSet.js";
8
+ import { min2 } from "../../../../core/math/min2.js";
9
+ import { max2 } from "../../../../core/math/max2.js";
10
+
11
+ /**
12
+ *
13
+ * @param {MicronGeometry} micron_geometry
14
+ * @param {number} fraction
15
+ * @param {number} min_face_count
16
+ * @returns {MicronGeometryPatch[]}
17
+ */
18
+ function collect_patches(micron_geometry, fraction, min_face_count) {
19
+ /**
20
+ *
21
+ * @type {BinaryHeap<MicronGeometryPatch>}
22
+ */
23
+ const heap = new BinaryHeap(patch => {
24
+ // LOD is a good proxy for how much detail there is in a patch
25
+ return -patch.lod;
26
+ });
27
+
28
+ let closed_set = new BitSet();
29
+
30
+ let current_polycount = 0;
31
+
32
+ /**
33
+ *
34
+ * @param {MicronGeometryPatch} patch
35
+ */
36
+ function add(patch) {
37
+
38
+ closed_set.set(patch.id, true);
39
+
40
+ heap.push(patch);
41
+
42
+ current_polycount += patch.polygon_count;
43
+ }
44
+
45
+ /**
46
+ *
47
+ * @param {MicronGeometryPatch} patch
48
+ */
49
+ function refine(patch) {
50
+ const children = patch.children;
51
+ const child_count = children.length;
52
+
53
+
54
+ for (let i = 0; i < child_count; i++) {
55
+ const child = children[i];
56
+
57
+ if (closed_set.get(child.id)) {
58
+ // already refined
59
+ continue;
60
+ }
61
+
62
+ add(child);
63
+
64
+ const parents = child.parents;
65
+
66
+ const parent_count = parents.length;
67
+ for (let j = 0; j < parent_count; j++) {
68
+ const parent = parents[j];
69
+
70
+ if (parent === parent) {
71
+ continue;
72
+ }
73
+
74
+ // remove and refine other patches in the same group
75
+ if (heap.delete(parent)) {
76
+ refine(parent);
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ add(micron_geometry.root);
83
+
84
+ const target_polycount_threshold = max2(
85
+ micron_geometry.source_triangle_count * fraction,
86
+ min2(
87
+ min_face_count,
88
+ micron_geometry.source_triangle_count
89
+ )
90
+ );
91
+
92
+ while (current_polycount < target_polycount_threshold) {
93
+ const p = heap.peek();
94
+
95
+ if (p === undefined || p.lod === 0) {
96
+ // no refinement possible
97
+ break;
98
+ }
99
+
100
+ heap.pop();
101
+
102
+ current_polycount -= p.polygon_count;
103
+
104
+ refine(p);
105
+ }
106
+
107
+ const result = [];
108
+
109
+ // collect
110
+ while (!heap.isEmpty()) {
111
+ result.push(heap.pop());
112
+ }
113
+
114
+ return result;
115
+ }
116
+
117
+ /**
118
+ *
119
+ * @param {MicronGeometryPatch[]} patches
120
+ * @param {VertexDataSpec} vertex_spec
121
+ * @returns {THREE.BufferGeometry}
122
+ */
123
+ function assemble_patches_to_geometry(patches, vertex_spec) {
124
+ const geo = new BufferGeometry();
125
+
126
+ //compute total number of vertices and faces
127
+ let total_faces = 0;
128
+ let total_vertices = 0;
129
+
130
+ for (let i = 0; i < patches.length; i++) {
131
+ const patch = patches[i];
132
+
133
+ total_faces += patch.polygon_count;
134
+ total_vertices += patch.vertex_count;
135
+ }
136
+
137
+ const index_data = new (UintArrayForCount(total_vertices))(total_faces * 3);
138
+
139
+ geo.setIndex(new BufferAttribute(index_data, 1, false));
140
+
141
+ const attribute_arrays = [];
142
+
143
+ const attribute_specs = vertex_spec.attributes;
144
+ const attribute_count = attribute_specs.length;
145
+ for (let i = 0; i < attribute_count; i++) {
146
+ const attribute = attribute_specs[i];
147
+
148
+ const TA = compute_typed_array_constructor_from_data_type(attribute.type);
149
+
150
+ const attribute_data = new TA(total_vertices * 3);
151
+
152
+ attribute_arrays[i] = attribute_data;
153
+
154
+ geo.setAttribute(attribute.name, new BufferAttribute(attribute_data, attribute.itemSize, attribute.normalized));
155
+ }
156
+
157
+ let index_cursor = 0;
158
+ let vertex_cursor = 0;
159
+
160
+ // add patches to resulting geometry
161
+ for (let i = 0; i < patches.length; i++) {
162
+ const patch = patches[i];
163
+
164
+ const local_index_size = patch.polygon_count * 3;
165
+
166
+ // copy transformed indices
167
+ for (let j = 0; j < local_index_size; j++) {
168
+ const local_index = patch.face_indices[j];
169
+
170
+ index_data[index_cursor + j] = local_index + vertex_cursor;
171
+ }
172
+
173
+ // copy vertex data
174
+
175
+ for (let j = 0; j < attribute_count; j++) {
176
+ const attribute_destination = attribute_arrays[j];
177
+
178
+ const attribute_source = patch.vertex_attribute_arrays[j];
179
+ const destination_offset = vertex_cursor * attribute_specs[j].itemSize;
180
+
181
+ attribute_destination.set(attribute_source, destination_offset);
182
+ }
183
+
184
+ vertex_cursor += patch.vertex_count;
185
+ index_cursor += local_index_size;
186
+ }
187
+
188
+ return geo;
189
+ }
190
+
191
+
192
+ /**
193
+ *
194
+ * @param {MicronGeometry} micron_geometry
195
+ * @param {number} fraction
196
+ * @param {number} [min_face_count]
197
+ * @returns {THREE.BufferGeometry}
198
+ */
199
+ export function micron_build_proxy_geometry(micron_geometry, fraction, min_face_count = 128) {
200
+ const patches = collect_patches(micron_geometry, fraction, min_face_count);
201
+
202
+ return assemble_patches_to_geometry(patches, micron_geometry.vertex_spec);
203
+ }
@@ -35,6 +35,25 @@ function max_polycount(object) {
35
35
  return r;
36
36
  }
37
37
 
38
+ /**
39
+ *
40
+ * @param {THREE.Object3D} object
41
+ */
42
+ function ensureProxy(object) {
43
+ if (object.isMicronMesh) {
44
+
45
+ /**
46
+ * @type {MicronGeometry}
47
+ */
48
+ const micron_geo = object.geometry;
49
+
50
+ if (micron_geo.proxy === null) {
51
+ // proxy geometry doesn't exist, build one
52
+ micron_geo.buildProxy();
53
+ }
54
+ }
55
+ }
56
+
38
57
  export class GLTFAssetTransformer extends AssetTransformer {
39
58
  /**
40
59
  *
@@ -171,6 +190,8 @@ export class GLTFAssetTransformer extends AssetTransformer {
171
190
 
172
191
  source.override_mesh = micron_root;
173
192
 
193
+ traverseThreeObject(micron_root, ensureProxy);
194
+
174
195
  return source;
175
196
  }
176
197
  }
@@ -0,0 +1,227 @@
1
+ import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
2
+ import {
3
+ AmbientLight,
4
+ CubeTextureLoader,
5
+ DirectionalLight,
6
+ FrontSide,
7
+ Mesh,
8
+ MeshBasicMaterial,
9
+ MeshStandardMaterial,
10
+ PerspectiveCamera,
11
+ PointLight,
12
+ RepeatWrapping,
13
+ Scene,
14
+ SphereGeometry,
15
+ sRGBEncoding,
16
+ TextureLoader,
17
+ VSMShadowMap,
18
+ WebGLRenderer
19
+ } from "three";
20
+ import Stats from "three/examples/jsm/libs/stats.module.js";
21
+ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
22
+ import { buildMicronGeometryFromBufferGeometry } from "./build/buildMicronGeometryFromBufferGeometry.js";
23
+
24
+ const background = new TextureLoader().load('data/textures/utility/checkers_white_grey_256x256.png');
25
+ background.repeat.set(50, 30);
26
+ background.wrapS = RepeatWrapping;
27
+ background.wrapT = RepeatWrapping;
28
+
29
+ let container, stats;
30
+
31
+ let camera, scene, renderer;
32
+ let directionalLight;
33
+ let pointLight;
34
+
35
+ let windowHalfX = window.innerWidth / 2;
36
+ let windowHalfY = window.innerHeight / 2;
37
+
38
+
39
+ function init() {
40
+
41
+ container = document.createElement("div");
42
+ document.body.appendChild(container);
43
+
44
+ camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000000);
45
+ camera.position.z = -4000;
46
+
47
+ //
48
+
49
+
50
+ scene = new Scene();
51
+
52
+ window.scene = scene;
53
+
54
+ // LIGHTS
55
+
56
+ const ambient = new AmbientLight(0xffffff, 0.1);
57
+ scene.add(ambient);
58
+
59
+ pointLight = new PointLight(0x6666ff, 0.5);
60
+ pointLight.position.y = 1000;
61
+ scene.add(pointLight);
62
+
63
+ // light representation
64
+
65
+ const sphere = new SphereGeometry(100, 16, 8);
66
+
67
+ const mesh = new Mesh(sphere, new MeshBasicMaterial({ color: 0xffffff }));
68
+ mesh.scale.set(0.5, 0.5, 0.5);
69
+ pointLight.add(mesh);
70
+
71
+ // add directional light
72
+ directionalLight = new DirectionalLight(0xFFAAAA, 0.8);
73
+ directionalLight.position.set(-500, 1000, 300);
74
+ directionalLight.castShadow = true;
75
+ const shadow_camera = directionalLight.shadow.camera;
76
+ // small bias to prevent shadow acne
77
+ directionalLight.shadow.bias = -0.0001;
78
+ // directionalLight.shadow.mapSize.set(4096, 4096);
79
+ directionalLight.shadow.mapSize.set(1024, 1024);
80
+ directionalLight.shadow.autoUpdate = false;
81
+
82
+ window.light = directionalLight;
83
+ // directionalLight.shadow.autoUpdate = true;
84
+
85
+ shadow_camera.near = 0.1;
86
+ shadow_camera.far = 2000;
87
+
88
+ const shadow_camera_size = 15;
89
+
90
+ shadow_camera.left = -shadow_camera_size / 2;
91
+ shadow_camera.right = shadow_camera_size / 2;
92
+
93
+ shadow_camera.bottom = -shadow_camera_size / 2;
94
+ shadow_camera.top = shadow_camera_size / 2;
95
+
96
+ shadow_camera.updateProjectionMatrix();
97
+
98
+
99
+ scene.add(directionalLight);
100
+ // material samples
101
+
102
+ const cubeMaterial1 = new MeshStandardMaterial({
103
+ wireframe: false,
104
+ side: FrontSide,
105
+ color: 0xffffff
106
+ });
107
+
108
+ //
109
+
110
+ renderer = new WebGLRenderer({
111
+ antialias: true,
112
+ preserveDrawingBuffer: true,
113
+ stencil: false
114
+ });
115
+
116
+ renderer.shadowMap.enabled = true;
117
+ renderer.shadowMap.type = VSMShadowMap;
118
+ // renderer.shadowMap.type = BasicShadowMap;
119
+ renderer.sortObjects = false;
120
+
121
+ renderer.setPixelRatio(window.devicePixelRatio);
122
+ renderer.setSize(window.innerWidth, window.innerHeight);
123
+ container.appendChild(renderer.domElement);
124
+
125
+ stats = new Stats();
126
+ container.appendChild(stats.dom);
127
+
128
+
129
+ window.addEventListener("resize", onWindowResize);
130
+
131
+ // envmap
132
+ const genCubeUrls = function (prefix, postfix) {
133
+
134
+ return [
135
+ prefix + "posx" + postfix, prefix + "negx" + postfix,
136
+ prefix + "posy" + postfix, prefix + "negy" + postfix,
137
+ prefix + "posz" + postfix, prefix + "negz" + postfix
138
+ ];
139
+
140
+ };
141
+
142
+ const urls = genCubeUrls("data/textures/cubemaps/hip_miramar/32/", ".png");
143
+
144
+ new CubeTextureLoader().load(urls, function (cubeTexture) {
145
+
146
+ cubeTexture.encoding = sRGBEncoding;
147
+
148
+ // scene.background = new Color(0.1, 0.1, 0.1);
149
+ // scene.background = new ThreeColor(1, 0.3, 0.3);
150
+ // scene.background = new Color(0.3, 1, 0.3);
151
+
152
+ scene.background = background;
153
+ scene.environment = cubeTexture;
154
+
155
+
156
+ // const lightProbe = new LightProbe();
157
+ //
158
+ // lightProbe.copy(LightProbeGenerator.fromCubeTexture(cubeTexture));
159
+ // lightProbe.intensity = 1.2;
160
+
161
+ // scene.add(lightProbe);
162
+ });
163
+
164
+ onWindowResize();
165
+
166
+ new PLYLoader().load("data/models/stanford/Lucy100k.ply", async geometry => {
167
+ geometry.computeVertexNormals();
168
+
169
+ const source = new Mesh(geometry, new MeshStandardMaterial({ color: 0xFFFFFF }));
170
+
171
+ const micron_g = await buildMicronGeometryFromBufferGeometry(geometry);
172
+
173
+ micron_g.buildProxy();
174
+
175
+ const proxy = new Mesh(micron_g.proxy, new MeshStandardMaterial({ color: 0xFF0000 }));
176
+
177
+ source.position.x += 700;
178
+ proxy.position.x -= 700;
179
+
180
+ console.warn(geometry, micron_g);
181
+
182
+ scene.add(source);
183
+ scene.add(proxy);
184
+ })
185
+ }
186
+
187
+ function onWindowResize() {
188
+
189
+ const w = window.innerWidth;
190
+ const h = window.innerHeight;
191
+
192
+ windowHalfX = w / 2;
193
+ windowHalfY = h / 2;
194
+
195
+ camera.aspect = w / h;
196
+ camera.updateProjectionMatrix();
197
+
198
+ renderer.setSize(w, h);
199
+
200
+ background.repeat.set(w / 20, h / 20);
201
+ }
202
+
203
+ function animate() {
204
+
205
+ requestAnimationFrame(animate);
206
+
207
+ render();
208
+ stats.update();
209
+
210
+ }
211
+
212
+ function render() {
213
+ if (orbitControls !== undefined) {
214
+ orbitControls.update();
215
+ }
216
+
217
+ const timer = -0.0002 * Date.now();
218
+
219
+ pointLight.position.x = 10000 * Math.cos(timer);
220
+ pointLight.position.z = 10000 * Math.sin(timer);
221
+
222
+ renderer.render(scene, camera);
223
+ }
224
+
225
+ init();
226
+ const orbitControls = new OrbitControls(camera, container);
227
+ animate();
@@ -6,12 +6,15 @@ import { assert } from "../../../core/assert.js";
6
6
  */
7
7
  class BinaryHeap {
8
8
  /**
9
- * @template T
10
- * @param {function(T):number} scoreFunction
9
+ * @param {(T)=>number} scoreFunction
11
10
  * @constructor
12
11
  */
13
12
  constructor(scoreFunction) {
14
13
 
14
+ /**
15
+ *
16
+ * @type {function(T): number}
17
+ */
15
18
  this.scoreFunction = scoreFunction;
16
19
 
17
20
  /**
@@ -165,6 +168,14 @@ class BinaryHeap {
165
168
  }
166
169
  }
167
170
 
171
+ /**
172
+ *
173
+ * @returns {T|undefined}
174
+ */
175
+ peek() {
176
+ return this.data[0];
177
+ }
178
+
168
179
  /**
169
180
  *
170
181
  * @param {T} node
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "productName": "Meep",
6
6
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.35.15",
8
+ "version": "2.35.16",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",