@damienmortini/three 0.1.187 → 0.1.188

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.
@@ -1,284 +1,284 @@
1
- import { Object3D, BufferGeometry, BufferAttribute, AnimationMixer, DataTexture, RGBAFormat, FloatType, RGBFormat, Points, Color, Matrix4 } from '../../../three/src/Three.js'
2
- import { quaternionFromMatrix } from '@damienmortini/core/shader/TransformShader.js'
3
- import THREEGPGPUSystem from '../../three/gpgpu/THREEGPGPUSystem.js'
4
- import THREEShaderMaterial from '../../three/material/THREEShaderMaterial.js'
5
-
6
- export default class THREEMotionVectorObject extends Object3D {
7
- constructor({
8
- renderer,
9
- gltfData,
10
- pointsAttributes = undefined,
11
- material = new THREEShaderMaterial({
12
- skinning: true,
13
- type: 'basic',
14
- uniforms: {
15
- diffuse: new Color('#ff0000'),
16
- },
17
- vertexChunks: [
18
- ['main', `
19
- gl_PointSize = 2.;
20
- `],
21
- ],
22
- }),
23
- pointCount = undefined,
24
- }) {
25
- super()
26
-
27
- this.loop = false
28
-
29
- this._pointCount = pointCount
30
-
31
- this._initialized = false
32
-
33
- const object = gltfData.scene
34
- this._mesh = object
35
- object.traverse((object) => {
36
- if (object.skeleton) {
37
- this._mesh = object
38
- this._mesh.frustumCulled = false
39
- }
40
- })
41
- // this._mesh.visible = false;
42
- this._mesh.scale.set(0, 0, 0)
43
- if (!pointsAttributes) {
44
- pointsAttributes = new Map()
45
- for (const [name, value] of Object.entries(this._mesh.geometry.attributes)) {
46
- pointsAttributes.set(name, {
47
- data: value.array,
48
- size: value.itemSize,
49
- })
50
- }
51
- }
52
- this.add(object)
53
-
54
- if (this._pointCount) {
55
- for (const attributeData of pointsAttributes.values()) {
56
- const newArray = new attributeData.data.constructor(this._pointCount * attributeData.size)
57
- const stride = attributeData.size
58
- const difference = Math.floor(attributeData.data.length / newArray.length)
59
- for (let index = 0; index < this._pointCount; index++) {
60
- for (let componentIndex = 0; componentIndex < stride; componentIndex++) {
61
- newArray[index * stride + componentIndex] = attributeData.data[index * stride * difference + componentIndex]
62
- }
63
- }
64
- attributeData.data = newArray
65
- }
66
- } else {
67
- const firstAttribute = pointsAttributes.values().next().value
68
- this._pointCount = firstAttribute.data.length / firstAttribute.size
69
- }
70
-
71
- this._skeleton = this._mesh.skeleton
72
-
73
- // Create bonesTexture manually
74
- // https://github.com/mrdoob/three.js/blob/cd41804aa436bb2cfd79797c04985f75c4c63e63/src/renderers/WebGLRenderer.js#L1632
75
-
76
- // let size = Math.sqrt(this._skeleton.bones.length * 4); // 4 pixels needed for 1 matrix
77
- // size = MathUtils.ceilPowerOfTwo(size);
78
- // size = Math.max(size, 4);
79
-
80
- // const boneMatrices = new Float32Array(size * size * 4); // 4 floats per RGBA pixel
81
- // boneMatrices.set(this._skeleton.boneMatrices); // copy current values
82
-
83
- // let boneTexture;
84
- // if (renderer.capabilities.isWebGL2) {
85
- // boneTexture = new DataTexture(boneMatrices, size, size, RGBAFormat, FloatType);
86
- // } else {
87
- // boneTexture = new DataTexture(Float16.fromFloat32Array(boneMatrices), size, size, RGBAFormat, HalfFloatType);
88
- // }
89
-
90
- // this._skeleton.boneMatrices = boneMatrices;
91
- // this._skeleton.boneTexture = boneTexture;
92
- // this._skeleton.boneTextureSize = size;
93
-
94
- //
95
-
96
- const geometry = new BufferGeometry()
97
-
98
- for (const [name, attributeData] of pointsAttributes) {
99
- geometry.setAttribute(name, new BufferAttribute(attributeData.data, attributeData.size))
100
- }
101
-
102
- this._points = new Points(geometry, material)
103
- this._points.isSkinnedMesh = true
104
- this._points.skeleton = this._skeleton
105
- this._points.bindMatrix = new Matrix4()
106
- this._points.bindMatrixInverse = new Matrix4()
107
- this._points.visible = false
108
- this._points.frustumCulled = false
109
- this.add(this._points)
110
-
111
- const animation = gltfData.animations[0]
112
- this._animationMixer = new AnimationMixer(object)
113
- this._animationClip = animation
114
- this._animationAction = this._animationMixer.clipAction(this._animationClip)
115
- this._animationAction.play()
116
-
117
- const pointTextures = new Map()
118
- const pointTextureSize = Math.ceil(Math.sqrt(this._pointCount))
119
- for (const [name, attributeData] of pointsAttributes) {
120
- const textureData = new Float32Array(pointTextureSize * pointTextureSize * attributeData.size)
121
- textureData.set(attributeData.data)
122
- const texture = new DataTexture(textureData, pointTextureSize, pointTextureSize, attributeData.size === 3 ? RGBFormat : RGBAFormat, FloatType)
123
- pointTextures.set(name, texture)
124
- }
125
-
126
- this._gpgpuSystem = new THREEGPGPUSystem({
127
- data: new Float32Array((4 * 3) * this._pointCount),
128
- stride: 3,
129
- renderer: renderer,
130
- format: RGBAFormat,
131
- uniforms: {
132
- pointsTextureSize: pointTextureSize,
133
- pointPositionTexture: pointTextures.get('position'),
134
- pointSkinIndexTexture: pointTextures.get('skinIndex'),
135
- pointSkinWeightTexture: pointTextures.get('skinWeight'),
136
- pointNormalTexture: pointTextures.get('normal'),
137
- },
138
- fragmentChunks: [
139
- ['start', `
140
- uniform float pointsTextureSize;
141
- uniform highp sampler2D pointPositionTexture;
142
- uniform highp sampler2D pointNormalTexture;
143
- uniform highp sampler2D pointSkinIndexTexture;
144
- uniform highp sampler2D pointSkinWeightTexture;
145
-
146
- uniform highp sampler2D boneTexture;
147
- uniform int boneTextureSize;
148
-
149
- ${quaternionFromMatrix()}
150
-
151
- mat4 getBoneMatrix( const in float i ) {
152
- float j = i * 4.0;
153
- float x = mod( j, float( boneTextureSize ) );
154
- float y = floor( j / float( boneTextureSize ) );
155
- float dx = 1.0 / float( boneTextureSize );
156
- float dy = 1.0 / float( boneTextureSize );
157
- y = dy * ( y + 0.5 );
158
- vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );
159
- vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );
160
- vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );
161
- vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );
162
- mat4 bone = mat4( v1, v2, v3, v4 );
163
- return bone;
164
- }
165
- `],
166
- ['end', `
167
- vec3 previousPosition = getDataChunk(0).xyz;
168
- int chunkIndex = getChunkIndex();
169
-
170
- float pointID = float(getDataIndex());
171
-
172
- float x = mod(pointID, pointsTextureSize);
173
- float y = floor(pointID / pointsTextureSize);
174
- float dx = 1. / pointsTextureSize;
175
- float dy = 1. / pointsTextureSize;
176
- x = dx * (x + .5);
177
- y = dy * (y + .5);
178
-
179
- vec3 position = texture(pointPositionTexture, vec2(x, y)).rgb;
180
- vec3 normal = texture(pointNormalTexture, vec2(x, y)).rgb;
181
- vec4 skinIndex = texture(pointSkinIndexTexture, vec2(x, y));
182
- vec4 skinWeight = texture(pointSkinWeightTexture, vec2(x, y));
183
-
184
- mat4 boneMatX = getBoneMatrix( skinIndex.x );
185
- mat4 boneMatY = getBoneMatrix( skinIndex.y );
186
- mat4 boneMatZ = getBoneMatrix( skinIndex.z );
187
- mat4 boneMatW = getBoneMatrix( skinIndex.w );
188
-
189
- vec4 data;
190
- if(chunkIndex < 2) {
191
- vec4 skinVertex = vec4( position, 1.0 );
192
- vec4 skinned = vec4( 0.0 );
193
- skinned += boneMatX * skinVertex * skinWeight.x;
194
- skinned += boneMatY * skinVertex * skinWeight.y;
195
- skinned += boneMatZ * skinVertex * skinWeight.z;
196
- skinned += boneMatW * skinVertex * skinWeight.w;
197
-
198
- position = skinned.xyz;
199
-
200
- vec3 velocity = position - previousPosition;
201
-
202
- if(chunkIndex == 0) {
203
- data = vec4(position, 0.);
204
- } else if(chunkIndex == 1) {
205
- data = vec4(velocity, 0.);
206
- }
207
- } else if(chunkIndex == 2) {
208
- mat4 rotationMatrix = mat4(0.);
209
- rotationMatrix += skinWeight.x * boneMatX;
210
- rotationMatrix += skinWeight.y * boneMatY;
211
- rotationMatrix += skinWeight.z * boneMatZ;
212
- rotationMatrix += skinWeight.w * boneMatW;
213
- vec4 quaternion = quaternionFromMatrix(rotationMatrix);
214
- data = quaternion;
215
- }
216
- gl_FragColor = data;
217
- `],
218
- ],
219
- })
220
- this._gpgpuSystem.onBeforeRender = () => {
221
- this._gpgpuSystem.material.boneTexture = this._skeleton.boneTexture
222
- this._gpgpuSystem.material.boneTextureSize = this._skeleton.boneTextureSize
223
- }
224
- }
225
-
226
- get pointCount() {
227
- return this._pointCount
228
- }
229
-
230
- get dataTexture() {
231
- return this._gpgpuSystem.dataTexture
232
- }
233
-
234
- get dataTextureStride() {
235
- return this._gpgpuSystem.stride
236
- }
237
-
238
- get dataTextureSize() {
239
- return this._gpgpuSystem.dataTextureSize
240
- }
241
-
242
- get meshVisible() {
243
- return this._mesh.visible
244
- }
245
-
246
- set meshVisible(value) {
247
- this._mesh.visible = value
248
- }
249
-
250
- get pointsVisible() {
251
- return this._points.visible
252
- }
253
-
254
- set pointsVisible(value) {
255
- this._points.visible = value
256
- }
257
-
258
- get currentTime() {
259
- return this._animationMixer.time
260
- }
261
-
262
- set currentTime(value) {
263
- if (value >= this._animationClip.duration) {
264
- if (this.loop) {
265
- value = 0
266
- } else {
267
- value = this._animationClip.duration
268
- }
269
- }
270
- this._animationMixer.setTime(Math.min(value, this._animationClip.duration - .01))
271
- this._update()
272
- }
273
-
274
- _update() {
275
- if (!this._points.visible && !this._mesh.visible) {
276
- this._skeleton.update()
277
- }
278
- if (!this._initialized) {
279
- this._gpgpuSystem.update()
280
- this._initialized = true
281
- }
282
- this._gpgpuSystem.update()
283
- }
284
- }
1
+ import { Object3D, BufferGeometry, BufferAttribute, AnimationMixer, DataTexture, RGBAFormat, FloatType, RGBFormat, Points, Color, Matrix4 } from '../../../three/src/Three.js'
2
+ import { quaternionFromMatrix } from '@damienmortini/core/shader/TransformShader.js'
3
+ import THREEGPGPUSystem from '../../three/gpgpu/THREEGPGPUSystem.js'
4
+ import THREEShaderMaterial from '../../three/material/THREEShaderMaterial.js'
5
+
6
+ export default class THREEMotionVectorObject extends Object3D {
7
+ constructor({
8
+ renderer,
9
+ gltfData,
10
+ pointsAttributes = undefined,
11
+ material = new THREEShaderMaterial({
12
+ skinning: true,
13
+ type: 'basic',
14
+ uniforms: {
15
+ diffuse: new Color('#ff0000'),
16
+ },
17
+ vertexChunks: [
18
+ ['main', `
19
+ gl_PointSize = 2.;
20
+ `],
21
+ ],
22
+ }),
23
+ pointCount = undefined,
24
+ }) {
25
+ super()
26
+
27
+ this.loop = false
28
+
29
+ this._pointCount = pointCount
30
+
31
+ this._initialized = false
32
+
33
+ const object = gltfData.scene
34
+ this._mesh = object
35
+ object.traverse((object) => {
36
+ if (object.skeleton) {
37
+ this._mesh = object
38
+ this._mesh.frustumCulled = false
39
+ }
40
+ })
41
+ // this._mesh.visible = false;
42
+ this._mesh.scale.set(0, 0, 0)
43
+ if (!pointsAttributes) {
44
+ pointsAttributes = new Map()
45
+ for (const [name, value] of Object.entries(this._mesh.geometry.attributes)) {
46
+ pointsAttributes.set(name, {
47
+ data: value.array,
48
+ size: value.itemSize,
49
+ })
50
+ }
51
+ }
52
+ this.add(object)
53
+
54
+ if (this._pointCount) {
55
+ for (const attributeData of pointsAttributes.values()) {
56
+ const newArray = new attributeData.data.constructor(this._pointCount * attributeData.size)
57
+ const stride = attributeData.size
58
+ const difference = Math.floor(attributeData.data.length / newArray.length)
59
+ for (let index = 0; index < this._pointCount; index++) {
60
+ for (let componentIndex = 0; componentIndex < stride; componentIndex++) {
61
+ newArray[index * stride + componentIndex] = attributeData.data[index * stride * difference + componentIndex]
62
+ }
63
+ }
64
+ attributeData.data = newArray
65
+ }
66
+ } else {
67
+ const firstAttribute = pointsAttributes.values().next().value
68
+ this._pointCount = firstAttribute.data.length / firstAttribute.size
69
+ }
70
+
71
+ this._skeleton = this._mesh.skeleton
72
+
73
+ // Create bonesTexture manually
74
+ // https://github.com/mrdoob/three.js/blob/cd41804aa436bb2cfd79797c04985f75c4c63e63/src/renderers/WebGLRenderer.js#L1632
75
+
76
+ // let size = Math.sqrt(this._skeleton.bones.length * 4); // 4 pixels needed for 1 matrix
77
+ // size = MathUtils.ceilPowerOfTwo(size);
78
+ // size = Math.max(size, 4);
79
+
80
+ // const boneMatrices = new Float32Array(size * size * 4); // 4 floats per RGBA pixel
81
+ // boneMatrices.set(this._skeleton.boneMatrices); // copy current values
82
+
83
+ // let boneTexture;
84
+ // if (renderer.capabilities.isWebGL2) {
85
+ // boneTexture = new DataTexture(boneMatrices, size, size, RGBAFormat, FloatType);
86
+ // } else {
87
+ // boneTexture = new DataTexture(Float16.fromFloat32Array(boneMatrices), size, size, RGBAFormat, HalfFloatType);
88
+ // }
89
+
90
+ // this._skeleton.boneMatrices = boneMatrices;
91
+ // this._skeleton.boneTexture = boneTexture;
92
+ // this._skeleton.boneTextureSize = size;
93
+
94
+ //
95
+
96
+ const geometry = new BufferGeometry()
97
+
98
+ for (const [name, attributeData] of pointsAttributes) {
99
+ geometry.setAttribute(name, new BufferAttribute(attributeData.data, attributeData.size))
100
+ }
101
+
102
+ this._points = new Points(geometry, material)
103
+ this._points.isSkinnedMesh = true
104
+ this._points.skeleton = this._skeleton
105
+ this._points.bindMatrix = new Matrix4()
106
+ this._points.bindMatrixInverse = new Matrix4()
107
+ this._points.visible = false
108
+ this._points.frustumCulled = false
109
+ this.add(this._points)
110
+
111
+ const animation = gltfData.animations[0]
112
+ this._animationMixer = new AnimationMixer(object)
113
+ this._animationClip = animation
114
+ this._animationAction = this._animationMixer.clipAction(this._animationClip)
115
+ this._animationAction.play()
116
+
117
+ const pointTextures = new Map()
118
+ const pointTextureSize = Math.ceil(Math.sqrt(this._pointCount))
119
+ for (const [name, attributeData] of pointsAttributes) {
120
+ const textureData = new Float32Array(pointTextureSize * pointTextureSize * attributeData.size)
121
+ textureData.set(attributeData.data)
122
+ const texture = new DataTexture(textureData, pointTextureSize, pointTextureSize, attributeData.size === 3 ? RGBFormat : RGBAFormat, FloatType)
123
+ pointTextures.set(name, texture)
124
+ }
125
+
126
+ this._gpgpuSystem = new THREEGPGPUSystem({
127
+ data: new Float32Array((4 * 3) * this._pointCount),
128
+ stride: 3,
129
+ renderer: renderer,
130
+ format: RGBAFormat,
131
+ uniforms: {
132
+ pointsTextureSize: pointTextureSize,
133
+ pointPositionTexture: pointTextures.get('position'),
134
+ pointSkinIndexTexture: pointTextures.get('skinIndex'),
135
+ pointSkinWeightTexture: pointTextures.get('skinWeight'),
136
+ pointNormalTexture: pointTextures.get('normal'),
137
+ },
138
+ fragmentChunks: [
139
+ ['start', `
140
+ uniform float pointsTextureSize;
141
+ uniform highp sampler2D pointPositionTexture;
142
+ uniform highp sampler2D pointNormalTexture;
143
+ uniform highp sampler2D pointSkinIndexTexture;
144
+ uniform highp sampler2D pointSkinWeightTexture;
145
+
146
+ uniform highp sampler2D boneTexture;
147
+ uniform int boneTextureSize;
148
+
149
+ ${quaternionFromMatrix()}
150
+
151
+ mat4 getBoneMatrix( const in float i ) {
152
+ float j = i * 4.0;
153
+ float x = mod( j, float( boneTextureSize ) );
154
+ float y = floor( j / float( boneTextureSize ) );
155
+ float dx = 1.0 / float( boneTextureSize );
156
+ float dy = 1.0 / float( boneTextureSize );
157
+ y = dy * ( y + 0.5 );
158
+ vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );
159
+ vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );
160
+ vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );
161
+ vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );
162
+ mat4 bone = mat4( v1, v2, v3, v4 );
163
+ return bone;
164
+ }
165
+ `],
166
+ ['end', `
167
+ vec3 previousPosition = getDataChunk(0).xyz;
168
+ int chunkIndex = getChunkIndex();
169
+
170
+ float pointID = float(getDataIndex());
171
+
172
+ float x = mod(pointID, pointsTextureSize);
173
+ float y = floor(pointID / pointsTextureSize);
174
+ float dx = 1. / pointsTextureSize;
175
+ float dy = 1. / pointsTextureSize;
176
+ x = dx * (x + .5);
177
+ y = dy * (y + .5);
178
+
179
+ vec3 position = texture(pointPositionTexture, vec2(x, y)).rgb;
180
+ vec3 normal = texture(pointNormalTexture, vec2(x, y)).rgb;
181
+ vec4 skinIndex = texture(pointSkinIndexTexture, vec2(x, y));
182
+ vec4 skinWeight = texture(pointSkinWeightTexture, vec2(x, y));
183
+
184
+ mat4 boneMatX = getBoneMatrix( skinIndex.x );
185
+ mat4 boneMatY = getBoneMatrix( skinIndex.y );
186
+ mat4 boneMatZ = getBoneMatrix( skinIndex.z );
187
+ mat4 boneMatW = getBoneMatrix( skinIndex.w );
188
+
189
+ vec4 data;
190
+ if(chunkIndex < 2) {
191
+ vec4 skinVertex = vec4( position, 1.0 );
192
+ vec4 skinned = vec4( 0.0 );
193
+ skinned += boneMatX * skinVertex * skinWeight.x;
194
+ skinned += boneMatY * skinVertex * skinWeight.y;
195
+ skinned += boneMatZ * skinVertex * skinWeight.z;
196
+ skinned += boneMatW * skinVertex * skinWeight.w;
197
+
198
+ position = skinned.xyz;
199
+
200
+ vec3 velocity = position - previousPosition;
201
+
202
+ if(chunkIndex == 0) {
203
+ data = vec4(position, 0.);
204
+ } else if(chunkIndex == 1) {
205
+ data = vec4(velocity, 0.);
206
+ }
207
+ } else if(chunkIndex == 2) {
208
+ mat4 rotationMatrix = mat4(0.);
209
+ rotationMatrix += skinWeight.x * boneMatX;
210
+ rotationMatrix += skinWeight.y * boneMatY;
211
+ rotationMatrix += skinWeight.z * boneMatZ;
212
+ rotationMatrix += skinWeight.w * boneMatW;
213
+ vec4 quaternion = quaternionFromMatrix(rotationMatrix);
214
+ data = quaternion;
215
+ }
216
+ gl_FragColor = data;
217
+ `],
218
+ ],
219
+ })
220
+ this._gpgpuSystem.onBeforeRender = () => {
221
+ this._gpgpuSystem.material.boneTexture = this._skeleton.boneTexture
222
+ this._gpgpuSystem.material.boneTextureSize = this._skeleton.boneTextureSize
223
+ }
224
+ }
225
+
226
+ get pointCount() {
227
+ return this._pointCount
228
+ }
229
+
230
+ get dataTexture() {
231
+ return this._gpgpuSystem.dataTexture
232
+ }
233
+
234
+ get dataTextureStride() {
235
+ return this._gpgpuSystem.stride
236
+ }
237
+
238
+ get dataTextureSize() {
239
+ return this._gpgpuSystem.dataTextureSize
240
+ }
241
+
242
+ get meshVisible() {
243
+ return this._mesh.visible
244
+ }
245
+
246
+ set meshVisible(value) {
247
+ this._mesh.visible = value
248
+ }
249
+
250
+ get pointsVisible() {
251
+ return this._points.visible
252
+ }
253
+
254
+ set pointsVisible(value) {
255
+ this._points.visible = value
256
+ }
257
+
258
+ get currentTime() {
259
+ return this._animationMixer.time
260
+ }
261
+
262
+ set currentTime(value) {
263
+ if (value >= this._animationClip.duration) {
264
+ if (this.loop) {
265
+ value = 0
266
+ } else {
267
+ value = this._animationClip.duration
268
+ }
269
+ }
270
+ this._animationMixer.setTime(Math.min(value, this._animationClip.duration - .01))
271
+ this._update()
272
+ }
273
+
274
+ _update() {
275
+ if (!this._points.visible && !this._mesh.visible) {
276
+ this._skeleton.update()
277
+ }
278
+ if (!this._initialized) {
279
+ this._gpgpuSystem.update()
280
+ this._initialized = true
281
+ }
282
+ this._gpgpuSystem.update()
283
+ }
284
+ }
@@ -1,49 +1,49 @@
1
- import {
2
- Vector3,
3
- } from '../../../three/src/Three.js'
4
-
5
- import THREELine from './THREELine.js'
6
-
7
- import FrenetSerretFrame from '@damienmortini/math/FrenetSerretFrame.js'
8
-
9
- export default class THREERibbon extends THREELine {
10
- constructor({
11
- points,
12
- thickness,
13
- detail,
14
- geometry,
15
- material,
16
- } = {}) {
17
- super({
18
- points,
19
- thickness,
20
- detail,
21
- geometry,
22
- material,
23
- })
24
-
25
- this.head = points[this.points.length - 1].clone()
26
- }
27
-
28
- update() {
29
- if (!this._initialized) {
30
- super.update()
31
- this._initialized = true
32
- return
33
- }
34
-
35
- this.userData._linePositions.copyWithin(0, 3)
36
- this.userData._lineNormals.copyWithin(0, 3)
37
-
38
- const headId = this.points.length - 1
39
- this.userData._linePositions[headId * 3] = this.head.x
40
- this.userData._linePositions[headId * 3 + 1] = this.head.y
41
- this.userData._linePositions[headId * 3 + 2] = this.head.z
42
-
43
- FrenetSerretFrame.compute({
44
- positions: this.userData._linePositions,
45
- normals: this.userData._lineNormals,
46
- range: [headId - 3, headId],
47
- })
48
- }
49
- }
1
+ import {
2
+ Vector3,
3
+ } from '../../../three/src/Three.js'
4
+
5
+ import THREELine from './THREELine.js'
6
+
7
+ import FrenetSerretFrame from '@damienmortini/math/FrenetSerretFrame.js'
8
+
9
+ export default class THREERibbon extends THREELine {
10
+ constructor({
11
+ points,
12
+ thickness,
13
+ detail,
14
+ geometry,
15
+ material,
16
+ } = {}) {
17
+ super({
18
+ points,
19
+ thickness,
20
+ detail,
21
+ geometry,
22
+ material,
23
+ })
24
+
25
+ this.head = points[this.points.length - 1].clone()
26
+ }
27
+
28
+ update() {
29
+ if (!this._initialized) {
30
+ super.update()
31
+ this._initialized = true
32
+ return
33
+ }
34
+
35
+ this.userData._linePositions.copyWithin(0, 3)
36
+ this.userData._lineNormals.copyWithin(0, 3)
37
+
38
+ const headId = this.points.length - 1
39
+ this.userData._linePositions[headId * 3] = this.head.x
40
+ this.userData._linePositions[headId * 3 + 1] = this.head.y
41
+ this.userData._linePositions[headId * 3 + 2] = this.head.z
42
+
43
+ FrenetSerretFrame.compute({
44
+ positions: this.userData._linePositions,
45
+ normals: this.userData._lineNormals,
46
+ range: [headId - 3, headId],
47
+ })
48
+ }
49
+ }