@woosh/meep-engine 2.35.3 → 2.35.6
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/SurfacePoint3.js +11 -11
- package/engine/ecs/EntityManager.d.ts +7 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts +11 -1
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +8 -6
- package/engine/graphics/ecs/mesh-v2/render/ShadedGeometryRendererContext.js +1 -1
- package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +25 -3
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +1 -0
- package/engine/graphics/ecs/path/tube/TubePathBuilder.js +350 -9
- package/package.json +1 -1
|
@@ -12,9 +12,9 @@ export class SurfacePoint3 {
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
*
|
|
15
|
-
* @param {number[]|mat4|Float32Array}
|
|
15
|
+
* @param {number[]|mat4|Float32Array} m
|
|
16
16
|
*/
|
|
17
|
-
applyMatrix4(
|
|
17
|
+
applyMatrix4(m) {
|
|
18
18
|
// transform position
|
|
19
19
|
const p = this.position;
|
|
20
20
|
|
|
@@ -23,13 +23,13 @@ export class SurfacePoint3 {
|
|
|
23
23
|
const p_z = p.z;
|
|
24
24
|
|
|
25
25
|
// compute perspective projection
|
|
26
|
-
const w = 1 / (
|
|
26
|
+
const w = 1 / (m[3] * p_x + m[7] * p_y + m[11] * p_z + m[15]);
|
|
27
27
|
|
|
28
|
-
const result_p_x = (
|
|
29
|
-
const result_p_y = (
|
|
30
|
-
const result_p_z = (
|
|
28
|
+
const result_p_x = (m[0] * p_x + m[4] * p_y + m[8] * p_z + m[12]) * w;
|
|
29
|
+
const result_p_y = (m[1] * p_x + m[5] * p_y + m[9] * p_z + m[13]) * w;
|
|
30
|
+
const result_p_z = (m[2] * p_x + m[6] * p_y + m[10] * p_z + m[14]) * w;
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
p.set(
|
|
33
33
|
result_p_x,
|
|
34
34
|
result_p_y,
|
|
35
35
|
result_p_z
|
|
@@ -42,13 +42,13 @@ export class SurfacePoint3 {
|
|
|
42
42
|
const n_y = n.y;
|
|
43
43
|
const n_z = n.z;
|
|
44
44
|
|
|
45
|
-
const result_n_x =
|
|
46
|
-
const result_n_y =
|
|
47
|
-
const result_n_z =
|
|
45
|
+
const result_n_x = m[0] * n_x + m[4] * n_y + m[8] * n_z;
|
|
46
|
+
const result_n_y = m[1] * n_x + m[5] * n_y + m[9] * n_z;
|
|
47
|
+
const result_n_z = m[2] * n_x + m[6] * n_y + m[10] * n_z;
|
|
48
48
|
|
|
49
49
|
const normal_multiplier = 1 / v3_length(result_n_x, result_n_y, result_n_z);
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
n.set(
|
|
52
52
|
result_n_x * normal_multiplier,
|
|
53
53
|
result_n_y * normal_multiplier,
|
|
54
54
|
result_n_z * normal_multiplier,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import {EntityComponentDataset} from "./EntityComponentDataset";
|
|
2
2
|
import {System} from "./System";
|
|
3
3
|
|
|
4
|
+
interface Type<T> extends Function {
|
|
5
|
+
new(...args: any[]): T;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
|
|
4
9
|
export class EntityManager {
|
|
5
10
|
dataset: EntityComponentDataset
|
|
6
11
|
|
|
@@ -10,6 +15,8 @@ export class EntityManager {
|
|
|
10
15
|
|
|
11
16
|
removeSystem<T>(system: System<T>): Promise<void>
|
|
12
17
|
|
|
18
|
+
getSystem<T>(systemClass: Type<T>): T | null
|
|
19
|
+
|
|
13
20
|
attachDataSet(dataset: EntityComponentDataset): void
|
|
14
21
|
|
|
15
22
|
detachDataSet(): void
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import {System} from "../../../ecs/System";
|
|
2
2
|
import Engine from "../../../Engine";
|
|
3
|
+
import {ShadedGeometry} from "./ShadedGeometry";
|
|
4
|
+
import {SurfacePoint3} from "../../../../core/geom/3d/SurfacePoint3";
|
|
3
5
|
|
|
4
|
-
export class ShadedGeometrySystem extends System {
|
|
6
|
+
export class ShadedGeometrySystem extends System<ShadedGeometry> {
|
|
5
7
|
constructor(engine: Engine)
|
|
8
|
+
|
|
9
|
+
raycastNearest(
|
|
10
|
+
contact: SurfacePoint3,
|
|
11
|
+
origin_x: number, origin_y: number, origin_z: number,
|
|
12
|
+
direction_x: number, direction_y: number, direction_z: number,
|
|
13
|
+
filter_function?: (entity: number, mesh: ShadedGeometry) => boolean,
|
|
14
|
+
filter_function_context?: any
|
|
15
|
+
): { entity: number, mesh: ShadedGeometry } | undefined
|
|
6
16
|
}
|
|
@@ -166,7 +166,7 @@ export class ShadedGeometrySystem extends System {
|
|
|
166
166
|
this.__render_layer.buildVisibleSet = ((destination, destination_offset, view) => {
|
|
167
167
|
const ctx = this.__view_contexts.get(view);
|
|
168
168
|
|
|
169
|
-
return ctx.collect(destination, destination_offset, view, this.__bvh);
|
|
169
|
+
return ctx.collect(destination, destination_offset,graphics.renderer, view, this.__bvh);
|
|
170
170
|
});
|
|
171
171
|
|
|
172
172
|
readyCallback();
|
|
@@ -235,7 +235,7 @@ export class ShadedGeometrySystem extends System {
|
|
|
235
235
|
* @param {number} direction_x
|
|
236
236
|
* @param {number} direction_y
|
|
237
237
|
* @param {number} direction_z
|
|
238
|
-
* @param {function(entity:number, mesh:ShadedGeometry)} [filter_function]
|
|
238
|
+
* @param {function(entity:number, mesh:ShadedGeometry):boolean} [filter_function]
|
|
239
239
|
* @param {*} [filter_function_context]
|
|
240
240
|
* @returns {{entity:number, mesh:ShadedGeometry}|undefined}
|
|
241
241
|
*/
|
|
@@ -245,7 +245,7 @@ export class ShadedGeometrySystem extends System {
|
|
|
245
245
|
direction_x, direction_y, direction_z,
|
|
246
246
|
filter_function = returnTrue, filter_function_context
|
|
247
247
|
) {
|
|
248
|
-
const root_bvh = this.
|
|
248
|
+
const root_bvh = this.__bvh;
|
|
249
249
|
const stack_frame_address = traversal_cursor;
|
|
250
250
|
|
|
251
251
|
traversal_stack[traversal_cursor++] = root_bvh;
|
|
@@ -304,9 +304,11 @@ export class ShadedGeometrySystem extends System {
|
|
|
304
304
|
mat4.invert(scratch_m4, m4);
|
|
305
305
|
|
|
306
306
|
// transform ray to local space
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
const
|
|
307
|
+
const inv_w = 1 / (scratch_m4[3] * origin_x + scratch_m4[7] * origin_y + scratch_m4[11] * origin_z + scratch_m4[15]);
|
|
308
|
+
|
|
309
|
+
const local_origin_x = (scratch_m4[0] * origin_x + scratch_m4[4] * origin_y + scratch_m4[8] * origin_z + scratch_m4[12]) * inv_w;
|
|
310
|
+
const local_origin_y = (scratch_m4[1] * origin_x + scratch_m4[5] * origin_y + scratch_m4[9] * origin_z + scratch_m4[13]) * inv_w;
|
|
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;
|
|
310
312
|
|
|
311
313
|
const local_direction_x = scratch_m4[0] * direction_x + scratch_m4[4] * direction_y + scratch_m4[8] * direction_z;
|
|
312
314
|
const local_direction_y = scratch_m4[1] * direction_x + scratch_m4[5] * direction_y + scratch_m4[9] * direction_z;
|
|
@@ -3,7 +3,7 @@ import { ShadedGeometrySystem } from "../ShadedGeometrySystem.js";
|
|
|
3
3
|
import EntityBuilder from "../../../../ecs/EntityBuilder.js";
|
|
4
4
|
import { Transform } from "../../../../ecs/transform/Transform.js";
|
|
5
5
|
import { ShadedGeometry } from "../ShadedGeometry.js";
|
|
6
|
-
import { BoxBufferGeometry, MeshStandardMaterial } from "three";
|
|
6
|
+
import { BoxBufferGeometry, MeshStandardMaterial, OctahedronGeometry } from "three";
|
|
7
7
|
import { randomFloatBetween } from "../../../../../core/math/random/randomFloatBetween.js";
|
|
8
8
|
import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
|
|
9
9
|
import ViewportPosition from "../../../../ecs/gui/position/ViewportPosition.js";
|
|
@@ -17,12 +17,31 @@ import Vector3 from "../../../../../core/geom/Vector3.js";
|
|
|
17
17
|
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
18
18
|
import { ShadedGeometryFlags } from "../ShadedGeometryFlags.js";
|
|
19
19
|
import { randomFromArray } from "../../../../../core/math/random/randomFromArray.js";
|
|
20
|
+
import { BehaviorComponent } from "../../../../intelligence/behavior/ecs/BehaviorComponent.js";
|
|
21
|
+
import { OrbitingBehavior } from "../../../../../../model/game/util/behavior/OrbitingBehavior.js";
|
|
22
|
+
import { BehaviorSystem } from "../../../../intelligence/behavior/ecs/BehaviorSystem.js";
|
|
20
23
|
|
|
21
24
|
const eh = new EngineHarness();
|
|
22
25
|
|
|
23
26
|
const DRAW_METHOD_PLAIN = 0;
|
|
24
27
|
const DRAW_METHOD_INSTANCED = 1;
|
|
25
28
|
|
|
29
|
+
function makeMovingShadedGeometry() {
|
|
30
|
+
const b = new OrbitingBehavior();
|
|
31
|
+
b.offset.set(4, 1, 4);
|
|
32
|
+
b.radius = 2;
|
|
33
|
+
b.rate = 1;
|
|
34
|
+
|
|
35
|
+
const sg = ShadedGeometry.from(new OctahedronGeometry(0.5, 5), new MeshStandardMaterial({ color: 0xFF0000 }));
|
|
36
|
+
|
|
37
|
+
sg.draw_method = DRAW_METHOD_INSTANCED;
|
|
38
|
+
|
|
39
|
+
return new EntityBuilder()
|
|
40
|
+
.add(new Transform())
|
|
41
|
+
.add(sg)
|
|
42
|
+
.add(BehaviorComponent.fromOne(b));
|
|
43
|
+
}
|
|
44
|
+
|
|
26
45
|
/**
|
|
27
46
|
*
|
|
28
47
|
* @param {Engine} engine
|
|
@@ -32,6 +51,7 @@ async function main(engine) {
|
|
|
32
51
|
const em = engine.entityManager;
|
|
33
52
|
|
|
34
53
|
await em.addSystem(new ShadedGeometrySystem(engine));
|
|
54
|
+
await em.addSystem(new BehaviorSystem(engine));
|
|
35
55
|
|
|
36
56
|
EngineHarness.buildBasics({
|
|
37
57
|
engine,
|
|
@@ -54,11 +74,11 @@ async function main(engine) {
|
|
|
54
74
|
|
|
55
75
|
const random = seededRandom(0);
|
|
56
76
|
|
|
57
|
-
const INSTANCE_COUNT =
|
|
77
|
+
const INSTANCE_COUNT = 0;
|
|
58
78
|
|
|
59
79
|
const geometries = [];
|
|
60
80
|
|
|
61
|
-
for (let i = 0; i <
|
|
81
|
+
for (let i = 0; i < 1; i++) {
|
|
62
82
|
geometries.push(new BoxBufferGeometry());
|
|
63
83
|
}
|
|
64
84
|
|
|
@@ -85,6 +105,8 @@ async function main(engine) {
|
|
|
85
105
|
.build(ecd);
|
|
86
106
|
}
|
|
87
107
|
|
|
108
|
+
makeMovingShadedGeometry().build(ecd);
|
|
109
|
+
|
|
88
110
|
debug_button(engine, () => {
|
|
89
111
|
const dot = convert_bvh_to_dot_format_string(engine.graphics.layers.getLayerByName('shaded-geometry').bvh);
|
|
90
112
|
downloadAsFile(dot, 'bvh.dot', 'text');
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BufferGeometry,
|
|
3
|
+
CatmullRomCurve3,
|
|
4
|
+
Float32BufferAttribute,
|
|
5
|
+
MeshMatcapMaterial,
|
|
6
|
+
MeshStandardMaterial,
|
|
7
|
+
TubeGeometry,
|
|
8
|
+
Vector3
|
|
9
|
+
} from "three";
|
|
2
10
|
import { InterpolationType } from "../../../../navigation/ecs/components/InterpolationType.js";
|
|
3
11
|
import EntityBuilder from "../../../../ecs/EntityBuilder.js";
|
|
4
12
|
import { Transform } from "../../../../ecs/transform/Transform.js";
|
|
@@ -6,6 +14,10 @@ import Renderable from "../../../../ecs/components/Renderable.js";
|
|
|
6
14
|
import ThreeFactory from "../../../three/ThreeFactory.js";
|
|
7
15
|
import { TubeMaterialType } from "./TubeMaterialType.js";
|
|
8
16
|
import { GameAssetType } from "../../../../asset/GameAssetType.js";
|
|
17
|
+
import { Matrix4 } from "three/src/math/Matrix4.js";
|
|
18
|
+
import * as MathUtils from "three/src/math/MathUtils.js";
|
|
19
|
+
import { max2 } from "../../../../../core/math/max2.js";
|
|
20
|
+
import { min2 } from "../../../../../core/math/min2.js";
|
|
9
21
|
|
|
10
22
|
/**
|
|
11
23
|
* some useful references:
|
|
@@ -43,6 +55,305 @@ function estimatePathViaIterativeIntegral(path, epsilon) {
|
|
|
43
55
|
return sum;
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @see https://github.com/mrdoob/three.js/blob/c12c9a166a1369cdd58622fff2aff7e3a84305d7/src/extras/core/Curve.js#L260
|
|
60
|
+
* @param {Vector3[]} points
|
|
61
|
+
* @param {boolean} [closed]
|
|
62
|
+
*/
|
|
63
|
+
function computeFrenetFrames(points, closed = false) {
|
|
64
|
+
// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
|
|
65
|
+
|
|
66
|
+
const normal = new Vector3();
|
|
67
|
+
|
|
68
|
+
const tangents = [];
|
|
69
|
+
const normals = [];
|
|
70
|
+
const binormals = [];
|
|
71
|
+
|
|
72
|
+
const vec = new Vector3();
|
|
73
|
+
const mat = new Matrix4();
|
|
74
|
+
|
|
75
|
+
const segments = points.length - 1;
|
|
76
|
+
|
|
77
|
+
const v3_0 = new Vector3();
|
|
78
|
+
const v3_1 = new Vector3();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param {number} i
|
|
83
|
+
* @param {Vector3} destination
|
|
84
|
+
*/
|
|
85
|
+
function getTangent(i, destination) {
|
|
86
|
+
// get points on either side
|
|
87
|
+
const i0 = max2(i - 1, 0);
|
|
88
|
+
const i1 = min2(i + 1, segments);
|
|
89
|
+
|
|
90
|
+
const p0 = points[i0];
|
|
91
|
+
const pR = points[i];
|
|
92
|
+
const p1 = points[i1];
|
|
93
|
+
|
|
94
|
+
// get points along the lines close to the reference
|
|
95
|
+
v3_0.subVectors(p0, pR);
|
|
96
|
+
v3_0.normalize();
|
|
97
|
+
|
|
98
|
+
v3_1.subVectors(p1, pR);
|
|
99
|
+
v3_1.normalize();
|
|
100
|
+
|
|
101
|
+
destination.subVectors(v3_1, v3_0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// compute the tangent vectors for each segment on the curve
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i <= segments; i++) {
|
|
107
|
+
|
|
108
|
+
const tangent = new Vector3();
|
|
109
|
+
getTangent(i, tangent);
|
|
110
|
+
|
|
111
|
+
tangents[i] = tangent;
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// select an initial normal vector perpendicular to the first tangent vector,
|
|
116
|
+
// and in the direction of the minimum tangent xyz component
|
|
117
|
+
|
|
118
|
+
normals[0] = new Vector3();
|
|
119
|
+
binormals[0] = new Vector3();
|
|
120
|
+
let min = Number.MAX_VALUE;
|
|
121
|
+
const tx = Math.abs(tangents[0].x);
|
|
122
|
+
const ty = Math.abs(tangents[0].y);
|
|
123
|
+
const tz = Math.abs(tangents[0].z);
|
|
124
|
+
|
|
125
|
+
if (tx <= min) {
|
|
126
|
+
|
|
127
|
+
min = tx;
|
|
128
|
+
normal.set(1, 0, 0);
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (ty <= min) {
|
|
133
|
+
|
|
134
|
+
min = ty;
|
|
135
|
+
normal.set(0, 1, 0);
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (tz <= min) {
|
|
140
|
+
|
|
141
|
+
normal.set(0, 0, 1);
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
vec.crossVectors(tangents[0], normal).normalize();
|
|
146
|
+
|
|
147
|
+
normals[0].crossVectors(tangents[0], vec);
|
|
148
|
+
binormals[0].crossVectors(tangents[0], normals[0]);
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
// compute the slowly-varying normal and binormal vectors for each segment on the curve
|
|
152
|
+
|
|
153
|
+
for (let i = 1; i <= segments; i++) {
|
|
154
|
+
|
|
155
|
+
normals[i] = normals[i - 1].clone();
|
|
156
|
+
|
|
157
|
+
binormals[i] = binormals[i - 1].clone();
|
|
158
|
+
|
|
159
|
+
vec.crossVectors(tangents[i - 1], tangents[i]);
|
|
160
|
+
|
|
161
|
+
if (vec.length() > Number.EPSILON) {
|
|
162
|
+
|
|
163
|
+
vec.normalize();
|
|
164
|
+
|
|
165
|
+
const theta = Math.acos(MathUtils.clamp(tangents[i - 1].dot(tangents[i]), -1, 1)); // clamp for floating pt errors
|
|
166
|
+
|
|
167
|
+
normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta));
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
binormals[i].crossVectors(tangents[i], normals[i]);
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
|
|
176
|
+
|
|
177
|
+
if (closed === true) {
|
|
178
|
+
|
|
179
|
+
let theta = Math.acos(MathUtils.clamp(normals[0].dot(normals[segments]), -1, 1));
|
|
180
|
+
theta /= segments;
|
|
181
|
+
|
|
182
|
+
if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
|
|
183
|
+
|
|
184
|
+
theta = -theta;
|
|
185
|
+
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
for (let i = 1; i <= segments; i++) {
|
|
189
|
+
|
|
190
|
+
// twist a little...
|
|
191
|
+
normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i));
|
|
192
|
+
binormals[i].crossVectors(tangents[i], normals[i]);
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
tangents: tangents,
|
|
200
|
+
normals: normals,
|
|
201
|
+
binormals: binormals
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @see https://github.com/mrdoob/three.js/blob/master/src/geometries/TubeGeometry.js
|
|
207
|
+
* @param {Vector3[]} points
|
|
208
|
+
* @param {Vector3[]} _normals
|
|
209
|
+
* @param {Vector3[]} binormals
|
|
210
|
+
* @param {number} radius
|
|
211
|
+
* @param {number} radialSegments
|
|
212
|
+
* @param {boolean} [closed]
|
|
213
|
+
* @returns {BufferGeometry}
|
|
214
|
+
*/
|
|
215
|
+
function makeTubeGeometry(points, _normals, binormals, radius, radialSegments, closed = false) {
|
|
216
|
+
const geometry = new BufferGeometry();
|
|
217
|
+
// helper variables
|
|
218
|
+
|
|
219
|
+
const vertex = new Vector3();
|
|
220
|
+
const normal = new Vector3();
|
|
221
|
+
|
|
222
|
+
// buffer
|
|
223
|
+
|
|
224
|
+
const vertices = [];
|
|
225
|
+
const normals = [];
|
|
226
|
+
const uvs = [];
|
|
227
|
+
const indices = [];
|
|
228
|
+
|
|
229
|
+
const tubularSegments = points.length - 1;
|
|
230
|
+
|
|
231
|
+
// create buffer data
|
|
232
|
+
|
|
233
|
+
generateBufferData();
|
|
234
|
+
|
|
235
|
+
// build geometry
|
|
236
|
+
|
|
237
|
+
geometry.setIndex(indices);
|
|
238
|
+
geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));
|
|
239
|
+
geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
|
|
240
|
+
geometry.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
|
|
241
|
+
|
|
242
|
+
// functions
|
|
243
|
+
|
|
244
|
+
function generateBufferData() {
|
|
245
|
+
|
|
246
|
+
for (let i = 0; i < tubularSegments; i++) {
|
|
247
|
+
|
|
248
|
+
generateSegment(i);
|
|
249
|
+
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// if the geometry is not closed, generate the last row of vertices and normals
|
|
253
|
+
// at the regular position on the given path
|
|
254
|
+
//
|
|
255
|
+
// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
|
|
256
|
+
|
|
257
|
+
generateSegment((closed === false) ? tubularSegments : 0);
|
|
258
|
+
|
|
259
|
+
// uvs are generated in a separate function.
|
|
260
|
+
// this makes it easy compute correct values for closed geometries
|
|
261
|
+
|
|
262
|
+
generateUVs();
|
|
263
|
+
|
|
264
|
+
// finally create faces
|
|
265
|
+
|
|
266
|
+
generateIndices();
|
|
267
|
+
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function generateSegment(i) {
|
|
271
|
+
|
|
272
|
+
// we use getPointAt to sample evenly distributed points from the given path
|
|
273
|
+
|
|
274
|
+
const P = points[i];
|
|
275
|
+
|
|
276
|
+
// retrieve corresponding normal and binormal
|
|
277
|
+
|
|
278
|
+
const N = _normals[i];
|
|
279
|
+
const B = binormals[i];
|
|
280
|
+
|
|
281
|
+
// generate normals and vertices for the current segment
|
|
282
|
+
|
|
283
|
+
for (let j = 0; j <= radialSegments; j++) {
|
|
284
|
+
|
|
285
|
+
const v = j / radialSegments * Math.PI * 2;
|
|
286
|
+
|
|
287
|
+
const sin = Math.sin(v);
|
|
288
|
+
const cos = -Math.cos(v);
|
|
289
|
+
|
|
290
|
+
// normal
|
|
291
|
+
|
|
292
|
+
normal.x = (cos * N.x + sin * B.x);
|
|
293
|
+
normal.y = (cos * N.y + sin * B.y);
|
|
294
|
+
normal.z = (cos * N.z + sin * B.z);
|
|
295
|
+
normal.normalize();
|
|
296
|
+
|
|
297
|
+
normals.push(normal.x, normal.y, normal.z);
|
|
298
|
+
|
|
299
|
+
// vertex
|
|
300
|
+
|
|
301
|
+
vertex.x = P.x + radius * normal.x;
|
|
302
|
+
vertex.y = P.y + radius * normal.y;
|
|
303
|
+
vertex.z = P.z + radius * normal.z;
|
|
304
|
+
|
|
305
|
+
vertices.push(vertex.x, vertex.y, vertex.z);
|
|
306
|
+
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function generateIndices() {
|
|
312
|
+
let i = 0, j = 0;
|
|
313
|
+
|
|
314
|
+
for (j = 1; j <= tubularSegments; j++) {
|
|
315
|
+
|
|
316
|
+
for (i = 1; i <= radialSegments; i++) {
|
|
317
|
+
|
|
318
|
+
const a = (radialSegments + 1) * (j - 1) + (i - 1);
|
|
319
|
+
const b = (radialSegments + 1) * j + (i - 1);
|
|
320
|
+
const c = (radialSegments + 1) * j + i;
|
|
321
|
+
const d = (radialSegments + 1) * (j - 1) + i;
|
|
322
|
+
|
|
323
|
+
// faces
|
|
324
|
+
|
|
325
|
+
indices.push(a, b, d);
|
|
326
|
+
indices.push(b, c, d);
|
|
327
|
+
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function generateUVs() {
|
|
335
|
+
let i = 0, j = 0;
|
|
336
|
+
|
|
337
|
+
for (i = 0; i <= tubularSegments; i++) {
|
|
338
|
+
|
|
339
|
+
const u = i / tubularSegments;
|
|
340
|
+
|
|
341
|
+
for (j = 0; j <= radialSegments; j++) {
|
|
342
|
+
|
|
343
|
+
const v = j / radialSegments;
|
|
344
|
+
|
|
345
|
+
uvs.push(u, v);
|
|
346
|
+
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
return geometry;
|
|
355
|
+
}
|
|
356
|
+
|
|
46
357
|
/**
|
|
47
358
|
*
|
|
48
359
|
* @param {Path} path
|
|
@@ -58,6 +369,35 @@ function estimatePathLength(path) {
|
|
|
58
369
|
|
|
59
370
|
}
|
|
60
371
|
|
|
372
|
+
/**
|
|
373
|
+
*
|
|
374
|
+
* @param {THREE.Vector3[]} points
|
|
375
|
+
* @param {number} point_count
|
|
376
|
+
* @param {TubePathStyle} style
|
|
377
|
+
* @return {BufferGeometry}
|
|
378
|
+
*/
|
|
379
|
+
function build_geometry_linear(points, point_count, style) {
|
|
380
|
+
|
|
381
|
+
const frames = computeFrenetFrames(points, false);
|
|
382
|
+
|
|
383
|
+
return makeTubeGeometry(points, frames.normals, frames.binormals, style.width, style.radial_resolution, false);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
*
|
|
388
|
+
* @param {THREE.Vector3[]} points
|
|
389
|
+
* @param {number} point_count
|
|
390
|
+
* @param {TubePathStyle} style
|
|
391
|
+
* @return {BufferGeometry}
|
|
392
|
+
*/
|
|
393
|
+
function build_geometry_catmullrom(points, point_count, style) {
|
|
394
|
+
|
|
395
|
+
const path = new CatmullRomCurve3(points, false, "centripetal");
|
|
396
|
+
|
|
397
|
+
return new TubeGeometry(path, style.resolution * point_count, style.width, style.radial_resolution, false);
|
|
398
|
+
|
|
399
|
+
}
|
|
400
|
+
|
|
61
401
|
export class TubePathBuilder {
|
|
62
402
|
constructor() {
|
|
63
403
|
/**
|
|
@@ -129,26 +469,27 @@ export class TubePathBuilder {
|
|
|
129
469
|
}
|
|
130
470
|
|
|
131
471
|
|
|
132
|
-
|
|
472
|
+
/**
|
|
473
|
+
* @type {THREE.BufferGeometry}
|
|
474
|
+
*/
|
|
475
|
+
let geometry;
|
|
133
476
|
|
|
134
477
|
if (path_component.interpolation === InterpolationType.Linear) {
|
|
135
|
-
|
|
478
|
+
geometry = build_geometry_linear(three_points, pointCount, style);
|
|
136
479
|
} else if (path_component.interpolation === InterpolationType.CatmullRom) {
|
|
137
|
-
|
|
480
|
+
geometry = build_geometry_catmullrom(three_points, pointCount, style);
|
|
138
481
|
} else {
|
|
139
482
|
throw new Error(`Unsupported interpolation type '${path_component.interpolation}'`);
|
|
140
483
|
}
|
|
141
484
|
|
|
142
485
|
|
|
143
|
-
const geometry = new TubeGeometry(path, style.resolution * pointCount, style.width, style.radial_resolution, false);
|
|
144
|
-
|
|
145
486
|
let material_def;
|
|
146
487
|
|
|
147
488
|
if (style.material_type === TubeMaterialType.Standard) {
|
|
148
489
|
material_def = new MeshStandardMaterial({
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
490
|
+
metalness: style.material.metalness,
|
|
491
|
+
roughness: style.material.roughness
|
|
492
|
+
});
|
|
152
493
|
} else if (style.material_type === TubeMaterialType.Matcap) {
|
|
153
494
|
|
|
154
495
|
material_def = new MeshMatcapMaterial();
|
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.6",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|