@woosh/meep-engine 2.35.14 → 2.35.15

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,42 @@
1
+ /**
2
+ *
3
+ * @param {number[]|ArrayLike<number>|Float32Array} output 6 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
4
+ * @param {number[]|ArrayLike<number>|Float32Array} input 6 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
5
+ * @param {number[]|ArrayLike<number>|Float32Array} m4 4x4 matrix
6
+ */
7
+ export function ray3_array_apply_matrix4(output, input, m4) {
8
+ const origin_x = input[0];
9
+ const origin_y = input[1];
10
+ const origin_z = input[2];
11
+
12
+ const direction_x = input[3];
13
+ const direction_y = input[4];
14
+ const direction_z = input[5];
15
+
16
+ // transform ray to local space (inlined for speed)
17
+ const inv_w = 1 / (m4[3] * origin_x + m4[7] * origin_y + m4[11] * origin_z + m4[15]);
18
+
19
+ const out_origin_x = (m4[0] * origin_x + m4[4] * origin_y + m4[8] * origin_z + m4[12]) * inv_w;
20
+ const out_origin_y = (m4[1] * origin_x + m4[5] * origin_y + m4[9] * origin_z + m4[13]) * inv_w;
21
+ const out_origin_z = (m4[2] * origin_x + m4[6] * origin_y + m4[10] * origin_z + m4[14]) * inv_w;
22
+
23
+ const out_direction_x = m4[0] * direction_x + m4[4] * direction_y + m4[8] * direction_z;
24
+ const out_direction_y = m4[1] * direction_x + m4[5] * direction_y + m4[9] * direction_z;
25
+ const out_direction_z = m4[2] * direction_x + m4[6] * direction_y + m4[10] * direction_z;
26
+
27
+ // normalize direction
28
+ const out_direction_magnitude = Math.hypot(out_direction_x, out_direction_y, out_direction_z);
29
+ const out_direction_magnitude_inverse = 1 / out_direction_magnitude;
30
+
31
+ const out_direction_normalized_x = out_direction_x * out_direction_magnitude_inverse;
32
+ const out_direction_normalized_y = out_direction_y * out_direction_magnitude_inverse;
33
+ const out_direction_normalized_z = out_direction_z * out_direction_magnitude_inverse;
34
+
35
+ output[0] = out_origin_x;
36
+ output[1] = out_origin_y;
37
+ output[2] = out_origin_z;
38
+
39
+ output[3] = out_direction_normalized_x;
40
+ output[4] = out_direction_normalized_y;
41
+ output[5] = out_direction_normalized_z;
42
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ *
3
+ * @param {number[]|ArrayLike<number>|Float32Array} output
4
+ * @param {number} origin_x
5
+ * @param {number} origin_y
6
+ * @param {number} origin_z
7
+ * @param {number} direction_x
8
+ * @param {number} direction_y
9
+ * @param {number} direction_z
10
+ */
11
+ export function ray3_array_compose(output, origin_x, origin_y, origin_z, direction_x, direction_y, direction_z) {
12
+ output[0] = origin_x;
13
+ output[1] = origin_y;
14
+ output[2] = origin_z;
15
+
16
+ output[3] = direction_x;
17
+ output[4] = direction_y;
18
+ output[5] = direction_z;
19
+ }
@@ -0,0 +1,14 @@
1
+ import { ray3_array_compose } from "./ray3_array_compose.js";
2
+
3
+ test('correctness', () => {
4
+ const result = [];
5
+ ray3_array_compose(result, 1, -3, 7, -11, 13, -17);
6
+
7
+ expect(result[0]).toBe(1);
8
+ expect(result[1]).toBe(-3);
9
+ expect(result[2]).toBe(7);
10
+
11
+ expect(result[3]).toBe(-11);
12
+ expect(result[4]).toBe(13);
13
+ expect(result[5]).toBe(-17);
14
+ });
@@ -10,6 +10,8 @@ import { aabb3_intersects_ray } from "../../../../core/bvh2/aabb3/aabb3_intersec
10
10
  import { ShadedGeometryRendererContext } from "./render/ShadedGeometryRendererContext.js";
11
11
  import { BinaryNode } from "../../../../core/bvh2/BinaryNode.js";
12
12
  import { assert } from "../../../../core/assert.js";
13
+ import { ray3_array_compose } from "../../../../core/geom/3d/ray/ray3_array_compose.js";
14
+ import { ray3_array_apply_matrix4 } from "../../../../core/geom/3d/ray/ray3_array_apply_matrix4.js";
13
15
 
14
16
  /**
15
17
  *
@@ -35,6 +37,9 @@ const scratch_point = new SurfacePoint3();
35
37
  */
36
38
  const scratch_m4 = new Float32Array(16);
37
39
 
40
+ const scratch_ray_0 = new Float32Array(6);
41
+ const scratch_ray_1 = new Float32Array(6);
42
+
38
43
  export class ShadedGeometrySystem extends System {
39
44
  /**
40
45
  *
@@ -332,29 +337,19 @@ export class ShadedGeometrySystem extends System {
332
337
  // get transform in local space
333
338
  mat4.invert(scratch_m4, m4);
334
339
 
335
- // transform ray to local space
336
- const inv_w = 1 / (scratch_m4[3] * origin_x + scratch_m4[7] * origin_y + scratch_m4[11] * origin_z + scratch_m4[15]);
337
-
338
- const local_origin_x = (scratch_m4[0] * origin_x + scratch_m4[4] * origin_y + scratch_m4[8] * origin_z + scratch_m4[12]) * inv_w;
339
- const local_origin_y = (scratch_m4[1] * origin_x + scratch_m4[5] * origin_y + scratch_m4[9] * origin_z + scratch_m4[13]) * inv_w;
340
- const local_origin_z = (scratch_m4[2] * origin_x + scratch_m4[6] * origin_y + scratch_m4[10] * origin_z + scratch_m4[14]) * inv_w;
341
-
342
- const local_direction_x = scratch_m4[0] * direction_x + scratch_m4[4] * direction_y + scratch_m4[8] * direction_z;
343
- const local_direction_y = scratch_m4[1] * direction_x + scratch_m4[5] * direction_y + scratch_m4[9] * direction_z;
344
- const local_direction_z = scratch_m4[2] * direction_x + scratch_m4[6] * direction_y + scratch_m4[10] * direction_z;
345
-
346
- const local_direction_magnitude = Math.hypot(local_direction_x, local_direction_y, local_direction_z);
347
- const local_direction_magnitude_inverse = 1 / local_direction_magnitude;
340
+ ray3_array_compose(
341
+ scratch_ray_0,
342
+ origin_x, origin_y, origin_z,
343
+ direction_x, direction_y, direction_z
344
+ );
348
345
 
349
- const local_direction_normalized_x = local_direction_x * local_direction_magnitude_inverse;
350
- const local_direction_normalized_y = local_direction_y * local_direction_magnitude_inverse;
351
- const local_direction_normalized_z = local_direction_z * local_direction_magnitude_inverse;
346
+ // transform ray to local space
347
+ ray3_array_apply_matrix4(scratch_ray_0, scratch_ray_0, scratch_m4);
352
348
 
353
- const geometry_hit_found = GeometrySpatialQueryAccelerator.INSTANCE.queryRaycastNearest_primitive(
349
+ const geometry_hit_found = GeometrySpatialQueryAccelerator.INSTANCE.queryRaycastNearest_array(
354
350
  scratch_point,
355
351
  sg.geometry,
356
- local_origin_x, local_origin_y, local_origin_z,
357
- local_direction_normalized_x, local_direction_normalized_y, local_direction_normalized_z
352
+ scratch_ray_0
358
353
  );
359
354
 
360
355
  if (!geometry_hit_found) {
@@ -373,13 +368,12 @@ export class ShadedGeometrySystem extends System {
373
368
  origin_x, origin_y, origin_z
374
369
  );
375
370
 
376
- if (distance_sqr >= best_distance) {
377
- // further than best found
378
- continue;
371
+ if (distance_sqr < best_distance) {
372
+ contact.copy(scratch_point);
373
+ best_result = sg;
374
+ best_distance = distance_sqr;
379
375
  }
380
376
 
381
- contact.copy(scratch_point);
382
- best_result = sg;
383
377
  }
384
378
  }
385
379
 
@@ -0,0 +1,212 @@
1
+ import { EngineHarness } from "../../../../EngineHarness.js";
2
+ import { ShadedGeometrySystem } from "../ShadedGeometrySystem.js";
3
+ import EntityBuilder from "../../../../ecs/EntityBuilder.js";
4
+ import { Transform } from "../../../../ecs/transform/Transform.js";
5
+ import { ShadedGeometry } from "../ShadedGeometry.js";
6
+ import {
7
+ BoxBufferGeometry,
8
+ MeshBasicMaterial,
9
+ MeshStandardMaterial,
10
+ OctahedronGeometry,
11
+ SphereBufferGeometry
12
+ } from "three";
13
+ import { randomFloatBetween } from "../../../../../core/math/random/randomFloatBetween.js";
14
+ import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
15
+ import ViewportPosition from "../../../../ecs/gui/position/ViewportPosition.js";
16
+ import GUIElement from "../../../../ecs/gui/GUIElement.js";
17
+ import ButtonView from "../../../../../view/elements/button/ButtonView.js";
18
+ import { downloadAsFile } from "../../../../../core/binary/ByteArrayTools.js";
19
+ import { convert_bvh_to_dot_format_string } from "../../../../../core/bvh2/visual/convert_bvh_to_dot_format_string.js";
20
+ import ViewportPositionSystem from "../../../../ecs/gui/position/ViewportPositionSystem.js";
21
+ import GUIElementSystem from "../../../../ecs/gui/GUIElementSystem.js";
22
+ import Vector3 from "../../../../../core/geom/Vector3.js";
23
+ import Quaternion from "../../../../../core/geom/Quaternion.js";
24
+ import { ShadedGeometryFlags } from "../ShadedGeometryFlags.js";
25
+ import { randomFromArray } from "../../../../../core/math/random/randomFromArray.js";
26
+ import { BehaviorComponent } from "../../../../intelligence/behavior/ecs/BehaviorComponent.js";
27
+ import { OrbitingBehavior } from "../../../../../../model/game/util/behavior/OrbitingBehavior.js";
28
+ import { BehaviorSystem } from "../../../../intelligence/behavior/ecs/BehaviorSystem.js";
29
+ import { MicronShadedGeometryRenderAdapter } from "../../../micron/plugin/shaded_geometry/MicronShadedGeometryRenderAdapter.js";
30
+ import { MicronRenderContext } from "../../../micron/render/v1/MicronRenderContext.js";
31
+ import { randomIntegerBetween } from "../../../../../core/math/random/randomIntegerBetween.js";
32
+ import Vector2 from "../../../../../core/geom/Vector2.js";
33
+ import { SurfacePoint3 } from "../../../../../core/geom/3d/SurfacePoint3.js";
34
+
35
+ const eh = new EngineHarness();
36
+
37
+ const DRAW_METHOD_PLAIN = 0;
38
+ const DRAW_METHOD_INSTANCED = 1;
39
+
40
+ function makeMovingShadedGeometry() {
41
+ const b = new OrbitingBehavior();
42
+ b.offset.set(4, 1, 4);
43
+ b.radius = 2;
44
+ b.rate = 1;
45
+
46
+ const sg = ShadedGeometry.from(new OctahedronGeometry(0.5, 5), new MeshStandardMaterial({ color: 0xFF0000 }));
47
+
48
+ sg.draw_method = DRAW_METHOD_INSTANCED;
49
+
50
+ return new EntityBuilder()
51
+ .add(new Transform())
52
+ .add(sg)
53
+ .add(BehaviorComponent.fromOne(b));
54
+ }
55
+
56
+ /**
57
+ *
58
+ * @param {Engine} engine
59
+ */
60
+ async function main(engine) {
61
+
62
+ const em = engine.entityManager;
63
+
64
+ const sgs = new ShadedGeometrySystem(engine);
65
+
66
+ const mrc = new MicronRenderContext();
67
+ sgs.register_render_adapter(2, () => {
68
+ const adapter = new MicronShadedGeometryRenderAdapter();
69
+ adapter.ctx = mrc;
70
+
71
+ return adapter;
72
+ });
73
+
74
+ await em.addSystem(sgs);
75
+ await em.addSystem(new BehaviorSystem(engine));
76
+
77
+ EngineHarness.buildBasics({
78
+ engine,
79
+ yaw: -0.8,
80
+ pitch: 1,
81
+ distance: 46,
82
+ focus: new Vector3(10, 0, 10)
83
+ });
84
+
85
+
86
+ const ecd = em.dataset;
87
+
88
+ const material = new MeshStandardMaterial({
89
+ color: 0xFFFFFF,
90
+ transparent: true,
91
+ opacity: 0.5
92
+ });
93
+
94
+ // material.visible = false;
95
+
96
+ window.material = material;
97
+
98
+ const random = seededRandom(0);
99
+
100
+ const INSTANCE_COUNT = 100;
101
+
102
+ const geometries = [];
103
+
104
+ for (let i = 0; i < 1; i++) {
105
+ geometries.push(new BoxBufferGeometry());
106
+ }
107
+
108
+ for (let i = 0; i < INSTANCE_COUNT; i++) {
109
+ const geometry = randomFromArray(random, geometries);
110
+ const sg = ShadedGeometry.from(geometry, material);
111
+
112
+ // sg.draw_method = DRAW_METHOD_PLAIN;
113
+ // sg.draw_method = DRAW_METHOD_INSTANCED;
114
+ // sg.draw_method = 2;
115
+ sg.draw_method = randomIntegerBetween(random, 0, 2);
116
+ // sg.draw_method = random() > 0.01 ? DRAW_METHOD_INSTANCED : DRAW_METHOD_PLAIN;
117
+ sg.clearFlag(ShadedGeometryFlags.CastShadow | ShadedGeometryFlags.ReceiveShadow);
118
+
119
+ new EntityBuilder()
120
+ .add(Transform.fromJSON({
121
+ position: {
122
+ x: randomFloatBetween(random, 0, 20),
123
+ y: randomFloatBetween(random, 0, 10),
124
+ z: randomFloatBetween(random, 0, 20)
125
+ },
126
+ rotation: Quaternion.random(random),
127
+ scale: 1
128
+ }))
129
+ .add(sg)
130
+ .build(ecd);
131
+ }
132
+
133
+ // makeMovingShadedGeometry().build(ecd);
134
+
135
+ debug_button(engine, () => {
136
+ const dot = convert_bvh_to_dot_format_string(engine.graphics.layers.getLayerByName('shaded-geometry').bvh);
137
+ downloadAsFile(dot, 'bvh.dot', 'text');
138
+
139
+ }, 'save dot file');
140
+
141
+ const raycast_marker = new EntityBuilder()
142
+ .add(ShadedGeometry.from(new SphereBufferGeometry(1), new MeshBasicMaterial({
143
+ color: 0xFF0000
144
+ })))
145
+ .add(Transform.fromJSON({
146
+ scale: 0.07
147
+ }));
148
+
149
+ raycast_marker.build(engine.entityManager.dataset);
150
+
151
+ engine.devices.pointer.position.onChanged.add((p_x, p_y) => {
152
+ const p = new Vector2(p_x, p_y);
153
+ const ndc = new Vector2();
154
+ const ray_origin = new Vector3();
155
+ const ray_direction = new Vector3();
156
+
157
+ engine.graphics.normalizeViewportPoint(p, ndc);
158
+ engine.graphics.viewportProjectionRay(ndc.x, ndc.y, ray_origin, ray_direction);
159
+
160
+ /**
161
+ *
162
+ * @type {ShadedGeometrySystem}
163
+ */
164
+ const sgm = engine.entityManager.getSystem(ShadedGeometrySystem);
165
+
166
+ const sp = new SurfacePoint3();
167
+
168
+ sgm.raycastNearest(sp, ray_origin.x, ray_origin.y, ray_origin.z, ray_direction.x, ray_direction.y, ray_direction.z, ((entity, mesh) => {
169
+ return (entity !== raycast_marker.entity);
170
+ }));
171
+
172
+ const t = raycast_marker.getComponent(Transform);
173
+
174
+ t.position.copy(sp.position);
175
+ });
176
+ }
177
+
178
+
179
+ const entityManager = engine.entityManager;
180
+
181
+ /**
182
+ *
183
+ * @param {Engine} engine
184
+ * @param {function} action
185
+ * @param {string} [name]
186
+ * @param {EntityComponentDataset} ecd
187
+ */
188
+ function debug_button(engine, action, name = "Button", ecd = entityManager.dataset) {
189
+ if (entityManager.getSystem(ViewportPositionSystem) === null) {
190
+ entityManager.addSystem(new ViewportPositionSystem(engine.graphics.viewport.size));
191
+ }
192
+
193
+ if (entityManager.getSystem(GUIElementSystem) === null) {
194
+ entityManager.addSystem(new GUIElementSystem(engine.gui.view, engine));
195
+ }
196
+
197
+ new EntityBuilder()
198
+ .add(ViewportPosition.fromJSON({}))
199
+ .add(GUIElement.fromView(new ButtonView({
200
+ action,
201
+ name,
202
+ css: {
203
+ background: 'rgba(255,255,255,0.8)',
204
+ border: '1px solid black',
205
+ borderRadius: '4px',
206
+ padding: '2px',
207
+ }
208
+ })))
209
+ .build(ecd);
210
+ }
211
+
212
+ eh.initialize().then(main);
@@ -56,6 +56,22 @@ export class GeometrySpatialQueryAccelerator {
56
56
  return this.__visitor_clip.getContainment();
57
57
  }
58
58
 
59
+ /**
60
+ *
61
+ * @param {SurfacePoint3} destination
62
+ * @param {THREE.BufferGeometry} geometry
63
+ * @param {number[]|ArrayLike<number>|Float32Array} ray 6 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
64
+ * @return {boolean}
65
+ */
66
+ queryRaycastNearest_array(destination, geometry, ray) {
67
+ return this.queryRaycastNearest_primitive(
68
+ destination,
69
+ geometry,
70
+ ray[0], ray[1], ray[2],
71
+ ray[3], ray[4], ray[5]
72
+ );
73
+ }
74
+
59
75
  /**
60
76
  *
61
77
  * @param {SurfacePoint3} destination
@@ -1,3 +1,6 @@
1
+ import { compose_matrix4_array } from "./composeMatrix4.js";
2
+ import Vector3 from "../../../core/geom/Vector3.js";
3
+
1
4
  /**
2
5
  *
3
6
  * @param {Matrix4} result
@@ -7,31 +10,5 @@
7
10
  export function composeMatrix4RotationScale(result, rotation, scale) {
8
11
  const te = result.elements;
9
12
 
10
- const x = rotation.x, y = rotation.y, z = rotation.z, w = rotation.w;
11
- const x2 = x + x, y2 = y + y, z2 = z + z;
12
- const xx = x * x2, xy = x * y2, xz = x * z2;
13
- const yy = y * y2, yz = y * z2, zz = z * z2;
14
- const wx = w * x2, wy = w * y2, wz = w * z2;
15
-
16
- const sx = scale.x, sy = scale.y, sz = scale.z;
17
-
18
- te[0] = (1 - (yy + zz)) * sx;
19
- te[1] = (xy + wz) * sx;
20
- te[2] = (xz - wy) * sx;
21
- te[3] = 0;
22
-
23
- te[4] = (xy - wz) * sy;
24
- te[5] = (1 - (xx + zz)) * sy;
25
- te[6] = (yz + wx) * sy;
26
- te[7] = 0;
27
-
28
- te[8] = (xz + wy) * sz;
29
- te[9] = (yz - wx) * sz;
30
- te[10] = (1 - (xx + yy)) * sz;
31
- te[11] = 0;
32
-
33
- te[12] = 0;
34
- te[13] = 0;
35
- te[14] = 0;
36
- te[15] = 1;
13
+ compose_matrix4_array(te, Vector3.zero, rotation, scale);
37
14
  }
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.14",
8
+ "version": "2.35.15",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",