@woosh/meep-engine 2.38.2 → 2.39.1
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/Quaternion.js +70 -0
- package/core/geom/Vector2.js +17 -0
- package/core/geom/v3_angle_between.js +17 -3
- package/engine/ecs/EntityBuilder.d.ts +3 -1
- package/engine/ecs/EntityBuilder.js +10 -1
- package/engine/ecs/EntityComponentDataset.js +1 -1
- package/engine/ecs/parent/ChildEntities.d.ts +3 -0
- package/engine/ecs/parent/ChildEntities.js +41 -0
- package/engine/ecs/system/AbstractContextSystem.js +4 -2
- package/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +1 -1
- package/engine/graphics/ecs/path/PathDisplayEvents.js +3 -2
- package/engine/graphics/ecs/path/PathDisplaySystem.js +5 -0
- package/engine/graphics/ecs/path/highlight/PathDisplayHighlightSystem.d.ts +7 -0
- package/engine/graphics/ecs/path/highlight/PathDisplayHighlightSystem.js +141 -0
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +86 -25
- package/engine/graphics/ecs/path/tube/BasicMaterialDefinition.d.ts +3 -0
- package/engine/graphics/ecs/path/tube/BasicMaterialDefinition.js +8 -0
- package/engine/graphics/ecs/path/tube/TubeMaterialType.d.ts +1 -0
- package/engine/graphics/ecs/path/tube/TubeMaterialType.js +1 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.d.ts +12 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.js +54 -9
- package/engine/graphics/ecs/path/tube/build/TubePathBuilder.js +67 -25
- package/engine/graphics/ecs/path/tube/build/build_geometry_catmullrom.js +12 -2
- package/engine/graphics/ecs/path/tube/build/build_geometry_linear.js +13 -2
- package/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +33 -28
- package/engine/graphics/ecs/path/tube/build/compute_smooth_profile_normals.js +41 -0
- package/engine/graphics/ecs/path/tube/build/fix_shape_normal_order.js +45 -0
- package/engine/graphics/ecs/path/tube/build/makeTubeGeometry.js +123 -347
- package/engine/graphics/ecs/path/tube/build/make_cap.js +274 -0
- package/engine/graphics/ecs/path/tube/build/make_ring_faces.js +40 -0
- package/engine/graphics/ecs/path/tube/build/make_ring_vertices.js +152 -0
- package/package.json +1 -1
- package/view/View.js +2 -2
- package/view/{compose3x3transform.js → m3_cm_compose_transform.js} +11 -3
- package/view/m3_rm_compose_transform.js +45 -0
- package/view/multiplyMatrices3.js +4 -4
|
@@ -1,336 +1,38 @@
|
|
|
1
1
|
import { BufferGeometry, Vector3 } from "three";
|
|
2
2
|
import { GeometryOutput } from "./GeometryOutput.js";
|
|
3
3
|
import { CapType } from "../CapType.js";
|
|
4
|
-
import {
|
|
4
|
+
import { make_ring_vertices } from "./make_ring_vertices.js";
|
|
5
|
+
import { assert } from "../../../../../../core/assert.js";
|
|
6
|
+
import { make_ring_faces } from "./make_ring_faces.js";
|
|
7
|
+
import { compute_cap_geometry_size, make_cap } from "./make_cap.js";
|
|
8
|
+
import { v3_angle_cos_between } from "../../../../../../core/geom/v3_angle_between.js";
|
|
5
9
|
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
* @param {GeometryOutput} out
|
|
10
|
-
* @param {number} Px
|
|
11
|
-
* @param {number} Py
|
|
12
|
-
* @param {number} Pz
|
|
13
|
-
* @param {Vector3} N normal
|
|
14
|
-
* @param {Vector3} B binormal
|
|
15
|
-
* @param {number} u X component of UV
|
|
16
|
-
* @param {number} radius
|
|
17
|
-
* @param {number} angular_step
|
|
18
|
-
* @param {number} radial_segments
|
|
19
|
-
*/
|
|
20
|
-
function make_ring_vertices(
|
|
21
|
-
out,
|
|
22
|
-
Px, Py, Pz,
|
|
23
|
-
N, B,
|
|
24
|
-
u,
|
|
25
|
-
radius, angular_step, radial_segments
|
|
26
|
-
) {
|
|
27
|
-
const out_positions = out.positions;
|
|
28
|
-
const out_normals = out.normals;
|
|
29
|
-
const out_uvs = out.uvs;
|
|
30
|
-
|
|
31
|
-
for (let j = 0; j <= radial_segments; j++) {
|
|
32
|
-
const angle = j * angular_step;
|
|
33
|
-
|
|
34
|
-
const sin = Math.sin(angle);
|
|
35
|
-
const cos = -Math.cos(angle);
|
|
36
|
-
|
|
37
|
-
// normal
|
|
38
|
-
|
|
39
|
-
const normal_x_r = (cos * N.x + sin * B.x);
|
|
40
|
-
const normal_y_r = (cos * N.y + sin * B.y);
|
|
41
|
-
const normal_z_r = (cos * N.z + sin * B.z);
|
|
42
|
-
|
|
43
|
-
const normal_length = 1 / Math.hypot(normal_x_r, normal_y_r, normal_z_r);
|
|
44
|
-
|
|
45
|
-
const normal_x = normal_x_r * normal_length;
|
|
46
|
-
const normal_y = normal_y_r * normal_length;
|
|
47
|
-
const normal_z = normal_z_r * normal_length;
|
|
48
|
-
|
|
49
|
-
const cv = out.cursor_vertices;
|
|
50
|
-
const cv3 = cv * 3;
|
|
51
|
-
|
|
52
|
-
out_normals[cv3] = normal_x;
|
|
53
|
-
out_normals[cv3 + 1] = normal_y;
|
|
54
|
-
out_normals[cv3 + 2] = normal_z;
|
|
55
|
-
|
|
56
|
-
// position
|
|
57
|
-
|
|
58
|
-
const vx = Px + radius * normal_x;
|
|
59
|
-
const vy = Py + radius * normal_y;
|
|
60
|
-
const vz = Pz + radius * normal_z;
|
|
61
|
-
|
|
62
|
-
out_positions[cv3] = vx;
|
|
63
|
-
out_positions[cv3 + 1] = vy;
|
|
64
|
-
out_positions[cv3 + 2] = vz;
|
|
65
|
-
|
|
66
|
-
// UV
|
|
67
|
-
const v = j / radial_segments;
|
|
68
|
-
|
|
69
|
-
const cv2 = cv * 2;
|
|
70
|
-
|
|
71
|
-
out_uvs[cv2] = u;
|
|
72
|
-
out_uvs[cv2 + 1] = v;
|
|
73
|
-
|
|
74
|
-
out.cursor_vertices++;
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
*
|
|
81
|
-
* @param {GeometryOutput} out
|
|
82
|
-
* @param {number} index_offset
|
|
83
|
-
* @param {number} tubular_segments
|
|
84
|
-
* @param {number} radial_segments
|
|
85
|
-
*/
|
|
86
|
-
function make_ring_faces(out, index_offset, tubular_segments, radial_segments) {
|
|
87
|
-
const indices = out.indices;
|
|
88
|
-
|
|
89
|
-
let i = 0, j = 0;
|
|
90
|
-
|
|
91
|
-
for (j = 1; j <= tubular_segments; j++) {
|
|
92
|
-
|
|
93
|
-
for (i = 1; i <= radial_segments; i++) {
|
|
94
|
-
|
|
95
|
-
const s_1 = radial_segments + 1;
|
|
96
|
-
|
|
97
|
-
const a = index_offset + s_1 * (j - 1) + (i - 1);
|
|
98
|
-
const b = index_offset + s_1 * j + (i - 1);
|
|
99
|
-
const c = index_offset + s_1 * j + i;
|
|
100
|
-
const d = index_offset + s_1 * (j - 1) + i;
|
|
101
|
-
|
|
102
|
-
// faces
|
|
103
|
-
|
|
104
|
-
const ci = out.cursor_indices;
|
|
105
|
-
|
|
106
|
-
indices[ci] = a;
|
|
107
|
-
indices[ci + 1] = b;
|
|
108
|
-
indices[ci + 2] = d;
|
|
109
|
-
|
|
110
|
-
indices[ci + 3] = b;
|
|
111
|
-
indices[ci + 4] = c;
|
|
112
|
-
indices[ci + 5] = d;
|
|
113
|
-
|
|
114
|
-
out.cursor_indices += 6;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
*
|
|
122
|
-
* @param {number} radial_segments
|
|
123
|
-
* @returns {number}
|
|
124
|
-
*/
|
|
125
|
-
function compute_cap_round_segment_count(radial_segments) {
|
|
126
|
-
return max2(3, Math.ceil(radial_segments / 4));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
*
|
|
131
|
-
* @param {number} index
|
|
132
|
-
* @param {Float32Array|number[]} in_positions
|
|
133
|
-
* @param {Vector3[]} in_normals
|
|
134
|
-
* @param {Vector3[]} in_binormals
|
|
135
|
-
* @param {GeometryOutput} out
|
|
136
|
-
* @param {number} radius
|
|
137
|
-
* @param {number} radial_segments
|
|
138
|
-
* @param {number} direction
|
|
139
|
-
*/
|
|
140
|
-
function make_cap_round(
|
|
141
|
-
out,
|
|
142
|
-
index,
|
|
143
|
-
in_positions, in_normals, in_binormals,
|
|
144
|
-
radius, radial_segments, direction
|
|
145
|
-
) {
|
|
146
|
-
// how many radial segments will be placed laterally to make up the cap
|
|
147
|
-
const cap_segment_count = compute_cap_round_segment_count(radial_segments);
|
|
148
|
-
|
|
149
|
-
const i3 = index * 3;
|
|
150
|
-
|
|
151
|
-
const Px = in_positions[i3];
|
|
152
|
-
const Py = in_positions[i3 + 1];
|
|
153
|
-
const Pz = in_positions[i3 + 2];
|
|
154
|
-
|
|
155
|
-
// retrieve corresponding normal and binormal
|
|
156
|
-
|
|
157
|
-
const N = in_normals[index];
|
|
158
|
-
const B = in_binormals[index];
|
|
159
|
-
|
|
160
|
-
const tangent = new Vector3();
|
|
161
|
-
tangent.crossVectors(N, B);
|
|
162
|
-
tangent.normalize();
|
|
163
|
-
|
|
164
|
-
const normal = direction > 0 ? N : N.clone().negate();
|
|
165
|
-
|
|
166
|
-
const angular_step_i = (Math.PI / 2) / cap_segment_count;
|
|
167
|
-
const angular_step_j = (Math.PI * 2) / radial_segments;
|
|
168
|
-
|
|
169
|
-
const uv_u = index / (in_positions.length / 3 - 1);
|
|
170
|
-
let i, j;
|
|
171
|
-
|
|
172
|
-
const index_offset = out.cursor_vertices;
|
|
173
|
-
|
|
174
|
-
for (i = 0; i <= cap_segment_count; i++) {
|
|
175
|
-
const angle_b = i * angular_step_i;
|
|
176
|
-
|
|
177
|
-
const sin_b = Math.sin(angle_b);
|
|
178
|
-
const cos_b = Math.cos(angle_b);
|
|
179
|
-
|
|
180
|
-
const cap_ring_radius = sin_b * radius;
|
|
181
|
-
|
|
182
|
-
const _d = -radius * direction;
|
|
183
|
-
|
|
184
|
-
const _px = Px + tangent.x * cos_b * _d;
|
|
185
|
-
const _py = Py + tangent.y * cos_b * _d;
|
|
186
|
-
const _pz = Pz + tangent.z * cos_b * _d;
|
|
187
|
-
|
|
188
|
-
make_ring_vertices(
|
|
189
|
-
out,
|
|
190
|
-
_px, _py, _pz,
|
|
191
|
-
normal, B, uv_u,
|
|
192
|
-
cap_ring_radius, angular_step_j, radial_segments
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
make_ring_faces(out, index_offset, cap_segment_count, radial_segments);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
*
|
|
201
|
-
* @param {number} index
|
|
202
|
-
* @param {Float32Array|number[]} in_positions
|
|
203
|
-
* @param {Vector3[]} in_normals
|
|
204
|
-
* @param {Vector3[]} in_binormals
|
|
205
|
-
* @param {GeometryOutput} out
|
|
206
|
-
* @param {number} radius
|
|
207
|
-
* @param {number} radial_segments
|
|
208
|
-
* @param {number} direction
|
|
209
|
-
*/
|
|
210
|
-
function make_cap_flat(
|
|
211
|
-
out,
|
|
212
|
-
index,
|
|
213
|
-
in_positions, in_normals, in_binormals,
|
|
214
|
-
radius, radial_segments, direction
|
|
215
|
-
) {
|
|
216
|
-
// how many radial segments will be placed laterally to make up the cap
|
|
217
|
-
const i3 = index * 3;
|
|
218
|
-
|
|
219
|
-
const Px = in_positions[i3];
|
|
220
|
-
const Py = in_positions[i3 + 1];
|
|
221
|
-
const Pz = in_positions[i3 + 2];
|
|
222
|
-
|
|
223
|
-
// retrieve corresponding normal and binormal
|
|
224
|
-
|
|
225
|
-
const N = in_normals[index];
|
|
226
|
-
const B = in_binormals[index];
|
|
227
|
-
|
|
228
|
-
const tangent = new Vector3();
|
|
229
|
-
tangent.crossVectors(N, B);
|
|
230
|
-
tangent.normalize();
|
|
231
|
-
|
|
232
|
-
const normal = direction > 0 ? N.clone().negate() : N;
|
|
233
|
-
|
|
234
|
-
const angular_step_j = (Math.PI * 2) / radial_segments;
|
|
235
|
-
|
|
236
|
-
const uv_u = index / (in_positions.length / 3 - 1);
|
|
237
|
-
|
|
238
|
-
const index_offset = out.cursor_vertices;
|
|
239
|
-
|
|
240
|
-
make_ring_vertices(
|
|
241
|
-
out,
|
|
242
|
-
Px, Py, Pz,
|
|
243
|
-
normal, B, uv_u,
|
|
244
|
-
radius, angular_step_j, radial_segments
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
make_ring_vertices(
|
|
248
|
-
out,
|
|
249
|
-
Px, Py, Pz,
|
|
250
|
-
normal, B, uv_u,
|
|
251
|
-
0, angular_step_j, radial_segments
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
make_ring_faces(out, index_offset, 1, radial_segments);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
*
|
|
259
|
-
* @param {number} index
|
|
260
|
-
* @param {Float32Array|number[]} in_positions
|
|
261
|
-
* @param {Vector3[]} in_normals
|
|
262
|
-
* @param {Vector3[]} in_binormals
|
|
263
|
-
* @param {GeometryOutput} out
|
|
264
|
-
* @param {number} radius
|
|
265
|
-
* @param {number} radial_segments
|
|
266
|
-
* @param {number} direction
|
|
267
|
-
* @param {CapType} type
|
|
268
|
-
*/
|
|
269
|
-
function make_cap(
|
|
270
|
-
out,
|
|
271
|
-
index,
|
|
272
|
-
in_positions, in_normals, in_binormals,
|
|
273
|
-
radius, radial_segments, direction, type
|
|
274
|
-
) {
|
|
275
|
-
if (type === CapType.None) {
|
|
276
|
-
// do nothing
|
|
277
|
-
} else if (type === CapType.Round) {
|
|
278
|
-
make_cap_round(
|
|
279
|
-
out,
|
|
280
|
-
index,
|
|
281
|
-
in_positions, in_normals, in_binormals,
|
|
282
|
-
radius, radial_segments,
|
|
283
|
-
direction
|
|
284
|
-
);
|
|
285
|
-
} else if (type === CapType.Flat) {
|
|
286
|
-
make_cap_flat(
|
|
287
|
-
out,
|
|
288
|
-
index,
|
|
289
|
-
in_positions, in_normals, in_binormals,
|
|
290
|
-
radius, radial_segments,
|
|
291
|
-
direction
|
|
292
|
-
);
|
|
293
|
-
} else {
|
|
294
|
-
throw new Error(`Unsupported cap type '${type}'`);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
*
|
|
300
|
-
* @param {number} count how many caps
|
|
301
|
-
* @param {{polygon_count:number, vertex_count:number}} out
|
|
302
|
-
* @param {number} radial_segments
|
|
303
|
-
* @param {CapType} type
|
|
304
|
-
*/
|
|
305
|
-
function compute_cap_geometry_size(count, out, radial_segments, type) {
|
|
306
|
-
|
|
307
|
-
if (type === CapType.None) {
|
|
308
|
-
// do nothing
|
|
309
|
-
} else if (type === CapType.Round) {
|
|
310
|
-
const cap_segment_count = compute_cap_round_segment_count(radial_segments);
|
|
311
|
-
|
|
312
|
-
out.vertex_count += count * (cap_segment_count + 1) * (radial_segments + 1);
|
|
313
|
-
out.polygon_count += count * cap_segment_count * (radial_segments) * 2;
|
|
314
|
-
} else if (type === CapType.Flat) {
|
|
315
|
-
out.vertex_count += count * (2) * (radial_segments + 1);
|
|
316
|
-
out.polygon_count += count * (radial_segments) * 2;
|
|
317
|
-
} else {
|
|
318
|
-
throw new Error(`Unsupported cap type '${type}'`);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
11
|
+
const v4_array = new Float32Array(4);
|
|
321
12
|
|
|
322
13
|
/**
|
|
323
14
|
* @see https://github.com/mrdoob/three.js/blob/master/src/geometries/TubeGeometry.js
|
|
324
15
|
* @param {Float32Array|number[]} in_positions
|
|
325
16
|
* @param {Vector3[]} in_normals
|
|
326
17
|
* @param {Vector3[]} in_binormals
|
|
327
|
-
* @param {
|
|
328
|
-
* @param {number}
|
|
18
|
+
* @param {Vector3[]} in_tangents
|
|
19
|
+
* @param {number[]} shape
|
|
20
|
+
* @param {number[]|Float32Array} shape_normal
|
|
21
|
+
* @param {number} shape_length
|
|
22
|
+
* @param {number[]|Float32Array} shape_transform
|
|
329
23
|
* @param {boolean} [closed]
|
|
330
24
|
* @param {CapType} [cap_type]
|
|
331
25
|
* @returns {BufferGeometry}
|
|
332
26
|
*/
|
|
333
|
-
export function makeTubeGeometry(
|
|
27
|
+
export function makeTubeGeometry(
|
|
28
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
29
|
+
shape, shape_normal, shape_length, shape_transform, closed = false, cap_type = CapType.Round
|
|
30
|
+
) {
|
|
31
|
+
assert.enum(cap_type, CapType, 'cap_type');
|
|
32
|
+
assert.isBoolean(closed, 'closed');
|
|
33
|
+
|
|
34
|
+
assert.isNumber(shape_length, 'shape_length');
|
|
35
|
+
assert.isArrayLike(shape, 'shape');
|
|
334
36
|
|
|
335
37
|
const out = new GeometryOutput();
|
|
336
38
|
|
|
@@ -341,12 +43,12 @@ export function makeTubeGeometry(in_positions, in_normals, in_binormals, radius,
|
|
|
341
43
|
|
|
342
44
|
|
|
343
45
|
const geometry_size = {
|
|
344
|
-
vertex_count: (tubular_segments + 1) * (
|
|
345
|
-
polygon_count: tubular_segments *
|
|
46
|
+
vertex_count: (tubular_segments + 1) * (shape_length + 1),
|
|
47
|
+
polygon_count: tubular_segments * shape_length * 2
|
|
346
48
|
};
|
|
347
49
|
|
|
348
50
|
if (!closed) {
|
|
349
|
-
compute_cap_geometry_size(2, geometry_size,
|
|
51
|
+
compute_cap_geometry_size(2, geometry_size, shape_length, cap_type);
|
|
350
52
|
}
|
|
351
53
|
|
|
352
54
|
out.allocate(
|
|
@@ -357,39 +59,44 @@ export function makeTubeGeometry(in_positions, in_normals, in_binormals, radius,
|
|
|
357
59
|
// create buffer data
|
|
358
60
|
if (!closed) {
|
|
359
61
|
// start cap
|
|
360
|
-
make_cap(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
if (!closed) {
|
|
366
|
-
// end cap
|
|
367
|
-
make_cap(out, point_count - 1, in_positions, in_normals, in_binormals, radius, radial_segments, -1, cap_type);
|
|
62
|
+
make_cap(
|
|
63
|
+
out, 0,
|
|
64
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
65
|
+
shape, shape_normal, shape_length, shape_transform, 1, cap_type
|
|
66
|
+
);
|
|
368
67
|
}
|
|
369
68
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
function generateBufferData() {
|
|
373
|
-
const index_offset = out.cursor_vertices;
|
|
69
|
+
const index_offset = out.cursor_vertices;
|
|
374
70
|
|
|
375
|
-
|
|
71
|
+
for (let i = 0; i < tubular_segments; i++) {
|
|
376
72
|
|
|
377
|
-
|
|
73
|
+
generateSegment(i);
|
|
378
74
|
|
|
379
|
-
|
|
75
|
+
}
|
|
380
76
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
77
|
+
// if the geometry is not closed, generate the last row of vertices and normals
|
|
78
|
+
// at the regular position on the given path
|
|
79
|
+
//
|
|
80
|
+
// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
|
|
385
81
|
|
|
386
|
-
|
|
82
|
+
generateSegment((closed === false) ? tubular_segments : 0);
|
|
387
83
|
|
|
388
|
-
|
|
389
|
-
|
|
84
|
+
// finally create faces
|
|
85
|
+
make_ring_faces(out, index_offset, tubular_segments, shape_length);
|
|
390
86
|
|
|
87
|
+
if (!closed) {
|
|
88
|
+
// end cap
|
|
89
|
+
make_cap(
|
|
90
|
+
out, point_count - 1,
|
|
91
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
92
|
+
shape, shape_normal, shape_length, shape_transform, -1, cap_type
|
|
93
|
+
);
|
|
391
94
|
}
|
|
392
95
|
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @param {number} i
|
|
99
|
+
*/
|
|
393
100
|
function generateSegment(i) {
|
|
394
101
|
|
|
395
102
|
// we use getPointAt to sample evenly distributed points from the given path
|
|
@@ -406,14 +113,14 @@ export function makeTubeGeometry(in_positions, in_normals, in_binormals, radius,
|
|
|
406
113
|
const B = in_binormals[i];
|
|
407
114
|
|
|
408
115
|
// generate normals and vertices for the current segment
|
|
409
|
-
|
|
410
|
-
const angular_step = (Math.PI * 2) / radial_segments;
|
|
116
|
+
compute_bend_normal(v4_array, i, tubular_segments, in_positions);
|
|
411
117
|
|
|
412
118
|
make_ring_vertices(
|
|
413
119
|
out,
|
|
414
120
|
Px, Py, Pz,
|
|
415
|
-
N, B, i
|
|
416
|
-
|
|
121
|
+
N, B, in_tangents[i],
|
|
122
|
+
i / tubular_segments, v4_array,
|
|
123
|
+
shape, shape_normal, shape_length, shape_transform
|
|
417
124
|
);
|
|
418
125
|
|
|
419
126
|
}
|
|
@@ -421,3 +128,72 @@ export function makeTubeGeometry(in_positions, in_normals, in_binormals, radius,
|
|
|
421
128
|
|
|
422
129
|
return out.build();
|
|
423
130
|
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
*
|
|
135
|
+
* @param {number[]|Float32Array} out
|
|
136
|
+
* @param {number} index
|
|
137
|
+
* @param {number} index_count
|
|
138
|
+
* @param {number[]|Float32Array} positions
|
|
139
|
+
*/
|
|
140
|
+
function compute_bend_normal(
|
|
141
|
+
out,
|
|
142
|
+
index,
|
|
143
|
+
index_count,
|
|
144
|
+
positions
|
|
145
|
+
) {
|
|
146
|
+
if (index <= 0 || index >= index_count - 1) {
|
|
147
|
+
// end points, no bending
|
|
148
|
+
|
|
149
|
+
out[0] = 0;
|
|
150
|
+
out[1] = 1;
|
|
151
|
+
out[2] = 0;
|
|
152
|
+
out[3] = 0;
|
|
153
|
+
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const index_next = index + 1;
|
|
158
|
+
const index_prev = index - 1;
|
|
159
|
+
|
|
160
|
+
const address_current = index * 3;
|
|
161
|
+
const address_next = index_next * 3;
|
|
162
|
+
const address_prev = index_prev * 3;
|
|
163
|
+
|
|
164
|
+
const i0_x = positions[address_prev];
|
|
165
|
+
const i0_y = positions[address_prev + 1];
|
|
166
|
+
const i0_z = positions[address_prev + 2];
|
|
167
|
+
|
|
168
|
+
const i1_x = positions[address_current];
|
|
169
|
+
const i1_y = positions[address_current + 1];
|
|
170
|
+
const i1_z = positions[address_current + 2];
|
|
171
|
+
|
|
172
|
+
const i2_x = positions[address_next];
|
|
173
|
+
const i2_y = positions[address_next + 1];
|
|
174
|
+
const i2_z = positions[address_next + 2];
|
|
175
|
+
|
|
176
|
+
const d0_x = i0_x - i1_x;
|
|
177
|
+
const d0_y = i0_y - i1_y;
|
|
178
|
+
const d0_z = i0_z - i1_z;
|
|
179
|
+
|
|
180
|
+
const d1_x = i1_x - i2_x;
|
|
181
|
+
const d1_y = i1_y - i2_y;
|
|
182
|
+
const d1_z = i1_z - i2_z;
|
|
183
|
+
|
|
184
|
+
// compute rotation axis
|
|
185
|
+
const cross_x = d0_y * d1_z - d0_z * d1_y;
|
|
186
|
+
const cross_y = d0_z * d1_x - d0_x * d1_z;
|
|
187
|
+
const cross_z = d0_x * d1_y - d0_y * d1_x;
|
|
188
|
+
|
|
189
|
+
const angle = v3_angle_cos_between(d0_x, d0_y, d0_z, d1_x, d1_y, d1_z);
|
|
190
|
+
|
|
191
|
+
const length_inv = 1 / Math.hypot(cross_x, cross_y, cross_z);
|
|
192
|
+
|
|
193
|
+
out[0] = cross_x * length_inv;
|
|
194
|
+
out[1] = cross_y * length_inv;
|
|
195
|
+
out[2] = cross_z * length_inv;
|
|
196
|
+
|
|
197
|
+
// bend amount
|
|
198
|
+
out[3] = (1 - Math.abs(angle)) * 0.5;
|
|
199
|
+
}
|