@woosh/meep-engine 2.43.6 → 2.43.8

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 (33) hide show
  1. package/core/geom/3d/SurfacePoint3.js +8 -0
  2. package/core/geom/3d/aabb/compute_aabb_from_points.js +1 -1
  3. package/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +10 -4
  4. package/core/geom/3d/topology/samples/sampleFloodFill.js +275 -0
  5. package/core/geom/3d/topology/simplify/prototypeMeshSimplification.js +5 -6
  6. package/core/geom/3d/topology/struct/TopoMesh.js +17 -0
  7. package/core/geom/3d/topology/three_buffer_geometry_to_topo_mesh.js +30 -0
  8. package/core/geom/3d/topology/{topoMeshToBufferGeometry.js → topo_mesh_to_three_buffer_geometry.js} +1 -1
  9. package/core/geom/3d/topology/util/mesh_flood_fill.js +61 -0
  10. package/engine/Engine.js +1 -1
  11. package/engine/EngineHarness.js +5 -5
  12. package/engine/ecs/parent/EntityNode.js +1 -2
  13. package/engine/graphics/GraphicsEngine.js +5 -2
  14. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +1 -1
  15. package/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +10 -0
  16. package/engine/graphics/geometry/buffered/makeGeometryIndexed.js +5 -4
  17. package/engine/graphics/geometry/buffered/query/RaycastNearestHitComputingVisitor.js +6 -5
  18. package/engine/graphics/impostors/octahedral/README.md +4 -0
  19. package/engine/graphics/impostors/octahedral/prototypeBaker.js +6 -5
  20. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +194 -20
  21. package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +2 -2
  22. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +1 -31
  23. package/engine/graphics/micron/plugin/shaded_geometry/MicronShadedGeometryRenderAdapter.js +23 -5
  24. package/engine/graphics/micron/simplifyGeometry.js +4 -2
  25. package/engine/graphics/sh3/LightProbeVolume.js +28 -5
  26. package/engine/graphics/sh3/README.md +3 -0
  27. package/engine/graphics/sh3/SH3VisualisationMaterial.js +1 -0
  28. package/engine/graphics/sh3/prototypeSH3Probe.js +26 -21
  29. package/engine/graphics/shadows/README.md +6 -0
  30. package/engine/input/devices/PointerDevice.js +28 -0
  31. package/package.json +1 -1
  32. package/samples/terrain/from_image_2.js +1 -45
  33. package/view/elements/navigation/ViewStack.js +4 -2
