@woosh/meep-engine 2.35.12 → 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.
- package/core/geom/3d/ray/ray3_array_apply_matrix4.js +42 -0
- package/core/geom/3d/ray/ray3_array_compose.js +19 -0
- package/core/geom/3d/ray/ray3_array_compose.spec.js +14 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +48 -25
- package/engine/graphics/ecs/mesh-v2/sample/prototype_sg_raycast.js +212 -0
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +6 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.d.ts +1 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.js +29 -2
- package/engine/graphics/ecs/path/tube/build/TubePathBuilder.js +42 -21
- package/engine/graphics/ecs/path/tube/build/build_geometry_catmullrom.js +41 -12
- package/engine/graphics/ecs/path/tube/build/build_geometry_linear.js +43 -3
- package/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +28 -16
- package/engine/graphics/ecs/path/tube/build/makeTubeGeometry.js +11 -6
- package/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +16 -0
- package/engine/graphics/util/composeMatrix4RotationScale.js +4 -27
- package/engine/navigation/ecs/components/Path.js +5 -6
- package/package.json +1 -1
|
@@ -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
|
*
|
|
@@ -74,6 +79,13 @@ export class ShadedGeometrySystem extends System {
|
|
|
74
79
|
* @private
|
|
75
80
|
*/
|
|
76
81
|
this.__adapter_suppliers = new Map();
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Keeps count of usage for each geometry by ID
|
|
85
|
+
* @type {Map<number, number>}
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
this.__geometry_usage_counters = new Map();
|
|
77
89
|
}
|
|
78
90
|
|
|
79
91
|
/**
|
|
@@ -166,7 +178,7 @@ export class ShadedGeometrySystem extends System {
|
|
|
166
178
|
this.__render_layer.buildVisibleSet = ((destination, destination_offset, view) => {
|
|
167
179
|
const ctx = this.__view_contexts.get(view);
|
|
168
180
|
|
|
169
|
-
return ctx.collect(destination, destination_offset,graphics.renderer, view, this.__bvh);
|
|
181
|
+
return ctx.collect(destination, destination_offset, graphics.renderer, view, this.__bvh);
|
|
170
182
|
});
|
|
171
183
|
|
|
172
184
|
readyCallback();
|
|
@@ -210,6 +222,13 @@ export class ShadedGeometrySystem extends System {
|
|
|
210
222
|
sg.__entity = entity;
|
|
211
223
|
|
|
212
224
|
this.__bvh.insertNode(leaf_node);
|
|
225
|
+
|
|
226
|
+
// update usage count
|
|
227
|
+
const geometry_id = sg.geometry.id;
|
|
228
|
+
const count_existing = this.__geometry_usage_counters.get(geometry_id);
|
|
229
|
+
const count_new = count_existing !== undefined ? count_existing + 1 : 1;
|
|
230
|
+
|
|
231
|
+
this.__geometry_usage_counters.set(geometry_id, count_new);
|
|
213
232
|
}
|
|
214
233
|
|
|
215
234
|
/**
|
|
@@ -224,6 +243,21 @@ export class ShadedGeometrySystem extends System {
|
|
|
224
243
|
t.scale.onChanged.remove(sg.updateTransform, sg);
|
|
225
244
|
|
|
226
245
|
sg.bvh.disconnect();
|
|
246
|
+
|
|
247
|
+
const geometry_id = sg.geometry.id;
|
|
248
|
+
const count_existing = this.__geometry_usage_counters.get(geometry_id);
|
|
249
|
+
|
|
250
|
+
if (count_existing === 1) {
|
|
251
|
+
|
|
252
|
+
// last instance
|
|
253
|
+
this.__geometry_usage_counters.delete(geometry_id);
|
|
254
|
+
|
|
255
|
+
// release GPU memory
|
|
256
|
+
sg.geometry.dispose();
|
|
257
|
+
|
|
258
|
+
} else {
|
|
259
|
+
this.__geometry_usage_counters.set(geometry_id, count_existing - 1);
|
|
260
|
+
}
|
|
227
261
|
}
|
|
228
262
|
|
|
229
263
|
/**
|
|
@@ -303,29 +337,19 @@ export class ShadedGeometrySystem extends System {
|
|
|
303
337
|
// get transform in local space
|
|
304
338
|
mat4.invert(scratch_m4, m4);
|
|
305
339
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const local_origin_z = (scratch_m4[2] * origin_x + scratch_m4[6] * origin_y + scratch_m4[10] * origin_z + scratch_m4[14]) * inv_w;
|
|
312
|
-
|
|
313
|
-
const local_direction_x = scratch_m4[0] * direction_x + scratch_m4[4] * direction_y + scratch_m4[8] * direction_z;
|
|
314
|
-
const local_direction_y = scratch_m4[1] * direction_x + scratch_m4[5] * direction_y + scratch_m4[9] * direction_z;
|
|
315
|
-
const local_direction_z = scratch_m4[2] * direction_x + scratch_m4[6] * direction_y + scratch_m4[10] * direction_z;
|
|
316
|
-
|
|
317
|
-
const local_direction_magnitude = Math.hypot(local_direction_x, local_direction_y, local_direction_z);
|
|
318
|
-
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
|
+
);
|
|
319
345
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
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);
|
|
323
348
|
|
|
324
|
-
const geometry_hit_found = GeometrySpatialQueryAccelerator.INSTANCE.
|
|
349
|
+
const geometry_hit_found = GeometrySpatialQueryAccelerator.INSTANCE.queryRaycastNearest_array(
|
|
325
350
|
scratch_point,
|
|
326
351
|
sg.geometry,
|
|
327
|
-
|
|
328
|
-
local_direction_normalized_x, local_direction_normalized_y, local_direction_normalized_z
|
|
352
|
+
scratch_ray_0
|
|
329
353
|
);
|
|
330
354
|
|
|
331
355
|
if (!geometry_hit_found) {
|
|
@@ -344,13 +368,12 @@ export class ShadedGeometrySystem extends System {
|
|
|
344
368
|
origin_x, origin_y, origin_z
|
|
345
369
|
);
|
|
346
370
|
|
|
347
|
-
if (distance_sqr
|
|
348
|
-
|
|
349
|
-
|
|
371
|
+
if (distance_sqr < best_distance) {
|
|
372
|
+
contact.copy(scratch_point);
|
|
373
|
+
best_result = sg;
|
|
374
|
+
best_distance = distance_sqr;
|
|
350
375
|
}
|
|
351
376
|
|
|
352
|
-
contact.copy(scratch_point);
|
|
353
|
-
best_result = sg;
|
|
354
377
|
}
|
|
355
378
|
}
|
|
356
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);
|
|
@@ -3,6 +3,8 @@ import { TubeMaterialType } from "./TubeMaterialType.js";
|
|
|
3
3
|
import { assert } from "../../../../../core/assert.js";
|
|
4
4
|
import { MatcapMaterialDefinition } from "./MatcapMaterialDefinition.js";
|
|
5
5
|
|
|
6
|
+
const DEFAULT_COLOR = Object.freeze({ r: 1, g: 1, b: 1 });
|
|
7
|
+
|
|
6
8
|
export class TubePathStyle {
|
|
7
9
|
constructor() {
|
|
8
10
|
/**
|
|
@@ -59,6 +61,16 @@ export class TubePathStyle {
|
|
|
59
61
|
* @type {boolean}
|
|
60
62
|
*/
|
|
61
63
|
this.receive_shadow = false;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Which parts of the path to visualise, in normalized offsets
|
|
67
|
+
* @example [ 0, 1 ] = whole path
|
|
68
|
+
* @example [ 0, 0.5 ] = first half of the path
|
|
69
|
+
* @example [ 0.5, 0.6 ] = segment from 50% along the path, to 60% along the path
|
|
70
|
+
* @example [ 0, 0.1, 0.9, 1] = first 10% of the path, and last 10% of the path
|
|
71
|
+
* @type {number[]}
|
|
72
|
+
*/
|
|
73
|
+
this.path_mask = [0, 1];
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
static fromJSON(j) {
|
|
@@ -70,7 +82,7 @@ export class TubePathStyle {
|
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
fromJSON({
|
|
73
|
-
color,
|
|
85
|
+
color = DEFAULT_COLOR,
|
|
74
86
|
material_type,
|
|
75
87
|
material,
|
|
76
88
|
opacity = 1,
|
|
@@ -78,9 +90,22 @@ export class TubePathStyle {
|
|
|
78
90
|
resolution = 10,
|
|
79
91
|
radial_resolution = 16,
|
|
80
92
|
cast_shadow = false,
|
|
81
|
-
receive_shadow = false
|
|
93
|
+
receive_shadow = false,
|
|
94
|
+
path_mask = [0, 1]
|
|
82
95
|
}) {
|
|
83
96
|
assert.enum(material_type, TubeMaterialType, 'material_type');
|
|
97
|
+
assert.isNumber(opacity, 'opacity');
|
|
98
|
+
assert.isNumber(width, 'width');
|
|
99
|
+
assert.isNumber(resolution, 'resolution');
|
|
100
|
+
assert.isNumber(radial_resolution, 'radial_resolution');
|
|
101
|
+
assert.isBoolean(cast_shadow, 'cast_shadow');
|
|
102
|
+
assert.isBoolean(receive_shadow, 'receive_shadow');
|
|
103
|
+
|
|
104
|
+
assert.defined(path_mask, 'path_mask');
|
|
105
|
+
assert.notNull(path_mask, 'path_mask');
|
|
106
|
+
|
|
107
|
+
assert.greaterThanOrEqual(path_mask.length, 2, 'path_mask length bust be at least 2');
|
|
108
|
+
assert.ok(path_mask.length % 2 === 0, 'path_mask length bust be multiple of 2');
|
|
84
109
|
|
|
85
110
|
if (typeof color === 'string') {
|
|
86
111
|
this.color.parse(color);
|
|
@@ -97,6 +122,8 @@ export class TubePathStyle {
|
|
|
97
122
|
this.cast_shadow = cast_shadow;
|
|
98
123
|
this.receive_shadow = receive_shadow;
|
|
99
124
|
|
|
125
|
+
this.path_mask = path_mask;
|
|
126
|
+
|
|
100
127
|
switch (material_type) {
|
|
101
128
|
case TubeMaterialType.Matcap:
|
|
102
129
|
this.material = new MatcapMaterialDefinition();
|
|
@@ -9,6 +9,28 @@ import { build_geometry_catmullrom } from "./build_geometry_catmullrom.js";
|
|
|
9
9
|
import { ShadedGeometry } from "../../../mesh-v2/ShadedGeometry.js";
|
|
10
10
|
import { ShadedGeometryFlags } from "../../../mesh-v2/ShadedGeometryFlags.js";
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {number} segment_start
|
|
15
|
+
* @param {number} segment_end
|
|
16
|
+
* @returns {BufferGeometry}
|
|
17
|
+
* @param {Path} path_component
|
|
18
|
+
* @param {TubePathStyle} style
|
|
19
|
+
*/
|
|
20
|
+
function make_geometry_segment(path_component, style, segment_start, segment_end) {
|
|
21
|
+
|
|
22
|
+
const interpolation = path_component.interpolation;
|
|
23
|
+
|
|
24
|
+
if (interpolation === InterpolationType.Linear) {
|
|
25
|
+
return build_geometry_linear(path_component, style, segment_start, segment_end);
|
|
26
|
+
} else if (interpolation === InterpolationType.CatmullRom) {
|
|
27
|
+
return build_geometry_catmullrom(path_component, style, segment_start, segment_end);
|
|
28
|
+
} else {
|
|
29
|
+
throw new Error(`Unsupported interpolation type '${interpolation}'`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
12
34
|
export class TubePathBuilder {
|
|
13
35
|
constructor() {
|
|
14
36
|
/**
|
|
@@ -80,20 +102,6 @@ export class TubePathBuilder {
|
|
|
80
102
|
}
|
|
81
103
|
|
|
82
104
|
|
|
83
|
-
/**
|
|
84
|
-
* @type {THREE.BufferGeometry}
|
|
85
|
-
*/
|
|
86
|
-
let geometry;
|
|
87
|
-
|
|
88
|
-
if (path_component.interpolation === InterpolationType.Linear) {
|
|
89
|
-
geometry = build_geometry_linear(three_points, pointCount, style);
|
|
90
|
-
} else if (path_component.interpolation === InterpolationType.CatmullRom) {
|
|
91
|
-
geometry = build_geometry_catmullrom(three_points, pointCount, style);
|
|
92
|
-
} else {
|
|
93
|
-
throw new Error(`Unsupported interpolation type '${path_component.interpolation}'`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
105
|
let material_def;
|
|
98
106
|
|
|
99
107
|
if (style.material_type === TubeMaterialType.Standard) {
|
|
@@ -122,17 +130,30 @@ export class TubePathBuilder {
|
|
|
122
130
|
material_def.opacity = style.opacity;
|
|
123
131
|
}
|
|
124
132
|
|
|
125
|
-
const
|
|
133
|
+
const segment_count = style.path_mask.length / 2;
|
|
134
|
+
|
|
135
|
+
for (let i = 0; i < segment_count; i++) {
|
|
136
|
+
const i2 = i * 2;
|
|
137
|
+
|
|
138
|
+
const segment_start = style.path_mask[i2];
|
|
139
|
+
const segment_end = style.path_mask[i2 + 1];
|
|
140
|
+
|
|
141
|
+
const geometry = make_geometry_segment(path_component, style, segment_start, segment_end);
|
|
126
142
|
|
|
127
|
-
|
|
143
|
+
const entityBuilder = new EntityBuilder();
|
|
128
144
|
|
|
129
|
-
|
|
145
|
+
entityBuilder.add(new Transform());
|
|
130
146
|
|
|
131
|
-
|
|
132
|
-
shaded_geometry.writeFlag(ShadedGeometryFlags.ReceiveShadow, style.receive_shadow);
|
|
147
|
+
const shaded_geometry = ShadedGeometry.from(geometry, material_def);
|
|
133
148
|
|
|
134
|
-
|
|
149
|
+
shaded_geometry.writeFlag(ShadedGeometryFlags.CastShadow, style.cast_shadow);
|
|
150
|
+
shaded_geometry.writeFlag(ShadedGeometryFlags.ReceiveShadow, style.receive_shadow);
|
|
151
|
+
|
|
152
|
+
entityBuilder.add(shaded_geometry);
|
|
153
|
+
|
|
154
|
+
destination.push(entityBuilder);
|
|
155
|
+
|
|
156
|
+
}
|
|
135
157
|
|
|
136
|
-
destination.push(entityBuilder);
|
|
137
158
|
}
|
|
138
159
|
}
|
|
@@ -1,32 +1,61 @@
|
|
|
1
|
-
import { CatmullRomCurve3 } from "three";
|
|
2
1
|
import { computeFrenetFrames } from "./computeFrenetFrames.js";
|
|
3
2
|
import { makeTubeGeometry } from "./makeTubeGeometry.js";
|
|
3
|
+
import Vector3 from "../../../../../../core/geom/Vector3.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
*
|
|
7
|
-
* @param {
|
|
8
|
-
* @param {number} point_count
|
|
7
|
+
* @param {Path} path
|
|
9
8
|
* @param {TubePathStyle} style
|
|
9
|
+
* @param {number} segment_start
|
|
10
|
+
* @param {number} segment_end
|
|
10
11
|
* @return {THREE.BufferGeometry}
|
|
11
12
|
*/
|
|
12
|
-
export function build_geometry_catmullrom(
|
|
13
|
+
export function build_geometry_catmullrom(path, style, segment_start, segment_end) {
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const sample_points = [];
|
|
15
|
+
const point_count = path.getPointCount();
|
|
17
16
|
|
|
18
17
|
// resample curve
|
|
19
18
|
const total_points = Math.ceil(point_count * style.resolution);
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
const path_length = path.length;
|
|
21
|
+
|
|
22
|
+
const point = new Vector3();
|
|
23
|
+
|
|
24
|
+
const points_f32 = [];
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
let added_points = 0;
|
|
28
|
+
let i;
|
|
29
|
+
|
|
30
|
+
// initial segment
|
|
31
|
+
path.sample_catmull_rom(point, segment_start * path_length);
|
|
32
|
+
|
|
33
|
+
point.writeToArray(points_f32, added_points * 3);
|
|
34
|
+
|
|
35
|
+
added_points++;
|
|
36
|
+
|
|
37
|
+
const max_i = segment_end * (total_points - 1);
|
|
38
|
+
for (i = Math.ceil(segment_start * total_points + 0.0001); i < max_i; i++) {
|
|
22
39
|
const t = i / (total_points - 1);
|
|
23
40
|
|
|
24
|
-
|
|
41
|
+
path.sample_catmull_rom(point, path_length * t);
|
|
42
|
+
|
|
43
|
+
point.writeToArray(points_f32, added_points * 3);
|
|
44
|
+
|
|
45
|
+
added_points++
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (((i - 1) / (total_points - 1)) - segment_end > 0.0001) {
|
|
49
|
+
// end
|
|
50
|
+
|
|
51
|
+
path.sample_catmull_rom(point, segment_end * path_length);
|
|
52
|
+
|
|
53
|
+
point.writeToArray(points_f32, added_points * 3);
|
|
25
54
|
|
|
26
|
-
|
|
55
|
+
added_points++;
|
|
27
56
|
}
|
|
28
57
|
|
|
29
|
-
const frames = computeFrenetFrames(
|
|
58
|
+
const frames = computeFrenetFrames(points_f32, false);
|
|
30
59
|
|
|
31
|
-
return makeTubeGeometry(
|
|
60
|
+
return makeTubeGeometry(points_f32, frames.normals, frames.binormals, style.width, style.radial_resolution, false);
|
|
32
61
|
}
|
|
@@ -1,14 +1,54 @@
|
|
|
1
1
|
import { computeFrenetFrames } from "./computeFrenetFrames.js";
|
|
2
2
|
import { makeTubeGeometry } from "./makeTubeGeometry.js";
|
|
3
|
+
import Vector3 from "../../../../../../core/geom/Vector3.js";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const scratch_array_0 = [];
|
|
7
|
+
const scratch_array_1 = [];
|
|
8
|
+
|
|
9
|
+
const scratch_v3 = new Vector3();
|
|
3
10
|
|
|
4
11
|
/**
|
|
5
12
|
*
|
|
6
|
-
* @param {
|
|
7
|
-
* @param {number} point_count
|
|
13
|
+
* @param {Path} path
|
|
8
14
|
* @param {TubePathStyle} style
|
|
15
|
+
* @param {number} segment_start
|
|
16
|
+
* @param {number} segment_end
|
|
9
17
|
* @return {THREE.BufferGeometry}
|
|
10
18
|
*/
|
|
11
|
-
export function build_geometry_linear(
|
|
19
|
+
export function build_geometry_linear(path, style, segment_start, segment_end) {
|
|
20
|
+
const points = [];
|
|
21
|
+
|
|
22
|
+
const path_length = path.length;
|
|
23
|
+
|
|
24
|
+
path.find_index_and_normalized_distance(scratch_array_0, segment_start * path_length);
|
|
25
|
+
path.find_index_and_normalized_distance(scratch_array_1, segment_end * path_length);
|
|
26
|
+
|
|
27
|
+
let points_added = 0;
|
|
28
|
+
|
|
29
|
+
if (scratch_array_0[1] !== 0) {
|
|
30
|
+
path.sample_linear(scratch_v3, segment_start * path_length);
|
|
31
|
+
|
|
32
|
+
scratch_v3.writeToArray(points, points_added * 3);
|
|
33
|
+
points_added++;
|
|
34
|
+
|
|
35
|
+
// offset first sampled point, we're already past it
|
|
36
|
+
scratch_array_0[0]++;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const max_i = scratch_array_1[0];
|
|
40
|
+
for (let i = scratch_array_0[0]; i <= max_i; i++) {
|
|
41
|
+
path.readPositionToArray(i, points, points_added * 3);
|
|
42
|
+
points_added++;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (scratch_array_1[1] !== 0) {
|
|
46
|
+
//add end
|
|
47
|
+
path.sample_linear(scratch_v3, segment_end * path_length);
|
|
48
|
+
|
|
49
|
+
scratch_v3.writeToArray(points, points_added * 3);
|
|
50
|
+
points_added++;
|
|
51
|
+
}
|
|
12
52
|
|
|
13
53
|
const frames = computeFrenetFrames(points, false);
|
|
14
54
|
|
|
@@ -2,15 +2,17 @@ import { Vector3 } from "three";
|
|
|
2
2
|
import { Matrix4 } from "three/src/math/Matrix4.js";
|
|
3
3
|
import { max2 } from "../../../../../../core/math/max2.js";
|
|
4
4
|
import { min2 } from "../../../../../../core/math/min2.js";
|
|
5
|
-
import
|
|
5
|
+
import { clamp } from "../../../../../../core/math/clamp.js";
|
|
6
|
+
import { vec3 } from "gl-matrix";
|
|
7
|
+
import { array_copy } from "../../../../../../core/collection/array/copyArray.js";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* @see https://github.com/mrdoob/three.js/blob/c12c9a166a1369cdd58622fff2aff7e3a84305d7/src/extras/core/Curve.js#L260
|
|
9
|
-
* @param {
|
|
11
|
+
* @param {Float32Array|number[]} points
|
|
10
12
|
* @param {boolean} [closed]
|
|
11
13
|
*/
|
|
12
14
|
export function computeFrenetFrames(points, closed = false) {
|
|
13
|
-
// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
|
|
15
|
+
// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
|
|
14
16
|
|
|
15
17
|
const normal = new Vector3();
|
|
16
18
|
|
|
@@ -21,10 +23,15 @@ export function computeFrenetFrames(points, closed = false) {
|
|
|
21
23
|
const vec = new Vector3();
|
|
22
24
|
const mat = new Matrix4();
|
|
23
25
|
|
|
24
|
-
const
|
|
26
|
+
const point_count = points.length / 3;
|
|
27
|
+
const segments = point_count - 1;
|
|
25
28
|
|
|
26
|
-
const v3_0 =
|
|
27
|
-
const v3_1 =
|
|
29
|
+
const v3_0 = [];
|
|
30
|
+
const v3_1 = [];
|
|
31
|
+
|
|
32
|
+
const p0_a = [];
|
|
33
|
+
const pR_a = [];
|
|
34
|
+
const p1_a = [];
|
|
28
35
|
|
|
29
36
|
/**
|
|
30
37
|
*
|
|
@@ -36,18 +43,23 @@ export function computeFrenetFrames(points, closed = false) {
|
|
|
36
43
|
const i0 = max2(i - 1, 0);
|
|
37
44
|
const i1 = min2(i + 1, segments);
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
array_copy(points, i0 * 3, p0_a, 0, 3);
|
|
47
|
+
array_copy(points, i * 3, pR_a, 0, 3);
|
|
48
|
+
array_copy(points, i1 * 3, p1_a, 0, 3);
|
|
42
49
|
|
|
43
50
|
// get points along the lines close to the reference
|
|
44
|
-
v3_0.subVectors(p0, pR);
|
|
45
|
-
v3_0.normalize();
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
vec3.sub(v3_0, p0_a, pR_a);
|
|
53
|
+
vec3.normalize(v3_0, v3_0);
|
|
54
|
+
|
|
55
|
+
vec3.sub(v3_1, p1_a, pR_a);
|
|
56
|
+
vec3.normalize(v3_1, v3_1);
|
|
49
57
|
|
|
50
|
-
destination.
|
|
58
|
+
destination.set(
|
|
59
|
+
v3_1[0] - v3_0[0],
|
|
60
|
+
v3_1[1] - v3_0[1],
|
|
61
|
+
v3_1[2] - v3_0[2],
|
|
62
|
+
);
|
|
51
63
|
destination.normalize();
|
|
52
64
|
}
|
|
53
65
|
|
|
@@ -112,7 +124,7 @@ export function computeFrenetFrames(points, closed = false) {
|
|
|
112
124
|
|
|
113
125
|
vec.normalize();
|
|
114
126
|
|
|
115
|
-
const theta = Math.acos(
|
|
127
|
+
const theta = Math.acos(clamp(tangents[i - 1].dot(tangents[i]), -1, 1)); // clamp for floating pt errors
|
|
116
128
|
|
|
117
129
|
normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta));
|
|
118
130
|
|
|
@@ -126,7 +138,7 @@ export function computeFrenetFrames(points, closed = false) {
|
|
|
126
138
|
|
|
127
139
|
if (closed === true) {
|
|
128
140
|
|
|
129
|
-
let theta = Math.acos(
|
|
141
|
+
let theta = Math.acos(clamp(normals[0].dot(normals[segments]), -1, 1));
|
|
130
142
|
theta /= segments;
|
|
131
143
|
|
|
132
144
|
if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
|
|
@@ -2,7 +2,7 @@ import { BufferGeometry, Float32BufferAttribute, Vector3 } from "three";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @see https://github.com/mrdoob/three.js/blob/master/src/geometries/TubeGeometry.js
|
|
5
|
-
* @param {
|
|
5
|
+
* @param {Float32Array|number[]} points
|
|
6
6
|
* @param {Vector3[]} _normals
|
|
7
7
|
* @param {Vector3[]} binormals
|
|
8
8
|
* @param {number} radius
|
|
@@ -24,7 +24,8 @@ export function makeTubeGeometry(points, _normals, binormals, radius, radialSegm
|
|
|
24
24
|
const uvs = [];
|
|
25
25
|
const indices = [];
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const point_count = points.length / 3;
|
|
28
|
+
const tubularSegments = point_count - 1;
|
|
28
29
|
|
|
29
30
|
// create buffer data
|
|
30
31
|
|
|
@@ -69,7 +70,11 @@ export function makeTubeGeometry(points, _normals, binormals, radius, radialSegm
|
|
|
69
70
|
|
|
70
71
|
// we use getPointAt to sample evenly distributed points from the given path
|
|
71
72
|
|
|
72
|
-
const
|
|
73
|
+
const i3 = i * 3;
|
|
74
|
+
|
|
75
|
+
const Px = points[i3];
|
|
76
|
+
const Py = points[i3 + 1];
|
|
77
|
+
const Pz = points[i3 + 2];
|
|
73
78
|
|
|
74
79
|
// retrieve corresponding normal and binormal
|
|
75
80
|
|
|
@@ -97,9 +102,9 @@ export function makeTubeGeometry(points, _normals, binormals, radius, radialSegm
|
|
|
97
102
|
|
|
98
103
|
// vertex
|
|
99
104
|
|
|
100
|
-
vertex.x =
|
|
101
|
-
vertex.y =
|
|
102
|
-
vertex.z =
|
|
105
|
+
vertex.x = Px + radius * normal.x;
|
|
106
|
+
vertex.y = Py + radius * normal.y;
|
|
107
|
+
vertex.z = Pz + radius * normal.z;
|
|
103
108
|
|
|
104
109
|
vertices.push(vertex.x, vertex.y, vertex.z);
|
|
105
110
|
|
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -436,7 +436,7 @@ class Path {
|
|
|
436
436
|
*/
|
|
437
437
|
sample_linear(result, offset) {
|
|
438
438
|
|
|
439
|
-
const found = this.
|
|
439
|
+
const found = this.find_index_and_normalized_distance(scratch_array_0, offset);
|
|
440
440
|
|
|
441
441
|
if (!found) {
|
|
442
442
|
return false;
|
|
@@ -466,9 +466,8 @@ class Path {
|
|
|
466
466
|
* @param {number[]} result
|
|
467
467
|
* @param {number} absolute_distance absolute distance along the path
|
|
468
468
|
* @returns {boolean}
|
|
469
|
-
* @private
|
|
470
469
|
*/
|
|
471
|
-
|
|
470
|
+
find_index_and_normalized_distance(result, absolute_distance) {
|
|
472
471
|
const pointCount = this.getPointCount();
|
|
473
472
|
|
|
474
473
|
if (pointCount === 0) {
|
|
@@ -495,10 +494,10 @@ class Path {
|
|
|
495
494
|
// we found v1
|
|
496
495
|
const local_offset = absolute_distance - cursor;
|
|
497
496
|
|
|
498
|
-
const
|
|
497
|
+
const local_normalized_offset = local_offset / distance;
|
|
499
498
|
|
|
500
499
|
result[0] = i - 1;
|
|
501
|
-
result[1] =
|
|
500
|
+
result[1] = local_normalized_offset;
|
|
502
501
|
return true;
|
|
503
502
|
}
|
|
504
503
|
|
|
@@ -525,7 +524,7 @@ class Path {
|
|
|
525
524
|
* @returns {boolean}
|
|
526
525
|
*/
|
|
527
526
|
sample_catmull_rom(result, offset) {
|
|
528
|
-
const found = this.
|
|
527
|
+
const found = this.find_index_and_normalized_distance(scratch_array_0, offset);
|
|
529
528
|
|
|
530
529
|
if (!found) {
|
|
531
530
|
return false;
|
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.
|
|
8
|
+
"version": "2.35.15",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|