three-base 2.0.1 → 2.0.3

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.
Files changed (102) hide show
  1. package/ApngTexture.d.ts +13 -0
  2. package/ApngTexture.js +61 -0
  3. package/ApngTexture.ts +91 -0
  4. package/ApngTextureManage.d.ts +18 -0
  5. package/ApngTextureManage.js +87 -0
  6. package/ApngTextureManage.ts +130 -0
  7. package/EventMesh.d.ts +18 -0
  8. package/EventMesh.js +59 -0
  9. package/EventMesh.ts +79 -0
  10. package/ExtrudeMesh.d.ts +111 -0
  11. package/ExtrudeMesh.js +363 -0
  12. package/ExtrudeMesh.ts +571 -0
  13. package/FPScontrol.d.ts +44 -0
  14. package/FPScontrol.js +170 -0
  15. package/FPScontrol.ts +209 -0
  16. package/InstancedGroupMesh.d.ts +10 -0
  17. package/InstancedGroupMesh.js +63 -0
  18. package/InstancedGroupMesh.ts +80 -0
  19. package/KeyFrameAnimation.d.ts +25 -0
  20. package/KeyFrameAnimation.js +78 -0
  21. package/KeyFrameAnimation.ts +122 -0
  22. package/PlaneModal1/PlaneModal1.d.ts +31 -0
  23. package/PlaneModal1/PlaneModal1.js +105 -0
  24. package/PlaneModal1/PlaneModal1.ts +151 -0
  25. package/PlaneModal1/index.d.ts +1 -0
  26. package/PlaneModal1/index.js +1 -0
  27. package/PlaneModal1/index.ts +1 -0
  28. package/PlaneModal1/planeModal.png +0 -0
  29. package/PlaneText.d.ts +37 -0
  30. package/PlaneText.js +30 -0
  31. package/PlaneText.ts +58 -0
  32. package/PlaneWithHtml.d.ts +11 -0
  33. package/PlaneWithHtml.js +67 -0
  34. package/PlaneWithHtml.ts +84 -0
  35. package/PointLight/PointLight.d.ts +13 -0
  36. package/PointLight/PointLight.js +63 -0
  37. package/PointLight/PointLight.ts +74 -0
  38. package/PointLight/index.d.ts +1 -0
  39. package/PointLight/index.js +1 -0
  40. package/PointLight/index.ts +1 -0
  41. package/PointLight/pointLight_map.png +0 -0
  42. package/README.md +1 -1
  43. package/Sky/Sky.d.ts +13 -0
  44. package/Sky/Sky.js +28 -0
  45. package/Sky/Sky.ts +36 -0
  46. package/Sky/bluesky.jpg +0 -0
  47. package/Sky/index.d.ts +1 -0
  48. package/Sky/index.js +1 -0
  49. package/Sky/index.ts +1 -0
  50. package/SpriteModal1/SpriteModal1.d.ts +30 -0
  51. package/SpriteModal1/SpriteModal1.js +110 -0
  52. package/SpriteModal1/SpriteModal1.ts +160 -0
  53. package/SpriteModal1/index.d.ts +1 -0
  54. package/SpriteModal1/index.js +1 -0
  55. package/SpriteModal1/index.ts +1 -0
  56. package/SpriteModal1/spriteModal1.png +0 -0
  57. package/SpriteText.d.ts +45 -0
  58. package/SpriteText.js +162 -0
  59. package/SpriteText.ts +189 -0
  60. package/SpriteText2.d.ts +47 -0
  61. package/SpriteText2.js +197 -0
  62. package/SpriteText2.ts +236 -0
  63. package/Text3D/Text3D.d.ts +20 -0
  64. package/Text3D/Text3D.js +62 -0
  65. package/Text3D/Text3D.ts +93 -0
  66. package/Text3D/fontController.d.ts +59 -0
  67. package/Text3D/fontController.js +200 -0
  68. package/Text3D/fontController.ts +285 -0
  69. package/Text3D/gentilis.json +811 -0
  70. package/Text3D/index.d.ts +1 -0
  71. package/Text3D/index.js +1 -0
  72. package/Text3D/index.ts +1 -0
  73. package/ThreeBase.d.ts +61 -0
  74. package/ThreeBase.js +403 -0
  75. package/ThreeBase.ts +484 -0
  76. package/ThreeMouse.d.ts +39 -0
  77. package/ThreeMouse.js +359 -0
  78. package/ThreeMouse.ts +465 -0
  79. package/Transition.d.ts +43 -0
  80. package/Transition.js +196 -0
  81. package/Transition.ts +268 -0
  82. package/index.d.ts +1 -0
  83. package/keyContorls.d.ts +25 -0
  84. package/keyContorls.js +98 -0
  85. package/keyContorls.ts +127 -0
  86. package/package.json +15 -20
  87. package/pass/FullScreenQuad.d.ts +7 -0
  88. package/pass/FullScreenQuad.js +25 -0
  89. package/pass/FullScreenQuad.ts +33 -0
  90. package/pass/stroke_pass.d.ts +2 -0
  91. package/pass/stroke_pass.js +190 -0
  92. package/pass/stroke_pass.ts +211 -0
  93. package/shaders.d.ts +17 -0
  94. package/shaders.js +245 -0
  95. package/shaders.ts +264 -0
  96. package/threeLoader.d.ts +20 -0
  97. package/threeLoader.js +118 -0
  98. package/threeLoader.ts +147 -0
  99. package/threeUtils.d.ts +44 -0
  100. package/threeUtils.js +233 -0
  101. package/threeUtils.ts +271 -0
  102. package/tsconfig.json +39 -0