@@ -8,6 +8,13 @@ export class SurfacePoint3 {
8
8
  constructor() {
9
9
  this.normal = new Vector3(0, 1, 0);
10
10
  this.position = new Vector3(0, 0, 0);
11
+
12
+ /**
13
+ * Primitive index, such as triangle/point/line from the source geometry
14
+ * optional
15
+ * @type {number}
16
+ */
17
+ this.index = -1;
11
18
  }
12
19
 
13
20
  /**
@@ -70,6 +77,7 @@ export class SurfacePoint3 {
70
77
  copy(other) {
71
78
  this.position.copy(other.position);
72
79
  this.normal.copy(other.normal);
80
+ this.index = other.index;
73
81
  }
74
82
 
75
83
  /**
@@ -19,7 +19,7 @@ export function compute_aabb_from_points(result, input, input_count, d) {
19
19
 
20
20
  for (i = 0; i < input_count; i++) {
21
21
  for (j = 0; j < d; j++) {
22
- const v = input[j];
22
+ const v = input[i*d + j];
23
23
 
24
24
  result[j] = min2(result[j], v);
25
25
  result[j + d] = max2(result[j + d], v);
@@ -71,8 +71,8 @@ function Kml(m, l) {
71
71
 
72
72
  /**
73
73
  * compute Index of spherical harmonics coefficient
74
- * @param {number} m
75
- * @param {number} l
74
+ * @param {number} m signed offset from zonal harmonic
75
+ * @param {number} l band
76
76
  * @return {number}
77
77
  */
78
78
  function SHindex(m, l) {
@@ -239,7 +239,7 @@ function rotateShericalHarmonicBand1(band1, M) {
239
239
  mat3.scale(invA1TimesK, invA1TimesK, band1);
240
240
 
241
241
 
242
- mat3.multiply(R1OverK, R1OverK, invA1TimesK );
242
+ mat3.multiply(R1OverK, R1OverK, invA1TimesK);
243
243
 
244
244
  return R1OverK;
245
245
  }
@@ -568,6 +568,7 @@ function windowSH(output, output_offset, input, input_offset, numBands, channel_
568
568
  for (let channel = 0; channel < channel_count; channel++) {
569
569
 
570
570
  for (let i = 0; i < numBands * numBands; i++) {
571
+ // copy this channel
571
572
  SH[i] = output[output_offset + i * channel_count + channel];
572
573
  }
573
574
 
@@ -583,19 +584,24 @@ function windowSH(output, output_offset, input, input_offset, numBands, channel_
583
584
  }
584
585
  }
585
586
 
587
+ // record minimum cutoff
586
588
  cutoff = min2(cutoff, l);
587
589
  }
588
590
  }
589
591
 
590
592
  array_copy(input, input_offset, output, output_offset, numBands * numBands * channel_count);
591
593
 
594
+
592
595
  for (let l = 0; l < numBands; l++) {
596
+ // scale each band individually
593
597
  let w = sincWindow(l, cutoff);
594
598
 
599
+ // write zonal harmonic
595
600
  for (let i = 0; i < channel_count; i++) {
596
- output[output_offset + SHindex(0, l) * channel_count + i] = w;
601
+ output[output_offset + SHindex(0, l) * channel_count + i] *= w;
597
602
  }
598
603
 
604
+ // write the rest of the band
599
605
  for (let m = 1; m <= l; m++) {
600
606
  for (let i = 0; i < channel_count; i++) {
601
607
  output[output_offset + SHindex(-m, l) * channel_count + i] *= w;
@@ -0,0 +1,275 @@
1
+ import { EngineHarness } from "../../../../../engine/EngineHarness.js";
2
+ import { MeshBasicMaterial, MeshStandardMaterial, OctahedronBufferGeometry } from "three";
3
+ import EntityBuilder from "../../../../../engine/ecs/EntityBuilder.js";
4
+ import { ShadedGeometry } from "../../../../../engine/graphics/ecs/mesh-v2/ShadedGeometry.js";
5
+ import { Transform } from "../../../../../engine/ecs/transform/Transform.js";
6
+ import Vector3 from "../../../Vector3.js";
7
+ import { ShadedGeometrySystem } from "../../../../../engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js";
8
+ import { SurfacePoint3 } from "../../SurfacePoint3.js";
9
+ import { topo_mesh_to_three_buffer_geometry } from "../topo_mesh_to_three_buffer_geometry.js";
10
+ import { three_buffer_geometry_to_topo_mesh } from "../three_buffer_geometry_to_topo_mesh.js";
11
+ import { mesh_flood_fill } from "../util/mesh_flood_fill.js";
12
+ import { compute_aabb_from_points } from "../../aabb/compute_aabb_from_points.js";
13
+ import { AABB3 } from "../../../../bvh2/aabb3/AABB3.js";
14
+ import { mergeVertices } from "three/examples/jsm/utils/BufferGeometryUtils.js";
15
+ import { makeGeometryIndexed } from "../../../../../engine/graphics/geometry/buffered/makeGeometryIndexed.js";
16
+ import { v3_dot } from "../../../v3_dot.js";
17
+ import { TopoMesh } from "../struct/TopoMesh.js";
18
+ import { SGMeshSystem } from "../../../../../engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js";
19
+ import { SGMesh } from "../../../../../engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js";
20
+ import { GameAssetType } from "../../../../../engine/asset/GameAssetType.js";
21
+ import { GLTFAssetLoader } from "../../../../../engine/asset/loaders/GLTFAssetLoader.js";
22
+ import { computeTriangleSurfaceArea } from "../../../../../engine/graphics/geometry/computeMeshSurfaceArea.js";
23
+ import { SGMeshEvents } from "../../../../../engine/graphics/ecs/mesh-v2/aggregate/SGMeshEvents.js";
24
+ import { Color } from "../../../../color/Color.js";
25
+ import { seededRandom } from "../../../../math/random/seededRandom.js";
26
+ import { expandConnectivityByLocality } from "../expandConnectivityByLocality.js";
27
+ import { buildCubeURLs } from "../../../../../engine/graphics/texture/cubemap/buildCubeURLs.js";
28
+ import { EntityNode } from "../../../../../engine/ecs/parent/EntityNode.js";
29
+ import { TransformAttachmentSystem } from "../../../../../engine/ecs/transform-attachment/TransformAttachmentSystem.js";
30
+
31
+ const harness = new EngineHarness();
32
+
33
+ /**
34
+ *
35
+ * @param {TopoMesh} mesh
36
+ * @param {TopoTriangle[]} faces
37
+ * @param {EntityNode} entity
38
+ */
39
+ function set_highlight({
40
+ mesh,
41
+ faces,
42
+ entity
43
+ }) {
44
+
45
+ entity.children.slice().forEach(e => {
46
+ entity.removeChild(e);
47
+
48
+ e.destroy();
49
+ });
50
+
51
+
52
+ const m = new TopoMesh();
53
+
54
+ const vertex_map = new Map();
55
+
56
+ faces.forEach(f => {
57
+ m.addFaceCopy(f, vertex_map);
58
+ });
59
+
60
+ const selected_geo = topo_mesh_to_three_buffer_geometry(m);
61
+
62
+ entity.addChild(EntityNode.fromComponents(
63
+ new Transform(),
64
+ ShadedGeometry.from(selected_geo, new MeshBasicMaterial({
65
+ transparent: true,
66
+ opacity: 0.7,
67
+ color: '#00c4ff',
68
+ depthTest: true
69
+ }))
70
+ ));
71
+
72
+ entity.addChild(EntityNode.fromComponents(
73
+ new Transform(),
74
+ ShadedGeometry.from(selected_geo,new MeshBasicMaterial({
75
+ wireframe: true,
76
+ transparent: true,
77
+ opacity: 0.7,
78
+ color: '#ffffff',
79
+ depthTest: false
80
+ }))
81
+ ))
82
+
83
+ }
84
+
85
+ /**
86
+ *
87
+ * @param {Engine} engine
88
+ * @return {Promise<void>}
89
+ */
90
+ async function main(engine) {
91
+ await EngineHarness.buildBasics({
92
+ engine,
93
+ focus: { x: -10.283977088703375, y: 1.7301942199921359, z: -0.3232510720362 },
94
+ pitch: 0.2700000000000029,
95
+ distance: 17,
96
+ yaw: -Math.PI / 2,
97
+ cameraFarDistance: 100,
98
+ enableTerrain: false
99
+ });
100
+
101
+ engine.graphics.loadEnvironmentMap(buildCubeURLs('data/textures/cubemaps/hip_miramar/32/', '.png'));
102
+
103
+ const path = 'data/models/sponza-pbr/gltf/sponza.glb';
104
+
105
+ const ecd = engine.entityManager.dataset;
106
+
107
+ const entityBuilder = new EntityBuilder();
108
+ entityBuilder
109
+ .add(SGMesh.fromURL(path))
110
+ .add(Transform.fromJSON({}))
111
+ .build(ecd);
112
+
113
+ const random = seededRandom();
114
+
115
+ entityBuilder.addEventListener(SGMeshEvents.AssetLoaded, () => {
116
+ /**
117
+ *
118
+ * @type {EntityNode}
119
+ */
120
+ const node = entityBuilder.getComponent(SGMesh).__node;
121
+
122
+ node.traverse(n => {
123
+
124
+ const sg = n.entity.getComponent(ShadedGeometry);
125
+
126
+ if (sg === null) {
127
+ return;
128
+ }
129
+
130
+ n.entity.removeComponent(ShadedGeometry);
131
+
132
+ let hue =0;
133
+
134
+ do {
135
+ hue = random();
136
+
137
+ }while(Math.abs(hue - 0.53855555555) < 0.11); // shift away from hue of selection mask
138
+
139
+ sg.material = new MeshStandardMaterial({
140
+ color: Color.fromHSV(hue, 0.9, 0.9).toHex()
141
+ });
142
+
143
+ n.entity.add(sg);
144
+
145
+ });
146
+ });
147
+
148
+ // create a mesh
149
+ let source_geo = new OctahedronBufferGeometry(5, 3);
150
+
151
+ makeGeometryIndexed(source_geo);
152
+ source_geo = mergeVertices(source_geo, 0.002);
153
+
154
+ const entity_source = new EntityBuilder();
155
+ entity_source
156
+ .add(ShadedGeometry.from(source_geo, new MeshStandardMaterial({
157
+ color: '#b60000'
158
+ })))
159
+ .add(Transform.fromJSON({
160
+ position: {
161
+ x: 10, y: 6, z: 15
162
+ }
163
+ }))
164
+ .build(ecd);
165
+
166
+ const highlight = new EntityNode();
167
+ highlight.entity.add(new Transform());
168
+
169
+
170
+ engine.devices.pointer.on.tap.add(
171
+ /**
172
+ *
173
+ * @param {Vector2} position
174
+ * @param {MouseEvent|TouchEvent} event
175
+ */
176
+ (position, event) => {
177
+ if (event instanceof MouseEvent) {
178
+ if ((event.buttons & (1)) !== 0) {
179
+ return;
180
+ }
181
+ }
182
+
183
+ /**
184
+ *
185
+ * @type {ShadedGeometrySystem}
186
+ */
187
+ const sgs = engine.entityManager.getSystem(ShadedGeometrySystem);
188
+
189
+ const contact = new SurfacePoint3();
190
+
191
+ const ray_origin = new Vector3();
192
+ const ray_direction = new Vector3();
193
+
194
+ engine.graphics.normalizeViewportPoint(position, position);
195
+ engine.graphics.viewportProjectionRay(position.x, position.y, ray_origin, ray_direction);
196
+
197
+ highlight.destroy();
198
+
199
+ const raycast_result = sgs.raycastNearest(contact, ray_origin.x, ray_origin.y, ray_origin.z, ray_direction.x, ray_direction.y, ray_direction.z);
200
+
201
+ if (raycast_result !== undefined) {
202
+ //got a hit
203
+
204
+ const sg = raycast_result.mesh;
205
+ makeGeometryIndexed(sg.geometry);
206
+ const geometry = mergeVertices(sg.geometry);
207
+ // console.warn(raycast_result, contact, geometry);
208
+
209
+
210
+ const topo = three_buffer_geometry_to_topo_mesh(geometry);
211
+
212
+ const aabb_array = [];
213
+ const position_attribute = geometry.getAttribute('position');
214
+ compute_aabb_from_points(aabb_array, position_attribute.array, position_attribute.count, 3);
215
+ const aabb3 = new AABB3(...aabb_array);
216
+ //
217
+ // weld_duplicate_vertices(topo, aabb3);
218
+ expandConnectivityByLocality(topo, aabb3);
219
+
220
+ // identify triangle that was clicked
221
+ const face = topo.getFaceByIndex(contact.index);
222
+
223
+ const selection = mesh_flood_fill({
224
+ mesh: topo,
225
+ initial_set: [face],
226
+ filter(current, prev) {
227
+ current.computeNormal();
228
+
229
+ const area = computeTriangleSurfaceArea(
230
+ current.vertices[0].x,
231
+ current.vertices[0].z,
232
+ current.vertices[0].y,
233
+
234
+ current.vertices[1].x,
235
+ current.vertices[1].z,
236
+ current.vertices[1].y,
237
+
238
+ current.vertices[2].x,
239
+ current.vertices[2].z,
240
+ current.vertices[2].y,
241
+ );
242
+
243
+ if (area < 0.0003) {
244
+ // area very small, allow jumping across
245
+ return true;
246
+ }
247
+
248
+ return v3_dot(current.normal[0], current.normal[1], current.normal[2], contact.normal.x, contact.normal.y, contact.normal.z) >= 0.8;
249
+ // return true;
250
+ }
251
+ });
252
+
253
+ // console.log(`selection: ${selection.length}`, selection);
254
+
255
+ highlight.transform.copy(ecd.getComponent(raycast_result.entity, Transform));
256
+ set_highlight({
257
+ mesh: topo, faces: selection, entity: highlight
258
+ });
259
+
260
+ highlight.build(ecd);
261
+ }
262
+ });
263
+ }
264
+
265
+ harness.initialize({
266
+ configuration(config, engine) {
267
+ config.addSystem(new ShadedGeometrySystem(engine));
268
+ config.addSystem(new TransformAttachmentSystem());
269
+ config.addSystem(new SGMeshSystem(engine));
270
+
271
+ const loader = new GLTFAssetLoader();
272
+ config.addLoader(GameAssetType.ModelGLTF_JSON, loader)
273
+ config.addLoader(GameAssetType.ModelGLTF, loader)
274
+ }
275
+ }).then(main);
@@ -24,7 +24,7 @@ import { mergeVertices } from "three/examples/jsm/utils/BufferGeometryUtils.js";
24
24
  import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
25
25
  import Stats from "three/examples/jsm/libs/stats.module.js";
26
26
  import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
27
- import { topoMeshToBufferGeometry } from "../topoMeshToBufferGeometry.js";
27
+ import { topo_mesh_to_three_buffer_geometry } from "../topo_mesh_to_three_buffer_geometry.js";
28
28
  import { TopoMesh } from "../struct/TopoMesh.js";
29
29
  import {
30
30
  deinterleaveBufferGeometry
@@ -36,6 +36,7 @@ import { computeTopoMeshBoundiningBox } from "../bounds/computeTopoMeshBoundinin
36
36
  import { AABB3 } from "../../../../bvh2/aabb3/AABB3.js";
37
37
  import { Color } from "../../../../color/Color.js";
38
38
  import { clamp } from "../../../../math/clamp.js";
39
+ import { three_buffer_geometry_to_topo_mesh } from "../three_buffer_geometry_to_topo_mesh.js";
39
40
 
40
41
 
41
42
  /**
@@ -290,15 +291,13 @@ function init() {
290
291
  label_steps = true
291
292
  }) {
292
293
 
293
- const topology = new TopoMesh();
294
- const faces_array = geo.getIndex().array;
295
- topology.build(geo.getAttribute('position').array, faces_array);
294
+ const topology = three_buffer_geometry_to_topo_mesh(geo);
296
295
 
297
296
  for (let i = 0; i < steps; i++) {
298
297
  if (i === 11) debugger;
299
298
  simplifyTopoMesh2(topology, 1);
300
299
 
301
- const simplified_bg = topoMeshToBufferGeometry(topology);
300
+ const simplified_bg = topo_mesh_to_three_buffer_geometry(topology);
302
301
  simplified_bg.computeVertexNormals();
303
302
 
304
303
  const proxy = build_preview_object({ geometry: simplified_bg, color: 'rgb(255,90,90)' });
@@ -372,7 +371,7 @@ function init() {
372
371
  console.timeEnd('simplification');
373
372
 
374
373
  console.time('topo -> buffer geo');
375
- const simplified_bg = topoMeshToBufferGeometry(mesh);
374
+ const simplified_bg = topo_mesh_to_three_buffer_geometry(mesh);
376
375
  console.timeEnd('topo -> buffer geo');
377
376
 
378
377
  simplified_bg.computeVertexNormals();
@@ -51,6 +51,23 @@ export class TopoMesh {
51
51
  return this.__faces;
52
52
  }
53
53
 
54
+ /**
55
+ *
56
+ * @param {number} index
57
+ * @return {undefined|TopoTriangle}
58
+ */
59
+ getFaceByIndex(index) {
60
+ assert.isNonNegativeInteger(index, 'index');
61
+
62
+ for (const face of this.__faces) {
63
+ if (face.index === index) {
64
+ return face;
65
+ }
66
+ }
67
+
68
+ return undefined;
69
+ }
70
+
54
71
  /**
55
72
  *
56
73
  * @param {function(reason:string)} error_consumer
@@ -0,0 +1,30 @@
1
+ import { TopoMesh } from "./struct/TopoMesh.js";
2
+
3
+ /**
4
+ *
5
+ * @param {THREE.BufferGeometry} geo
6
+ * @return {TopoMesh}
7
+ */
8
+ export function three_buffer_geometry_to_topo_mesh(geo) {
9
+ const topology = new TopoMesh();
10
+ let faces_array;
11
+
12
+
13
+ const position_attribute = geo.getAttribute('position');
14
+
15
+ const geo_index = geo.getIndex();
16
+
17
+ if (geo_index !== null) {
18
+ faces_array = geo_index.array;
19
+ } else {
20
+ faces_array = new Uint32Array(position_attribute.count );
21
+
22
+ for (let i = 0; i < faces_array.length; i++) {
23
+ faces_array[i] = i;
24
+ }
25
+ }
26
+
27
+ topology.build(position_attribute.array, faces_array);
28
+
29
+ return topology;
30
+ }
@@ -5,7 +5,7 @@ import { BufferAttribute, BufferGeometry } from "three";
5
5
  * @param {TopoMesh} mesh
6
6
  * @returns {THREE.BufferGeometry}
7
7
  */
8
- export function topoMeshToBufferGeometry(mesh) {
8
+ export function topo_mesh_to_three_buffer_geometry(mesh) {
9
9
  const vertices_lookup = new Map();
10
10
 
11
11
  // build vertices array
@@ -0,0 +1,61 @@
1
+ import { BitSet } from "../../../../binary/BitSet.js";
2
+
3
+ /**
4
+ *
5
+ * @type {TopoTriangle[]}
6
+ */
7
+ const neighbours = [];
8
+
9
+ /**
10
+ *
11
+ * @param {TopoMesh} mesh
12
+ * @param {TopoTriangle[]} initial_set indices of triangles that make up initial set, these are triangles that we start from, they will also be included in the resulting set
13
+ * @param {function(tri:TopoTriangle, prev:TopoTriangle):boolean} filter decides whether a triangle should be included or not
14
+ * @returns {TopoTriangle[]} set of selected triangles, will include initial set as well
15
+ */
16
+ export function mesh_flood_fill({
17
+ mesh,
18
+ initial_set,
19
+ filter
20
+ }) {
21
+
22
+ const closed = new BitSet();
23
+ const open = [...initial_set];
24
+
25
+ const result_set = [];
26
+
27
+ while (open.length > 0) {
28
+ const current = open.pop();
29
+
30
+ closed.set(current.index, true);
31
+
32
+ result_set.push(current);
33
+
34
+ // get neighbours
35
+
36
+ const neighbour_count = current.getEdgeNeighbours(neighbours, 0);
37
+
38
+ for (let i = 0; i < neighbour_count; i++) {
39
+ const neighbour_face = neighbours[i];
40
+
41
+ if (closed.get(neighbour_face.index)) {
42
+ continue;
43
+ }
44
+
45
+ if (!filter(neighbour_face, current)) {
46
+ // rejected by filter
47
+ continue;
48
+ }
49
+
50
+ if (open.includes(neighbour_face)) {
51
+ // already included
52
+ continue;
53
+ }
54
+
55
+ open.push(neighbour_face);
56
+ }
57
+
58
+ }
59
+
60
+ return result_set;
61
+ }
package/engine/Engine.js CHANGED
@@ -305,7 +305,7 @@ class Engine {
305
305
  gameView.addChild(viewport);
306
306
 
307
307
  this.viewStack = new ViewStack();
308
- this.viewStack.push(gameView);
308
+ this.viewStack.push(gameView,'game-view');
309
309
 
310
310
  //bind size of renderer viewport to game view
311
311
  viewport.bindSignal(gameView.size.onChanged, viewport.size.set.bind(viewport.size));
@@ -260,7 +260,7 @@ export class EngineHarness {
260
260
  }) {
261
261
 
262
262
  if (enableLights) {
263
- EngineHarness.buildLights({ engine: engine, shadowmapResolution });
263
+ await EngineHarness.buildLights({ engine: engine, shadowmapResolution });
264
264
  }
265
265
 
266
266
  const camera = EngineHarness.buildCamera({
@@ -307,11 +307,11 @@ export class EngineHarness {
307
307
  * @param {EntityComponentDataset} ecd
308
308
  * @param shadowmapResolution
309
309
  */
310
- static buildLights({ engine, ecd = engine.entityManager.dataset, shadowmapResolution = 1024 }) {
310
+ static async buildLights({ engine, ecd = engine.entityManager.dataset, shadowmapResolution = 1024 }) {
311
311
  const em = engine.entityManager;
312
312
 
313
- if (em.getSystem(LightSystem) === null) {
314
- em.addSystem(new LightSystem(engine, {
313
+ if (!em.hasSystem(LightSystem)) {
314
+ await em.addSystem(new LightSystem(engine, {
315
315
  shadowResolution: shadowmapResolution
316
316
  }));
317
317
  }
@@ -345,7 +345,7 @@ export class EngineHarness {
345
345
  const fill = new Light();
346
346
  fill.type.set(Light.Type.AMBIENT);
347
347
  fill.color.setRGB(1, 1, 1);
348
- fill.intensity.set(0.4);
348
+ fill.intensity.set(0.1);
349
349
 
350
350
 
351
351
  new EntityBuilder()
@@ -233,7 +233,7 @@ export class EntityNode {
233
233
 
234
234
  // live mode
235
235
  if (this.__entity.isBuilt) {
236
- // TODO attach node live
236
+ node.build(this.__entity.dataset);
237
237
  }
238
238
 
239
239
  return true;
@@ -256,7 +256,6 @@ export class EntityNode {
256
256
 
257
257
  node.parent = null;
258
258
 
259
-
260
259
  return true;
261
260
  }
262
261
 
@@ -486,8 +486,11 @@ GraphicsEngine.prototype.normalizeViewportPoint = function (input, result) {
486
486
 
487
487
  const viewportSize = this.viewport.size;
488
488
 
489
- result.x = (input.x / viewportSize.x) * 2 - 1;
490
- result.y = -(input.y / viewportSize.y) * 2 + 1;
489
+ const _x = input.x;
490
+ const _y = input.y;
491
+
492
+ result.x = (_x / viewportSize.x) * 2 - 1;
493
+ result.y = -(_y / viewportSize.y) * 2 + 1;
491
494
  };
492
495
 
493
496
  /**
@@ -324,7 +324,7 @@ export class ShadedGeometry {
324
324
  *
325
325
  * @param {SurfacePoint3} contact if found, contact is written here
326
326
  * @param {ArrayLike<number>|number[]|Float32Array} ray 6-tuple: [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
327
- * @param {ArrayLike<number>|number[]|Float32Array} transform_matrix4
327
+ * @param {ArrayLike<number>|number[]|Float32Array} transform_matrix4 transform applied to the geometry
328
328
  * @returns {boolean}
329
329
  */
330
330
  query_raycast_nearest(contact, ray, transform_matrix4) {
@@ -9,6 +9,7 @@ import { SGMeshEvents } from "./SGMeshEvents.js";
9
9
  import { ParentEntity } from "../../../../ecs/parent/ParentEntity.js";
10
10
  import { EntityNode } from "../../../../ecs/parent/EntityNode.js";
11
11
  import { min2 } from "../../../../../core/math/min2.js";
12
+ import { TransformAttachmentSystem } from "../../../../ecs/transform-attachment/TransformAttachmentSystem.js";
12
13
 
13
14
 
14
15
  /**
@@ -69,6 +70,15 @@ export class SGMeshSystem extends System {
69
70
  this.__asset_object_cache = new Map();
70
71
  }
71
72
 
73
+ async startup(em, ready_callback, error_callback) {
74
+
75
+ if (!em.hasSystem(TransformAttachmentSystem)) {
76
+ await em.addSystem(new TransformAttachmentSystem());
77
+ }
78
+
79
+ super.startup(em, ready_callback, error_callback);
80
+ }
81
+
72
82
  /**
73
83
  *
74
84
  * @param {number} entity
@@ -1,4 +1,4 @@
1
- import { Float32BufferAttribute } from "three";
1
+ import { Uint32BufferAttribute } from "three";
2
2
 
3
3
  /**
4
4
  *
@@ -10,13 +10,14 @@ export function makeGeometryIndexed(geometry) {
10
10
  if (index_attribute === null || index_attribute === undefined) {
11
11
  const position_attribute = geometry.getAttribute('position');
12
12
  // non-indexed geometry, build index
13
- const array = new Float32Array(position_attribute.count * 3);
13
+ const size = position_attribute.count;
14
+ const array = new Uint32Array(size);
14
15
 
15
- for (let i = 0; i < array.length; i++) {
16
+ for (let i = 0; i < size; i++) {
16
17
  array[i] = i;
17
18
  }
18
19
 
19
- index_attribute = new Float32BufferAttribute(array, 1, false);
20
+ index_attribute = new Uint32BufferAttribute(array, 1, false);
20
21
 
21
22
  geometry.setIndex(index_attribute);
22
23
  }