@damienmortini/three 0.1.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ import { ShaderMaterial } from '../../../three/src/materials/ShaderMaterial.js'
2
+ import { ShaderLib } from '../../../three/src/renderers/shaders/ShaderLib.js'
3
+ import { UniformsUtils } from '../../../three/src/renderers/shaders/UniformsUtils.js'
4
+ import DEFAULT_VERTEX from '../../../three/src/renderers/shaders/ShaderChunk/default_vertex.glsl.js'
5
+ import DEFAULT_FRAGMENT from '../../../three/src/renderers/shaders/ShaderChunk/default_fragment.glsl.js'
6
+
7
+ import Shader from '../../core/3d/Shader.js'
8
+
9
+ const toWebGL1 = (source, type) => {
10
+ source = source.replace(/#version.*?\n/g, '')
11
+ source = source.replace(/\btexture\b/g, 'texture2D')
12
+ if (type === 'vertex') {
13
+ source = source.replace(/(^\s*)\bin\b/gm, '$1attribute')
14
+ source = source.replace(/(^\s*)\bout\b/gm, '$1varying')
15
+ } else {
16
+ source = source.replace(/(^\s*)\bin\b/gm, '$1varying')
17
+ const results = /out vec4 (.*?);/.exec(source)
18
+ if (results) {
19
+ const fragColorName = results[1]
20
+ source = source.replace(/out.*?;/, '')
21
+ source = source.replace(new RegExp(`\\b${fragColorName}\\b`, 'g'), 'gl_FragColor')
22
+ }
23
+ }
24
+ return source
25
+ }
26
+
27
+ export default class THREEShaderMaterial extends ShaderMaterial {
28
+ constructor({
29
+ type = '',
30
+ vertex = undefined,
31
+ fragment = undefined,
32
+ vertexChunks = [],
33
+ fragmentChunks = [],
34
+ uniforms = {},
35
+ ...options
36
+ } = {}) {
37
+ const shader = new Shader({
38
+ vertex: vertex || (type ? ShaderLib[type].vertexShader : DEFAULT_VERTEX),
39
+ fragment: fragment || (type ? ShaderLib[type].fragmentShader : DEFAULT_FRAGMENT),
40
+ uniforms,
41
+ vertexChunks,
42
+ fragmentChunks,
43
+ })
44
+
45
+ const threeUniforms = {}
46
+ for (const [key, value] of Object.entries(shader.uniforms)) {
47
+ if (value.value !== undefined) {
48
+ continue
49
+ }
50
+ threeUniforms[key] = {
51
+ value,
52
+ }
53
+ }
54
+
55
+ super({
56
+ fragmentShader: toWebGL1(shader.fragment, 'fragment'),
57
+ vertexShader: toWebGL1(shader.vertex, 'vertex'),
58
+ uniforms: {
59
+ ...(type ? UniformsUtils.clone(ShaderLib[type].uniforms) : {}),
60
+ ...threeUniforms,
61
+ },
62
+ ...options,
63
+ })
64
+
65
+ this.lights = /lambert|phong|standard/.test(type)
66
+
67
+ for (const key of Object.keys(this.uniforms)) {
68
+ Object.defineProperty(this, key, {
69
+ configurable: true,
70
+ get: function () {
71
+ return this.uniforms[key].value
72
+ },
73
+ set: function (value) {
74
+ this.uniforms[key].value = value
75
+ },
76
+ })
77
+ }
78
+ }
79
+
80
+ clone() {
81
+ const clone = super.clone()
82
+ for (const key of Object.keys(clone.uniforms)) {
83
+ Object.defineProperty(clone, key, {
84
+ configurable: true,
85
+ get: function () {
86
+ return this.uniforms[key].value
87
+ },
88
+ set: function (value) {
89
+ this.uniforms[key].value = value
90
+ },
91
+ })
92
+ }
93
+ return clone
94
+ }
95
+ }
@@ -0,0 +1,113 @@
1
+ import FrenetSerretFrame from '../../core/math/FrenetSerretFrame.js'
2
+
3
+ import THREEShaderMaterial from './THREEShaderMaterial.js'
4
+
5
+ export default class THREELine extends THREE.Mesh {
6
+ constructor({
7
+ points = [new THREE.Vector3(0, -1, 0), new THREE.Vector3(0, 1, 0)],
8
+ material = new THREEShaderMaterial(),
9
+ detail = 3,
10
+ thickness = .1,
11
+ geometry = new THREE.CylinderBufferGeometry(1, 1, points.length - 1, detail, points.length - 1),
12
+ } = {}) {
13
+ super(geometry, material)
14
+
15
+ this.points = points
16
+
17
+ this.userData._thickness = thickness
18
+ this.userData._lineNormals = new Float32Array(this.points.length * 3)
19
+ this.userData._linePositions = new Float32Array(this.points.length * 3)
20
+
21
+ this.frustumCulled = false
22
+
23
+ const positions = this.geometry.getAttribute('position').array
24
+ const verticesNumber = positions.length / 3
25
+ const ids = new Float32Array(verticesNumber)
26
+ const offsetY = (points.length - 1) / 2
27
+ for (let i = 0; i < verticesNumber; i++) {
28
+ ids[i] = positions[i * 3 + 1] + offsetY
29
+ }
30
+
31
+ this.geometry.addAttribute('linePointId', new THREE.BufferAttribute(ids, 1))
32
+
33
+ if (!material.linePositions) {
34
+ material.add({
35
+ vertexShaderChunks: [
36
+ ['start', `
37
+ uniform float lineThickness;
38
+ uniform vec3 linePositions[${this.points.length}];
39
+ uniform vec3 lineNormals[${this.points.length}];
40
+
41
+ attribute float linePointId;
42
+ `],
43
+ ['main', `
44
+ vec3 position = position;
45
+ vec3 normal = normal;
46
+
47
+ vec3 linePosition = linePositions[int(linePointId)];
48
+ vec3 lineDirection = normalize(linePointId == ${this.points.length - 1}. ? linePosition - linePositions[int(linePointId) - 1] : linePositions[int(linePointId) + 1] - linePosition);
49
+ vec3 lineNormal = lineNormals[int(linePointId)];
50
+ vec3 lineBinormal = cross(lineNormal, lineDirection);
51
+
52
+ mat3 lineRotationMatrix = mat3(
53
+ lineNormal,
54
+ lineDirection,
55
+ lineBinormal
56
+ );
57
+ position.y = 0.;
58
+ position = linePosition + lineRotationMatrix * position * lineThickness;
59
+ normal = lineRotationMatrix * normal;
60
+ `],
61
+ ],
62
+ })
63
+ }
64
+
65
+ this.update()
66
+ }
67
+
68
+ onBeforeRender(renderer, scene, camera, geometry, material, group) {
69
+ this.material.lineThickness = this.userData._thickness
70
+ this.material.lineNormals = this.userData._lineNormals
71
+ this.material.linePositions = this.userData._linePositions
72
+
73
+ const threeProgram = renderer.properties.get(material).program
74
+
75
+ if (!threeProgram) {
76
+ return
77
+ }
78
+
79
+ const gl = renderer.getContext()
80
+ const uniforms = threeProgram.getUniforms()
81
+
82
+ gl.useProgram(threeProgram.program)
83
+ uniforms.setValue(gl, 'lineThickness', this.userData._thickness)
84
+ uniforms.setValue(gl, 'lineNormals', this.userData._lineNormals)
85
+ uniforms.setValue(gl, 'linePositions', this.userData._linePositions)
86
+ }
87
+
88
+ set thickness(value) {
89
+ this.userData._thickness = value
90
+ }
91
+
92
+ get thickness() {
93
+ return this.userData._thickness
94
+ }
95
+
96
+ update({
97
+ range = [0, this.points.length - 1],
98
+ } = {}) {
99
+ const end = range[1]
100
+ for (let i = range[0]; i <= end; i++) {
101
+ const point = this.points[i]
102
+ this.userData._linePositions[i * 3] = point.x
103
+ this.userData._linePositions[i * 3 + 1] = point.y
104
+ this.userData._linePositions[i * 3 + 2] = point.z
105
+ }
106
+
107
+ FrenetSerretFrame.compute({
108
+ positions: this.userData._linePositions,
109
+ normals: this.userData._lineNormals,
110
+ range,
111
+ })
112
+ }
113
+ }
@@ -0,0 +1,284 @@
1
+ import { Object3D, BufferGeometry, BufferAttribute, AnimationMixer, DataTexture, RGBAFormat, FloatType, RGBFormat, Points, Color, Matrix4 } from '../../../three/src/Three.js'
2
+ import TransformShader from '../../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
+ ${TransformShader.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
+ }
@@ -0,0 +1,49 @@
1
+ import {
2
+ Vector3,
3
+ } from '../../../three/build/three.module.js'
4
+
5
+ import THREELine from './THREELine.js'
6
+
7
+ import FrenetSerretFrame from '../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
+ }