package/FPScontrol.js ADDED
@@ -0,0 +1,170 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2022-05-04 23:01:36
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2022-06-06 13:32:08
6
+ */
7
+ import { Clock, EventDispatcher, Vector3 } from "three";
8
+ import { Capsule } from "three/examples/jsm/math/Capsule";
9
+ import { Octree } from "three/examples/jsm/math/Octree";
10
+ import { clamp, degToRad } from "three/src/math/MathUtils";
11
+ /**
12
+ * 第一人称控制器
13
+ *
14
+ * @export
15
+ * @class FPScontrol
16
+ * @extends {EventDispatcher}
17
+ */
18
+ export default class FPScontrol extends EventDispatcher {
19
+ canvas;
20
+ constructor(camera, canvas) {
21
+ super();
22
+ // 相机对象
23
+ this.camera = camera;
24
+ this.camera.rotation.order = 'YXZ';
25
+ this.canvas = canvas;
26
+ this.init(canvas);
27
+ }
28
+ // 是否启用
29
+ enable = false;
30
+ GRAVITY = 30; // 重力
31
+ STEPS_PER_FRAME = 5; // 速度
32
+ camera;
33
+ // 世界八叉树对象
34
+ worldOctree = new Octree();
35
+ // 用户自己的碰撞体积
36
+ playerCollider = new Capsule(new Vector3(0, 0.35, 0), new Vector3(0, 1, 0), 0.35);
37
+ // 时钟对象
38
+ clock = new Clock();
39
+ playerVelocity = new Vector3();
40
+ playerDirection = new Vector3();
41
+ playerOnFloor = false;
42
+ mouseTime = 0;
43
+ isMousedown = false;
44
+ keyStates = {};
45
+ init(canvas) {
46
+ this.playerCollider.end.set(0, 1, 0);
47
+ document.addEventListener('keydown', this.keydown);
48
+ document.addEventListener('keyup', this.keyup);
49
+ canvas.addEventListener('pointerdown', this.mousedown);
50
+ document.addEventListener('pointerup', this.mouseup);
51
+ document.body.addEventListener('pointermove', this.mousemove);
52
+ this.enable = true;
53
+ }
54
+ keydown = (event) => {
55
+ this.keyStates[event.code] = true;
56
+ };
57
+ keyup = (event) => {
58
+ this.keyStates[event.code] = false;
59
+ };
60
+ mousedown = () => {
61
+ this.isMousedown = true;
62
+ this.mouseTime = performance.now();
63
+ };
64
+ mouseup = () => {
65
+ this.isMousedown = false;
66
+ };
67
+ mousemove = (event) => {
68
+ if (this.enable && this.isMousedown) {
69
+ this.camera.rotation.y -= event.movementX / 500;
70
+ this.camera.rotation.x -= event.movementY / 500;
71
+ }
72
+ };
73
+ // 设置 八叉树 节点
74
+ fromGraphNode(object3d) {
75
+ this.worldOctree.fromGraphNode(object3d);
76
+ }
77
+ // 获取前进的向量
78
+ getForwardVector = () => {
79
+ this.camera.getWorldDirection(this.playerDirection);
80
+ this.playerDirection.y = 0;
81
+ this.playerDirection.normalize();
82
+ return this.playerDirection;
83
+ };
84
+ // 获取 后退的向量
85
+ getSideVector = () => {
86
+ this.camera.getWorldDirection(this.playerDirection);
87
+ this.playerDirection.y = 0;
88
+ this.playerDirection.normalize();
89
+ this.playerDirection.cross(this.camera.up);
90
+ return this.playerDirection;
91
+ };
92
+ // 玩家移动控制器
93
+ controls = (deltaTime) => {
94
+ const speedDelta = deltaTime * (this.playerOnFloor ? 25 : 8);
95
+ if (this.keyStates['KeyW']) {
96
+ this.playerVelocity.add(this.getForwardVector().multiplyScalar(speedDelta));
97
+ }
98
+ if (this.keyStates['KeyS']) {
99
+ this.playerVelocity.add(this.getForwardVector().multiplyScalar(-speedDelta));
100
+ }
101
+ if (this.keyStates['KeyA']) {
102
+ this.playerVelocity.add(this.getSideVector().multiplyScalar(-speedDelta));
103
+ }
104
+ if (this.keyStates['KeyD']) {
105
+ this.playerVelocity.add(this.getSideVector().multiplyScalar(speedDelta));
106
+ }
107
+ if (this.playerOnFloor) {
108
+ if (this.keyStates['Space']) {
109
+ this.playerVelocity.y = 15;
110
+ }
111
+ }
112
+ };
113
+ // 更新玩家的位置
114
+ updatePlayer = (deltaTime) => {
115
+ let damping = Math.exp(-4 * deltaTime) - 1;
116
+ if (!this.playerOnFloor) {
117
+ this.playerVelocity.y -= this.GRAVITY * deltaTime;
118
+ damping *= 0.1;
119
+ }
120
+ this.playerVelocity.addScaledVector(this.playerVelocity, damping);
121
+ const deltaPosition = this.playerVelocity.clone().multiplyScalar(deltaTime);
122
+ this.playerCollider.translate(deltaPosition);
123
+ this.playerCollisions();
124
+ this.camera.position.copy(this.playerCollider.end);
125
+ this.camera.position.y += 1;
126
+ this.camera.rotation.x = clamp(this.camera.rotation.x, degToRad(-20), degToRad(20));
127
+ };
128
+ // 玩家的碰撞检测
129
+ playerCollisions() {
130
+ const result = this.worldOctree.capsuleIntersect(this.playerCollider);
131
+ this.playerOnFloor = false;
132
+ if (result) {
133
+ this.playerOnFloor = result.normal.y > 0;
134
+ if (!this.playerOnFloor) {
135
+ this.playerVelocity.addScaledVector(result.normal, -result.normal.dot(this.playerVelocity));
136
+ }
137
+ this.playerCollider.translate(result.normal.multiplyScalar(result.depth));
138
+ }
139
+ }
140
+ // 更新控制器的位置
141
+ teleportPlayerIfOob = () => {
142
+ if (this.camera.position.y <= -10) {
143
+ this.playerCollider.start.set(0, 0.35, 0);
144
+ this.playerCollider.end.set(0, 1, 10);
145
+ this.playerCollider.radius = 0.35;
146
+ this.camera.position.copy(this.playerCollider.end);
147
+ // this.camera.position.set(0, 3, 0);
148
+ }
149
+ };
150
+ // 更新
151
+ update() {
152
+ if (this.enable) {
153
+ const deltaTime = Math.min(0.05, this.clock.getDelta()) / this.STEPS_PER_FRAME;
154
+ for (let i = 0; i < this.STEPS_PER_FRAME; i++) {
155
+ this.controls(deltaTime);
156
+ this.updatePlayer(deltaTime);
157
+ this.teleportPlayerIfOob();
158
+ }
159
+ }
160
+ }
161
+ // 销毁事件
162
+ disposer() {
163
+ this.enable = false;
164
+ document.removeEventListener('keydown', this.keydown);
165
+ document.removeEventListener('keyup', this.keyup);
166
+ this.canvas.removeEventListener('pointerdown', this.mousedown);
167
+ document.removeEventListener('pointerup', this.mouseup);
168
+ document.body.removeEventListener('pointermove', this.mousemove);
169
+ }
170
+ }
package/FPScontrol.ts ADDED
@@ -0,0 +1,209 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2022-05-04 23:01:36
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2022-06-06 13:32:08
6
+ */
7
+
8
+ import { Camera, Clock, EventDispatcher, Object3D, Vector3 } from "three";
9
+ import { Capsule } from "three/examples/jsm/math/Capsule";
10
+ import { Octree } from "three/examples/jsm/math/Octree";
11
+ import { clamp, degToRad } from "three/src/math/MathUtils";
12
+
13
+
14
+ /**
15
+ * 第一人称控制器
16
+ *
17
+ * @export
18
+ * @class FPScontrol
19
+ * @extends {EventDispatcher}
20
+ */
21
+ export default class FPScontrol extends EventDispatcher {
22
+
23
+ canvas!: HTMLCanvasElement
24
+
25
+ constructor(camera: Camera, canvas: HTMLCanvasElement) {
26
+ super();
27
+
28
+ // 相机对象
29
+ this.camera = camera;
30
+
31
+ this.camera.rotation.order = 'YXZ';
32
+
33
+ this.canvas = canvas;
34
+
35
+ this.init(canvas);
36
+ }
37
+
38
+ // 是否启用
39
+ enable = false;
40
+
41
+ GRAVITY = 30; // 重力
42
+ STEPS_PER_FRAME = 5; // 速度
43
+
44
+ camera!: Camera;
45
+
46
+ // 世界八叉树对象
47
+ worldOctree = new Octree();
48
+
49
+ // 用户自己的碰撞体积
50
+ playerCollider = new Capsule(new Vector3(0, 0.35, 0), new Vector3(0, 1, 0), 0.35);
51
+
52
+ // 时钟对象
53
+ clock = new Clock();
54
+
55
+ playerVelocity = new Vector3();
56
+ playerDirection = new Vector3();
57
+
58
+ playerOnFloor = false;
59
+ mouseTime = 0;
60
+ isMousedown = false;
61
+ keyStates: { [key: string]: boolean } = {};
62
+
63
+
64
+ init(canvas: HTMLCanvasElement) {
65
+ this.playerCollider.end.set(0, 1, 0);
66
+ document.addEventListener('keydown', this.keydown);
67
+ document.addEventListener('keyup', this.keyup);
68
+ canvas.addEventListener('pointerdown', this.mousedown);
69
+ document.addEventListener('pointerup', this.mouseup);
70
+ document.body.addEventListener('pointermove', this.mousemove);
71
+ this.enable = true;
72
+ }
73
+
74
+
75
+ keydown = (event: KeyboardEvent) => {
76
+ this.keyStates[event.code] = true;
77
+ }
78
+
79
+ keyup = (event: KeyboardEvent) => {
80
+ this.keyStates[event.code] = false;
81
+ }
82
+
83
+ mousedown = () => {
84
+ this.isMousedown = true;
85
+ this.mouseTime = performance.now();
86
+ }
87
+
88
+ mouseup = () => {
89
+ this.isMousedown = false;
90
+ }
91
+
92
+ mousemove = (event: MouseEvent) => {
93
+ if (this.enable && this.isMousedown) {
94
+ this.camera.rotation.y -= event.movementX / 500;
95
+ this.camera.rotation.x -= event.movementY / 500;
96
+
97
+ }
98
+ }
99
+
100
+ // 设置 八叉树 节点
101
+ fromGraphNode(object3d: Object3D) {
102
+ this.worldOctree.fromGraphNode(object3d);
103
+ }
104
+
105
+ // 获取前进的向量
106
+ getForwardVector = () => {
107
+ this.camera.getWorldDirection(this.playerDirection);
108
+ this.playerDirection.y = 0;
109
+ this.playerDirection.normalize();
110
+ return this.playerDirection;
111
+ }
112
+
113
+ // 获取 后退的向量
114
+ getSideVector = () => {
115
+ this.camera.getWorldDirection(this.playerDirection);
116
+ this.playerDirection.y = 0;
117
+ this.playerDirection.normalize();
118
+ this.playerDirection.cross(this.camera.up);
119
+ return this.playerDirection;
120
+ }
121
+
122
+ // 玩家移动控制器
123
+ controls = (deltaTime: number) => {
124
+ const speedDelta = deltaTime * (this.playerOnFloor ? 25 : 8);
125
+ if (this.keyStates['KeyW']) {
126
+ this.playerVelocity.add(this.getForwardVector().multiplyScalar(speedDelta));
127
+ }
128
+ if (this.keyStates['KeyS']) {
129
+ this.playerVelocity.add(this.getForwardVector().multiplyScalar(-speedDelta));
130
+ }
131
+ if (this.keyStates['KeyA']) {
132
+ this.playerVelocity.add(this.getSideVector().multiplyScalar(-speedDelta));
133
+ }
134
+ if (this.keyStates['KeyD']) {
135
+ this.playerVelocity.add(this.getSideVector().multiplyScalar(speedDelta));
136
+ }
137
+
138
+ if (this.playerOnFloor) {
139
+ if (this.keyStates['Space']) {
140
+ this.playerVelocity.y = 15;
141
+ }
142
+ }
143
+
144
+ }
145
+
146
+ // 更新玩家的位置
147
+ updatePlayer = (deltaTime: number) => {
148
+ let damping = Math.exp(-4 * deltaTime) - 1;
149
+ if (!this.playerOnFloor) {
150
+ this.playerVelocity.y -= this.GRAVITY * deltaTime;
151
+ damping *= 0.1;
152
+ }
153
+ this.playerVelocity.addScaledVector(this.playerVelocity, damping);
154
+ const deltaPosition = this.playerVelocity.clone().multiplyScalar(deltaTime);
155
+ this.playerCollider.translate(deltaPosition);
156
+ this.playerCollisions();
157
+ this.camera.position.copy(this.playerCollider.end);
158
+ this.camera.position.y += 1;
159
+ this.camera.rotation.x = clamp(this.camera.rotation.x, degToRad(-20), degToRad(20));
160
+ }
161
+
162
+ // 玩家的碰撞检测
163
+ playerCollisions() {
164
+ const result = this.worldOctree.capsuleIntersect(this.playerCollider);
165
+ this.playerOnFloor = false;
166
+ if (result) {
167
+ this.playerOnFloor = result.normal.y > 0;
168
+ if (!this.playerOnFloor) {
169
+ this.playerVelocity.addScaledVector(result.normal, -result.normal.dot(this.playerVelocity));
170
+
171
+ }
172
+ this.playerCollider.translate(result.normal.multiplyScalar(result.depth));
173
+ }
174
+ }
175
+ // 更新控制器的位置
176
+ teleportPlayerIfOob = () => {
177
+ if (this.camera.position.y <= -10) {
178
+ this.playerCollider.start.set(0, 0.35, 0);
179
+ this.playerCollider.end.set(0, 1, 10);
180
+ this.playerCollider.radius = 0.35;
181
+ this.camera.position.copy(this.playerCollider.end);
182
+ // this.camera.position.set(0, 3, 0);
183
+ }
184
+ }
185
+
186
+ // 更新
187
+ update() {
188
+ if (this.enable) {
189
+ const deltaTime = Math.min(0.05, this.clock.getDelta()) / this.STEPS_PER_FRAME;
190
+ for (let i = 0; i < this.STEPS_PER_FRAME; i++) {
191
+ this.controls(deltaTime);
192
+ this.updatePlayer(deltaTime);
193
+ this.teleportPlayerIfOob();
194
+ }
195
+ }
196
+ }
197
+
198
+ // 销毁事件
199
+ disposer() {
200
+ this.enable = false;
201
+ document.removeEventListener('keydown', this.keydown);
202
+ document.removeEventListener('keyup', this.keyup);
203
+ this.canvas.removeEventListener('pointerdown', this.mousedown);
204
+ document.removeEventListener('pointerup', this.mouseup);
205
+ document.body.removeEventListener('pointermove', this.mousemove);
206
+ }
207
+
208
+
209
+ }
@@ -0,0 +1,10 @@
1
+ import * as THREE from 'three';
2
+ export default class InstancedGroupMesh extends THREE.Mesh {
3
+ isInstancedGroupMesh: boolean;
4
+ count: number;
5
+ meshCollect: Record<string, THREE.Mesh[]>;
6
+ instanceCollect: Record<string, THREE.InstancedMesh>;
7
+ static matrix: THREE.Matrix4;
8
+ constructor(group: THREE.Group, count: number);
9
+ setMatrixAt(index: number, matrix: THREE.Matrix4): void;
10
+ }
@@ -0,0 +1,63 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2023-02-21 09:55:52
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2023-02-26 14:42:21
6
+ */
7
+ import * as THREE from 'three';
8
+ // 模型组转成 实例对象
9
+ export default class InstancedGroupMesh extends THREE.Mesh {
10
+ isInstancedGroupMesh = true;
11
+ count = 0;
12
+ meshCollect = {};
13
+ instanceCollect = {};
14
+ static matrix = new THREE.Matrix4();
15
+ constructor(group, count) {
16
+ super();
17
+ this.count = count;
18
+ const { meshCollect, instanceCollect } = this;
19
+ group.updateMatrixWorld(true);
20
+ // collect all mesh counts, in case there are more than one copy of the same mesh in this group
21
+ group.traverse((obj) => {
22
+ const mesh = obj;
23
+ if (mesh.isMesh) {
24
+ mesh.matrixWorld.decompose(mesh.position, mesh.quaternion, mesh.scale);
25
+ mesh.rotation.setFromQuaternion(mesh.quaternion);
26
+ mesh.updateMatrix();
27
+ // same geometry and same material consider as the same mesh
28
+ const uuid = mesh.geometry.uuid + '/' + mesh.material.uuid;
29
+ if (meshCollect[uuid]) {
30
+ meshCollect[uuid].push(mesh);
31
+ }
32
+ else {
33
+ meshCollect[uuid] = [mesh];
34
+ }
35
+ }
36
+ else {
37
+ obj.position.set(0, 0, 0);
38
+ obj.scale.set(1, 1, 1);
39
+ obj.rotation.set(0, 0, 0);
40
+ }
41
+ });
42
+ // create all instances
43
+ Object.keys(meshCollect).forEach(uuid => {
44
+ const meshes = meshCollect[uuid];
45
+ const mesh = meshes[0];
46
+ const instancedMesh = new THREE.InstancedMesh(mesh.geometry, mesh.material, meshes.length * count);
47
+ instanceCollect[uuid] = instancedMesh;
48
+ this.add(instancedMesh);
49
+ });
50
+ }
51
+ setMatrixAt(index, matrix) {
52
+ Object.keys(this.meshCollect).forEach(uuid => {
53
+ const instancedMesh = this.instanceCollect[uuid];
54
+ const collect = this.meshCollect[uuid];
55
+ collect.forEach((mesh, i) => {
56
+ InstancedGroupMesh.matrix.copy(mesh.matrix);
57
+ InstancedGroupMesh.matrix.premultiply(matrix);
58
+ instancedMesh.setMatrixAt(collect.length * index + i, InstancedGroupMesh.matrix);
59
+ instancedMesh.instanceMatrix.needsUpdate = true;
60
+ });
61
+ });
62
+ }
63
+ }
@@ -0,0 +1,80 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2023-02-21 09:55:52
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2023-02-26 14:42:21
6
+ */
7
+
8
+ import * as THREE from 'three'
9
+
10
+ // 模型组转成 实例对象
11
+ export default class InstancedGroupMesh extends THREE.Mesh {
12
+ isInstancedGroupMesh = true
13
+
14
+ count: number = 0
15
+
16
+ meshCollect: Record<string, THREE.Mesh[]> = {}
17
+
18
+ instanceCollect: Record<string, THREE.InstancedMesh> = {}
19
+
20
+ static matrix = new THREE.Matrix4()
21
+
22
+ constructor(group: THREE.Group, count: number) {
23
+ super()
24
+
25
+ this.count = count
26
+
27
+ const { meshCollect, instanceCollect } = this
28
+
29
+ group.updateMatrixWorld(true);
30
+
31
+ // collect all mesh counts, in case there are more than one copy of the same mesh in this group
32
+ group.traverse((obj) => {
33
+ const mesh = obj as THREE.Mesh
34
+ if (mesh.isMesh) {
35
+
36
+ mesh.matrixWorld.decompose(mesh.position, mesh.quaternion, mesh.scale);
37
+ mesh.rotation.setFromQuaternion(mesh.quaternion);
38
+ mesh.updateMatrix();
39
+
40
+ // same geometry and same material consider as the same mesh
41
+ const uuid = mesh.geometry.uuid + '/' + (mesh.material as THREE.Material).uuid
42
+
43
+ if (meshCollect[uuid]) {
44
+ meshCollect[uuid].push(mesh)
45
+ } else {
46
+ meshCollect[uuid] = [mesh]
47
+ }
48
+ } else {
49
+ obj.position.set(0, 0, 0);
50
+ obj.scale.set(1, 1, 1);
51
+ obj.rotation.set(0, 0, 0);
52
+ }
53
+
54
+ })
55
+
56
+ // create all instances
57
+ Object.keys(meshCollect).forEach(uuid => {
58
+ const meshes = meshCollect[uuid]
59
+ const mesh = meshes[0]
60
+
61
+ const instancedMesh = new THREE.InstancedMesh(mesh.geometry, mesh.material, meshes.length * count)
62
+ instanceCollect[uuid] = instancedMesh
63
+ this.add(instancedMesh)
64
+ })
65
+ }
66
+
67
+ setMatrixAt(index: number, matrix: THREE.Matrix4) {
68
+ Object.keys(this.meshCollect).forEach(uuid => {
69
+ const instancedMesh = this.instanceCollect[uuid]
70
+ const collect = this.meshCollect[uuid]
71
+ collect.forEach((mesh: THREE.Mesh, i: number) => {
72
+ InstancedGroupMesh.matrix.copy(mesh.matrix)
73
+ InstancedGroupMesh.matrix.premultiply(matrix)
74
+
75
+ instancedMesh.setMatrixAt(collect.length * index + i, InstancedGroupMesh.matrix);
76
+ instancedMesh.instanceMatrix.needsUpdate = true;
77
+ })
78
+ })
79
+ }
80
+ }
@@ -0,0 +1,25 @@
1
+ import { Euler, Line, LineBasicMaterial, Object3D, Vector3 } from "three";
2
+ export type Keyframe = {
3
+ position: Vector3;
4
+ scale: Vector3;
5
+ rotation: Euler;
6
+ timeTemp: number;
7
+ };
8
+ export type KeyframeAnimationProps = {
9
+ speedScale?: number;
10
+ object3d: Object3D;
11
+ keyframes: Array<Keyframe>;
12
+ };
13
+ export default class KeyframeAnimation extends Object3D {
14
+ constructor(props: KeyframeAnimationProps);
15
+ speedScale: number;
16
+ object3d: Object3D;
17
+ halperLine: Line<any, LineBasicMaterial>;
18
+ keyframes: Array<Keyframe>;
19
+ setObject3D(object3d: Object3D): void;
20
+ getKeyframe(i: number): Keyframe;
21
+ setKeyframe(i: number, keyframe: Keyframe): void;
22
+ setKeyframes(keyframes: Array<Keyframe>): void;
23
+ update(): void;
24
+ updateMatrix(): void;
25
+ }
@@ -0,0 +1,78 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2023-02-16 00:22:31
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2023-02-16 19:08:55
6
+ */
7
+ import { last } from "lodash";
8
+ import { BufferAttribute, Line, LineBasicMaterial, Object3D } from "three";
9
+ import threeUtils from "./threeUtils";
10
+ // 关键帧动画对象
11
+ export default class KeyframeAnimation extends Object3D {
12
+ constructor(props) {
13
+ super();
14
+ // 速度调整
15
+ this.speedScale = props.speedScale || 1;
16
+ // 设置关键帧对象数组
17
+ this.setKeyframes(props.keyframes);
18
+ // 设置对象
19
+ this.setObject3D(props.object3d);
20
+ }
21
+ // 速度调整
22
+ speedScale = 1;
23
+ // 需要需要移动的对象
24
+ object3d;
25
+ //路径辅助线
26
+ halperLine = new Line(undefined, new LineBasicMaterial({ color: "#f00" }));
27
+ // 关键帧数组
28
+ keyframes = [];
29
+ // 设置需要移动的对象
30
+ setObject3D(object3d) {
31
+ this.object3d = object3d;
32
+ if (threeUtils.isDev) {
33
+ this.children = [object3d, this.halperLine];
34
+ }
35
+ else {
36
+ this.children = [object3d];
37
+ }
38
+ }
39
+ // 获取单个关键帧
40
+ getKeyframe(i) {
41
+ return this.keyframes[i];
42
+ }
43
+ // 设置单个关键帧
44
+ setKeyframe(i, keyframe) {
45
+ this.keyframes[i] = keyframe;
46
+ this.setKeyframes(this.keyframes);
47
+ }
48
+ //设置全部关键帧
49
+ setKeyframes(keyframes) {
50
+ this.keyframes = keyframes;
51
+ const position = [];
52
+ keyframes.map(k => {
53
+ position.push(k.position.x);
54
+ position.push(k.position.y);
55
+ position.push(k.position.z);
56
+ });
57
+ this.halperLine.geometry.setAttribute("position", new BufferAttribute(new Float32Array(position), 3, false));
58
+ }
59
+ // 更具关键帧的信息更新 对象的位置
60
+ update() {
61
+ const { _timeTemp } = threeUtils;
62
+ const maxtimetemp = last(this.keyframes).timeTemp;
63
+ const currentTime = _timeTemp % maxtimetemp;
64
+ const currentKeyframeIndex = this.keyframes.findIndex(k => currentTime < k.timeTemp);
65
+ const startKeyframe = this.keyframes[currentKeyframeIndex - 1];
66
+ const endKeyframe = this.keyframes[currentKeyframeIndex];
67
+ const progress = (currentTime - startKeyframe.timeTemp) / (endKeyframe.timeTemp - startKeyframe.timeTemp);
68
+ this.object3d.position.copy(endKeyframe.position).sub(startKeyframe.position).multiplyScalar(progress).add(startKeyframe.position);
69
+ this.object3d.scale.copy(endKeyframe.scale).sub(startKeyframe.scale).multiplyScalar(progress).add(startKeyframe.scale);
70
+ this.object3d.rotation.set((endKeyframe.rotation.x - startKeyframe.rotation.x) * progress + startKeyframe.rotation.x, (endKeyframe.rotation.y - startKeyframe.rotation.y) * progress + startKeyframe.rotation.y, (endKeyframe.rotation.z - startKeyframe.rotation.z) * progress + startKeyframe.rotation.z);
71
+ this.dispatchEvent({ type: "update" });
72
+ }
73
+ //更新关键帧的实例矩阵
74
+ updateMatrix() {
75
+ this.update();
76
+ super.updateMatrix();
77
+ }
78
+ }