three-base 2.0.142 → 2.0.166

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 (231) hide show
  1. package/DirectionalLight.d.ts +6 -6
  2. package/DirectionalLight.js +68 -68
  3. package/EventMap.d.ts +103 -103
  4. package/EventMap.js +17 -17
  5. package/EventMesh.d.ts +18 -18
  6. package/EventMesh.js +59 -59
  7. package/ExtrudeMesh.d.ts +112 -112
  8. package/ExtrudeMesh.js +342 -342
  9. package/FPScontrol.d.ts +531 -511
  10. package/FPScontrol.js +1866 -1799
  11. package/FPScontrol.ts +1922 -1855
  12. package/Fire/Fire.d.ts +28 -28
  13. package/Fire/Fire.js +80 -80
  14. package/Fire/FireGeometry.d.ts +9 -9
  15. package/Fire/FireGeometry.js +40 -40
  16. package/Fire/FireMaterial.d.ts +28 -28
  17. package/Fire/FireMaterial.js +32 -32
  18. package/Fire/index.d.ts +2 -2
  19. package/Fire/index.js +2 -2
  20. package/GLTFDracoLoader.d.ts +71 -71
  21. package/GLTFDracoLoader.js +266 -266
  22. package/GLTFDracoLoader.ts +1 -1
  23. package/Grass/Grass.d.ts +8 -8
  24. package/Grass/Grass.js +38 -38
  25. package/Grass/index.d.ts +2 -2
  26. package/Grass/index.js +2 -2
  27. package/Ground1/Ground1.d.ts +10 -10
  28. package/Ground1/Ground1.js +71 -71
  29. package/Ground1/index.d.ts +1 -1
  30. package/Ground1/index.js +1 -1
  31. package/MeshBase.d.ts +36 -36
  32. package/MeshBase.js +251 -247
  33. package/MeshBase.ts +6 -2
  34. package/Mirror.d.ts +25 -25
  35. package/Mirror.js +143 -143
  36. package/MktMesh/MktMesh.d.ts +301 -291
  37. package/MktMesh/MktMesh.js +1064 -1045
  38. package/MktMesh/MktMesh.ts +32 -11
  39. package/MktMesh/assetUrl.d.ts +59 -35
  40. package/MktMesh/assetUrl.js +165 -69
  41. package/MktMesh/assetUrl.ts +164 -69
  42. package/MktMesh/mktMappingShader.d.ts +12 -12
  43. package/MktMesh/mktMappingShader.js +138 -138
  44. package/MktMesh/mktMappingShader.ts +139 -139
  45. package/MktMesh/mktShader.d.ts +263 -263
  46. package/MktMesh/mktShader.js +1236 -1236
  47. package/MktMesh/mktShader.ts +1344 -1344
  48. package/MktMesh/panoBitmapTexture.d.ts +25 -25
  49. package/MktMesh/panoBitmapTexture.js +52 -52
  50. package/MktMesh/panoBitmapTexture.ts +54 -54
  51. package/MktMesh/panoSlotBind.d.ts +29 -29
  52. package/MktMesh/panoSlotBind.js +106 -106
  53. package/MktMesh/panoSlotBind.ts +153 -153
  54. package/MktMesh/panoSlotRoster.d.ts +22 -22
  55. package/MktMesh/panoSlotRoster.js +169 -169
  56. package/MktMesh/panoSlotRoster.ts +168 -168
  57. package/MktMesh/panoTileStitcher.d.ts +119 -119
  58. package/MktMesh/panoTileStitcher.js +529 -529
  59. package/MktMesh/panoTileStitcher.ts +616 -616
  60. package/MktMesh/types.d.ts +75 -75
  61. package/MktMesh/types.js +1 -1
  62. package/MktMesh/wallCapTessellate.d.ts +33 -33
  63. package/MktMesh/wallCapTessellate.js +97 -97
  64. package/MktMesh/wallCapTessellate.ts +68 -68
  65. package/PipeMesh/PathGeometry.d.ts +44 -44
  66. package/PipeMesh/PathGeometry.js +307 -307
  67. package/PipeMesh/PathPoint.d.ts +17 -17
  68. package/PipeMesh/PathPoint.js +31 -31
  69. package/PipeMesh/PathPointList.d.ts +31 -31
  70. package/PipeMesh/PathPointList.js +209 -209
  71. package/PipeMesh/PathTubeGeometry.d.ts +25 -25
  72. package/PipeMesh/PathTubeGeometry.js +130 -130
  73. package/PipeMesh/PipeMesh.d.ts +25 -25
  74. package/PipeMesh/PipeMesh.js +63 -63
  75. package/PipeMesh/index.d.ts +1 -1
  76. package/PipeMesh/index.js +1 -1
  77. package/PlaneModal1/PlaneModal1.d.ts +34 -34
  78. package/PlaneModal1/PlaneModal1.js +109 -109
  79. package/PlaneModal1/index.d.ts +1 -1
  80. package/PlaneModal1/index.js +1 -1
  81. package/PlaneText.d.ts +27 -27
  82. package/PlaneText.js +35 -35
  83. package/PlaneWithHtml.d.ts +13 -13
  84. package/PlaneWithHtml.js +66 -64
  85. package/PlaneWithHtml.ts +3 -1
  86. package/PointLight/PointLight.d.ts +13 -13
  87. package/PointLight/PointLight.js +64 -64
  88. package/PointLight/index.d.ts +1 -1
  89. package/PointLight/index.js +1 -1
  90. package/Sky/Sky.d.ts +9 -9
  91. package/Sky/Sky.js +22 -22
  92. package/Sky/index.d.ts +1 -1
  93. package/Sky/index.js +1 -1
  94. package/SpotLight.d.ts +6 -6
  95. package/SpotLight.js +72 -72
  96. package/SpriteModal1/SpriteModal1.d.ts +33 -33
  97. package/SpriteModal1/SpriteModal1.js +116 -116
  98. package/SpriteModal1/index.d.ts +1 -1
  99. package/SpriteModal1/index.js +1 -1
  100. package/SpriteText.d.ts +46 -46
  101. package/SpriteText.js +176 -176
  102. package/SpriteText2.d.ts +48 -48
  103. package/SpriteText2.js +223 -223
  104. package/SpriteText3.d.ts +86 -86
  105. package/SpriteText3.js +517 -517
  106. package/SpriteText3.ts +599 -599
  107. package/SpriteWithHtml.d.ts +9 -9
  108. package/SpriteWithHtml.js +46 -44
  109. package/SpriteWithHtml.ts +3 -1
  110. package/Text3D/Text3D.d.ts +20 -20
  111. package/Text3D/Text3D.js +58 -58
  112. package/Text3D/fontController.d.ts +60 -60
  113. package/Text3D/fontController.js +166 -166
  114. package/Text3D/index.d.ts +1 -1
  115. package/Text3D/index.js +1 -1
  116. package/ThreeBase.d.ts +248 -248
  117. package/ThreeBase.js +1202 -1202
  118. package/ThreeBase.ts +1314 -1314
  119. package/ThreeMouse.d.ts +53 -54
  120. package/ThreeMouse.js +453 -453
  121. package/Transition.d.ts +45 -45
  122. package/Transition.js +209 -209
  123. package/Water/Water.d.ts +5 -5
  124. package/Water/Water.js +44 -44
  125. package/Water/index.d.ts +2 -2
  126. package/Water/index.js +2 -2
  127. package/WaterFlow/FloatingDuck.d.ts +88 -88
  128. package/WaterFlow/FloatingDuck.js +307 -307
  129. package/WaterFlow/FloatingDuck.ts +445 -445
  130. package/WaterFlow/GPUFluidSimulation.d.ts +56 -56
  131. package/WaterFlow/GPUFluidSimulation.js +781 -781
  132. package/WaterFlow/GPUFluidSimulation.ts +827 -827
  133. package/WaterFlow/ReservoirSystem.d.ts +106 -106
  134. package/WaterFlow/ReservoirSystem.js +611 -611
  135. package/WaterFlow/ReservoirSystem.ts +754 -754
  136. package/WaterFlow/SPHField.d.ts +35 -35
  137. package/WaterFlow/SPHField.js +203 -203
  138. package/WaterFlow/SPHField.ts +228 -228
  139. package/WaterFlow/ScreenSpaceFluidPass.d.ts +69 -69
  140. package/WaterFlow/ScreenSpaceFluidPass.js +728 -728
  141. package/WaterFlow/ScreenSpaceFluidPass.ts +789 -789
  142. package/WaterFlow/ShallowWaterSurface.d.ts +45 -45
  143. package/WaterFlow/ShallowWaterSurface.js +438 -438
  144. package/WaterFlow/ShallowWaterSurface.ts +510 -510
  145. package/WaterFlow/WaterFlow.d.ts +87 -87
  146. package/WaterFlow/WaterFlow.js +171 -171
  147. package/WaterFlow/WaterFlow.ts +219 -219
  148. package/WaterFlow/types.d.ts +161 -161
  149. package/WaterFlow/types.js +1 -1
  150. package/WaterFlow/types.ts +189 -189
  151. package/WaterFlow/waterFlowPass.d.ts +3 -3
  152. package/WaterFlow/waterFlowPass.js +20 -20
  153. package/WaterFlow/waterFlowPass.ts +40 -40
  154. package/collisionOBB.d.ts +42 -42
  155. package/collisionOBB.js +112 -112
  156. package/collisionOBB.ts +108 -108
  157. package/declare.d.ts +25 -25
  158. package/index.d.ts +1 -1
  159. package/index.js +1 -1
  160. package/instanced/InstancedBatch.d.ts +57 -57
  161. package/instanced/InstancedBatch.js +348 -348
  162. package/instanced/InstancedBatch.ts +406 -406
  163. package/instanced/InstancedChild.d.ts +174 -174
  164. package/instanced/InstancedChild.js +264 -264
  165. package/instanced/InstancedChild.ts +327 -327
  166. package/instanced/InstancedGroup.d.ts +43 -43
  167. package/instanced/InstancedGroup.js +126 -126
  168. package/instanced/InstancedGroup.ts +137 -137
  169. package/instanced/InstancedMeshBase.d.ts +38 -38
  170. package/instanced/InstancedMeshBase.js +282 -282
  171. package/instanced/InstancedTemplate.d.ts +46 -46
  172. package/instanced/InstancedTemplate.js +125 -125
  173. package/keyControls.d.ts +29 -30
  174. package/keyControls.js +101 -101
  175. package/lensflare/LensFlare.d.ts +39 -39
  176. package/lensflare/LensFlare.js +284 -284
  177. package/package.json +6 -1
  178. package/pass/bloom_pass.d.ts +2 -2
  179. package/pass/bloom_pass.js +174 -174
  180. package/pass/cover_pass.d.ts +2 -2
  181. package/pass/cover_pass.js +108 -108
  182. package/pass/debugDepthState.d.ts +20 -20
  183. package/pass/debugDepthState.js +9 -9
  184. package/pass/debugDepthState.ts +22 -22
  185. package/pass/depthTestBias.d.ts +12 -12
  186. package/pass/depthTestBias.js +12 -12
  187. package/pass/depthTestBias.ts +12 -12
  188. package/pass/effectUserData.d.ts +27 -27
  189. package/pass/effectUserData.js +1 -1
  190. package/pass/effectUserData.ts +46 -46
  191. package/pass/frosted_glass_pass.d.ts +2 -2
  192. package/pass/frosted_glass_pass.js +150 -150
  193. package/pass/fsQuad.d.ts +9 -9
  194. package/pass/fsQuad.js +28 -28
  195. package/pass/glow_pass.d.ts +2 -2
  196. package/pass/glow_pass.js +350 -350
  197. package/pass/screen_bloom_pass.d.ts +11 -11
  198. package/pass/screen_bloom_pass.js +136 -136
  199. package/pass/ssao_pass.d.ts +88 -88
  200. package/pass/ssao_pass.js +799 -799
  201. package/pass/ssao_pass.ts +918 -918
  202. package/pass/stroke_pass.d.ts +2 -2
  203. package/pass/stroke_pass.js +267 -267
  204. package/shaders/FXAAShaderMaterial.d.ts +3 -3
  205. package/shaders/FXAAShaderMaterial.js +20 -20
  206. package/shaders/baseDepthVisShader.d.ts +11 -11
  207. package/shaders/baseDepthVisShader.js +36 -36
  208. package/shaders/baseDepthVisShader.ts +36 -36
  209. package/shaders/baseTextureToRenderShader.d.ts +2 -2
  210. package/shaders/baseTextureToRenderShader.js +19 -19
  211. package/shaders/copyShader.d.ts +3 -3
  212. package/shaders/copyShader.js +13 -13
  213. package/shaders/debugDepthCompareShader.d.ts +14 -14
  214. package/shaders/debugDepthCompareShader.js +49 -49
  215. package/shaders/debugDepthCompareShader.ts +50 -50
  216. package/shaders/debugDepthJudgeShader.d.ts +18 -18
  217. package/shaders/debugDepthJudgeShader.js +52 -52
  218. package/shaders/debugDepthJudgeShader.ts +54 -54
  219. package/shaders/debugExcludedShader.d.ts +13 -13
  220. package/shaders/debugExcludedShader.js +46 -46
  221. package/shaders/debugExcludedShader.ts +48 -48
  222. package/spriteTextBg.d.ts +1 -1
  223. package/spriteTextBg.js +20 -20
  224. package/spriteTextBg.ts +20 -20
  225. package/threeLoader.d.ts +35 -35
  226. package/threeLoader.js +518 -518
  227. package/threeUtils.d.ts +71 -53
  228. package/threeUtils.js +363 -329
  229. package/threeUtils.ts +35 -0
  230. package/types.d.ts +2 -2
  231. package/types.js +6 -6
package/ExtrudeMesh.js CHANGED
@@ -1,342 +1,342 @@
1
- /*
2
- * @Author: xiaosihan
3
- * @Date: 2022-06-08 14:20:52
4
- * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2025-06-25
6
- */
7
- import { clamp, cloneDeep, filter, first, get, isNumber, last } from "lodash";
8
- import { BufferAttribute, BufferGeometry, Matrix4, Mesh, Vector2, Vector3 } from "three";
9
- /**
10
- * 挤出模型
11
- * 此组件适合自动生成 公路 河流山川等 2d 平面上的模型
12
- *
13
- * @export
14
- * @class ExtrudeMesh
15
- * @extends {Mesh<BufferGeometry, Material>}
16
- */
17
- export default class ExtrudeMesh extends Mesh {
18
- // 临时使用的二维顶点对象
19
- static temp1Vector2 = new Vector2();
20
- static temp2Vector2 = new Vector2();
21
- static temp3Vector2 = new Vector2();
22
- // 临时使用的3维顶点对象
23
- static tempVector3 = new Vector3();
24
- static temp1Vector3 = new Vector3();
25
- static temp2Vector3 = new Vector3();
26
- static temp3Vector3 = new Vector3();
27
- // 临时使用的矩阵
28
- static temp1Matrix4 = new Matrix4();
29
- static temp2Matrix4 = new Matrix4();
30
- static temp3Matrix4 = new Matrix4();
31
- constructor(props, material) {
32
- super(undefined, material);
33
- this.updateGeometry(props);
34
- }
35
- //宽度
36
- shapePathWidth = 1;
37
- // 通过 props.paths 和圆角属性 计算出来的 最终路径
38
- pointerWidthRadius = [];
39
- // 通过2个顶点和缩放值计算矩阵
40
- computerMatrix(vector1, vector2, scale) {
41
- ExtrudeMesh.temp1Matrix4.identity();
42
- ExtrudeMesh.temp1Matrix4.multiply(ExtrudeMesh.temp2Matrix4.lookAt(ExtrudeMesh.temp1Vector3.set(vector1[0], vector1[1], vector1[2]), ExtrudeMesh.temp2Vector3.set(vector2[0], vector1[1], vector2[2]), ExtrudeMesh.temp3Vector3.set(0, 1, 0)));
43
- ExtrudeMesh.temp1Matrix4.scale(ExtrudeMesh.temp1Vector3.set(...scale));
44
- return ExtrudeMesh.temp1Matrix4.transpose().toArray();
45
- }
46
- /**
47
- * @计算渐变值 computerGradient([3,2,4], 0.3);
48
- * @渐变区间 values:number[]
49
- * @百分比 percentage:number
50
- */
51
- computerGradient(values, percentage) {
52
- // 过滤有效数字类型
53
- values = filter(values, v => isNumber(v));
54
- // 限定取值范围
55
- let P = clamp(percentage, 0, 1);
56
- let VL = values.length;
57
- for (let i = (VL - 1); i >= 0; i--) {
58
- if (P === (i / (VL - 1))) {
59
- return values[i];
60
- }
61
- else if (P > (i / (VL - 1))) {
62
- P -= (i / (VL - 1));
63
- P *= 1 / ((i + 1) / (VL - 1) - (i / (VL - 1)));
64
- return (values[i + 1] - values[i]) * P + values[i];
65
- }
66
- }
67
- return 0;
68
- }
69
- // 计算圆角路径 并存到 this.pointerWidthRadius 上
70
- computerPointerWidthRadius(paths, closed) {
71
- // 路径小于2个就不执行计算
72
- if (paths.length < 2) {
73
- return;
74
- }
75
- // 路径少于3个闭合路径参数不起作用
76
- if (paths.length < 3) {
77
- closed = false;
78
- }
79
- // 清空圆角路径
80
- this.pointerWidthRadius = [];
81
- paths = cloneDeep(paths);
82
- // 如果是闭合路径的话就头尾相连
83
- if (closed) {
84
- Object.defineProperties(paths, {
85
- [-1]: {
86
- value: last(paths),
87
- configurable: false,
88
- enumerable: false,
89
- writable: false // 此属性的值能否修改
90
- },
91
- [paths.length]: {
92
- value: first(paths),
93
- configurable: false,
94
- enumerable: false,
95
- writable: false // 此属性的值能否修改
96
- }
97
- });
98
- }
99
- paths.map((P, i) => {
100
- const { vector3, radius = 0.1, segments = 0, scale = { x: 1, y: 1 } } = P;
101
- //当前点位置前后都有点时就可以做圆角计算
102
- if (paths[i - 1] && paths[i + 1]) {
103
- // 第一个向量
104
- let v1 = ExtrudeMesh.temp1Vector3
105
- .set(...vector3)
106
- .sub(ExtrudeMesh.tempVector3.set(...paths[i - 1].vector3))
107
- .normalize()
108
- .clone();
109
- // 第二个向量
110
- let v2 = ExtrudeMesh.temp2Vector3
111
- .set(...paths[i + 1].vector3)
112
- .sub(ExtrudeMesh.tempVector3.set(...vector3))
113
- .normalize()
114
- .clone();
115
- // 夹角
116
- let innerAngle = v1.clone().multiplyScalar(-1).angleTo(v2);
117
- // 边长
118
- let sideLength = radius / Math.tan(innerAngle / 2);
119
- // 圆角的起点
120
- let startP = new Vector3(...vector3).sub(v1.clone().multiplyScalar(sideLength));
121
- // 圆角的终点
122
- let endP = new Vector3(...vector3).add(v2.clone().multiplyScalar(sideLength));
123
- // 圆角起点到终点的向量
124
- let StoE = endP.clone().sub(startP);
125
- // 弦长
126
- let chordLength = radius / Math.sin(innerAngle / 2);
127
- // 圆心位置
128
- let circleCenter = v2
129
- .clone()
130
- .add(v1)
131
- .multiplyScalar(0.5)
132
- .sub(v1)
133
- .setLength(chordLength)
134
- .add(ExtrudeMesh.tempVector3.set(...vector3));
135
- //向量2是否在 向量1的左边
136
- let v2Inv1Left = ExtrudeMesh.temp1Vector3
137
- .set(-v1.z, 0, v1.x)
138
- .angleTo(ExtrudeMesh.temp2Vector3.set(v2.x, 0, v2.z))
139
- < (Math.PI / 2);
140
- // XZ平面上的夹角
141
- let innerAngleXZ = ExtrudeMesh.temp1Vector3
142
- .set(v1.x, 0, v1.z)
143
- .angleTo(ExtrudeMesh.temp2Vector3.set(v2.x, 0, v2.z));
144
- // 如果当前点的位置在前后2点的连线上,就不进行分段计算 并且应用上一个点的矩阵
145
- if (innerAngleXZ === 0) {
146
- let { x = 1, y = 1 } = scale;
147
- let lastPointMatrix = last(this.pointerWidthRadius).matrix;
148
- this.pointerWidthRadius.push({
149
- vector3,
150
- matrix: ExtrudeMesh.temp1Matrix4
151
- .identity()
152
- .extractRotation(ExtrudeMesh.temp2Matrix4.set(...lastPointMatrix))
153
- .multiply(ExtrudeMesh.temp3Matrix4
154
- .identity()
155
- .scale(ExtrudeMesh.temp1Vector3.set(1, y, x)))
156
- .transpose()
157
- .toArray()
158
- });
159
- }
160
- else if (segments === 0) { // 分段数为0时不分段 并在前后各加一个点
161
- let { x = 1, y = 1 } = scale;
162
- this.pointerWidthRadius.push({
163
- vector3,
164
- matrix: this.computerMatrix((v2Inv1Left ? circleCenter.toArray() : vector3), (v2Inv1Left ? vector3 : circleCenter.toArray()), [1, y, x / Math.sin(innerAngle / 2)])
165
- });
166
- }
167
- else {
168
- for (let ii = 0; ii <= segments; ii++) {
169
- // 圆角计算的第n个点的角度
170
- let Aa = ii * ((Math.PI - innerAngle) / segments);
171
- //半径对角
172
- let Cc = Math.PI - Aa - (innerAngle / 2);
173
- //圆角分段的弦长
174
- let a = radius * Math.sin(Aa) / Math.sin(Cc);
175
- // 每段圆角的弦长
176
- let StoEvector = StoE.clone().setLength(a).add(startP);
177
- // 当前点的位置
178
- let ridiusP = StoEvector
179
- .clone()
180
- .sub(circleCenter)
181
- .setLength(radius)
182
- .add(circleCenter);
183
- let { x: preX = 1, y: preY = 1 } = get(paths[i - 1], ["scale"]) || {};
184
- let { x: nextX = 1, y: nextY = 1 } = get(paths[i + 1], ["scale"]) || {};
185
- let { x = 1, y = 1 } = scale;
186
- // 缩放值过渡计算
187
- x = this.computerGradient([(preX + x) / 2, x, (x + nextX) / 2], ii / segments);
188
- y = this.computerGradient([(preY + y) / 2, y, (y + nextY) / 2], ii / segments);
189
- // 添加一个带矩阵的点
190
- this.pointerWidthRadius.push({
191
- vector3: ridiusP.toArray(),
192
- matrix: this.computerMatrix((v2Inv1Left ? circleCenter.toArray() : ridiusP.toArray()), (v2Inv1Left ? ridiusP.toArray() : circleCenter.toArray()), [1, y, x])
193
- });
194
- }
195
- }
196
- }
197
- else {
198
- // 最后一个位置
199
- if (i === paths.length - 1) {
200
- // 如果是闭合的话 就把第一个点的位置加入最后后面
201
- if (closed) {
202
- this.pointerWidthRadius.push(first(this.pointerWidthRadius));
203
- }
204
- else {
205
- // 如果路径未闭合并且遍历到最后一个时特殊处理
206
- let lastPoint = last(this.pointerWidthRadius);
207
- // 在没有闭合的情况下添加第一个点的位置
208
- let v = ExtrudeMesh.temp1Vector3
209
- .set(...vector3)
210
- .sub(ExtrudeMesh.temp3Vector3.set(...lastPoint.vector3))
211
- .normalize();
212
- let lookAtPoint = ExtrudeMesh.temp2Vector3
213
- .set(v.z, 0, -v.x)
214
- .add(ExtrudeMesh.temp3Vector3.set(...vector3))
215
- .toArray();
216
- let { x = 1, y = 1 } = scale;
217
- this.pointerWidthRadius.push({
218
- vector3,
219
- matrix: this.computerMatrix(vector3, lookAtPoint, [1, y, x])
220
- });
221
- }
222
- }
223
- else {
224
- let { x = 1, y = 1 } = scale;
225
- // 在没有闭合的情况下添加第一个点的位置
226
- let v2 = ExtrudeMesh.temp1Vector3
227
- .set(...paths[i + 1].vector3)
228
- .sub(ExtrudeMesh.temp2Vector3.set(...vector3))
229
- .normalize();
230
- let lookAtPoint = ExtrudeMesh.temp1Vector3
231
- .set(v2.z, 0, -v2.x)
232
- .add(ExtrudeMesh.temp2Vector3.set(...vector3))
233
- .toArray();
234
- this.pointerWidthRadius.push({
235
- vector3,
236
- matrix: this.computerMatrix(vector3, lookAtPoint, [1, y, x])
237
- });
238
- }
239
- } // else
240
- });
241
- }
242
- // 计算三维路径的总长度
243
- computerPathLength(points) {
244
- let length = 0;
245
- points.map((p, index) => {
246
- if (index < points.length - 1) {
247
- ExtrudeMesh.temp1Vector3.set(...p);
248
- ExtrudeMesh.temp2Vector3.set(...points[index + 1]);
249
- length += ExtrudeMesh.temp1Vector3.distanceTo(ExtrudeMesh.temp2Vector3);
250
- }
251
- });
252
- return length;
253
- }
254
- // 通过一条线段计算挤出模型的各个顶点的位置和 uv坐标
255
- setExtrudeMesh(startP, // 起点位置
256
- startMatrix4, // 起点位置的矩阵
257
- endP, // 终点位置
258
- endMatrix4, // 终点位置的矩阵
259
- uvx, // uv.x 的起始位置
260
- shapePath) {
261
- // 计算二维路径的总长度 作为uv坐标的边长
262
- let shapePathLength = this.computerPathLength(shapePath.map(p => [...p, 0]));
263
- // 挤出长度
264
- let extrudeLength = this.computerPathLength([startP, endP]);
265
- // 网格模型每个点
266
- let geometryPoint = [];
267
- // 网格模型每个点对应的uv坐标
268
- let uvPoint = [];
269
- shapePath.map((P, index) => {
270
- if (index < shapePath.length - 1) {
271
- // 计算出矩形面的4个顶点
272
- let Pa = ExtrudeMesh.tempVector3
273
- .set(0, P[1], -P[0])
274
- .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...startMatrix4))
275
- .add(ExtrudeMesh.temp1Vector3.set(...startP))
276
- .toArray();
277
- let Pb = ExtrudeMesh.tempVector3
278
- .set(0, shapePath[index + 1][1], -shapePath[index + 1][0])
279
- .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...startMatrix4))
280
- .add(ExtrudeMesh.temp1Vector3.set(...startP))
281
- .toArray();
282
- let Pc = ExtrudeMesh.tempVector3
283
- .set(0, shapePath[index + 1][1], -shapePath[index + 1][0])
284
- .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...endMatrix4))
285
- .add(ExtrudeMesh.temp1Vector3.set(...endP))
286
- .toArray();
287
- let Pd = ExtrudeMesh.tempVector3
288
- .set(0, P[1], -P[0])
289
- .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...endMatrix4))
290
- .add(ExtrudeMesh.temp1Vector3.set(...endP))
291
- .toArray();
292
- // 组成矩形的2个三角面
293
- geometryPoint.push(...Pa, ...Pb, ...Pc, ...Pa, ...Pc, ...Pd);
294
- // 计算出矩形面的4个顶点的uv坐标
295
- // 当前位置的 uv.y 位置
296
- let currentUvy = this.computerPathLength([first(shapePath), ...shapePath.slice(0, index + 1)].map(sP => [...sP, 0])) / shapePathLength;
297
- // 下一个坐标的 uv.y 位置
298
- let nextUvy = this.computerPathLength([first(shapePath), ...shapePath.slice(0, index + 2)].map(sP => [...sP, 0])) / shapePathLength;
299
- let Pauv = [uvx / shapePathLength, currentUvy];
300
- let Pbuv = [uvx / shapePathLength, nextUvy];
301
- let Pcuv = [(uvx + extrudeLength) / shapePathLength, nextUvy];
302
- let Pduv = [(uvx + extrudeLength) / shapePathLength, currentUvy];
303
- uvPoint.push(...Pauv, ...Pbuv, ...Pcuv, ...Pauv, ...Pcuv, ...Pduv);
304
- }
305
- });
306
- return { geometryPoint, uvPoint };
307
- }
308
- //设置模型
309
- updateGeometry(props) {
310
- const { paths, shapePath, closed } = props;
311
- this.shapePathWidth = Math.max(...shapePath.map(path => path[0])) - Math.min(...shapePath.map(path => path[0]));
312
- // 计算圆角路径
313
- this.computerPointerWidthRadius(paths, closed);
314
- //网格模型的每个顶点位置
315
- let geometryPoint = [];
316
- // 网格模型每个点对应的uv坐标
317
- let uvPoint = [];
318
- for (let i = 0; i < this.pointerWidthRadius.length - 1; i++) {
319
- let Point1 = this.pointerWidthRadius[i];
320
- let Point2 = this.pointerWidthRadius[i + 1];
321
- let uvx = this.computerPathLength(this.pointerWidthRadius.slice(0, i + 1).map(p => p.vector3));
322
- const { geometryPoint: geo, uvPoint: uv } = this.setExtrudeMesh(Point1.vector3, Point1.matrix, Point2.vector3, Point2.matrix, uvx, shapePath);
323
- // 把挤出的网格模型的顶点收集起来
324
- geometryPoint.push(...geo);
325
- // 把挤出的网格模型顶点的uv坐标收集起来
326
- uvPoint.push(...uv);
327
- }
328
- let geometry = new BufferGeometry();
329
- // 修改模型
330
- let positionArray = new Float32Array(geometryPoint);
331
- let position = new BufferAttribute(positionArray, 3, false);
332
- geometry.setAttribute("position", position);
333
- let uvArray = new Float32Array(uvPoint);
334
- let uv = new BufferAttribute(uvArray, 2, false);
335
- geometry.setAttribute("uv", uv);
336
- // 计算顶点法线
337
- geometry.computeVertexNormals();
338
- this.geometry.dispose();
339
- this.geometry = geometry;
340
- this.dispatchEvent({ type: "loaded" });
341
- }
342
- }
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2022-06-08 14:20:52
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2025-06-25
6
+ */
7
+ import { clamp, cloneDeep, filter, first, get, isNumber, last } from "lodash";
8
+ import { BufferAttribute, BufferGeometry, Matrix4, Mesh, Vector2, Vector3 } from "three";
9
+ /**
10
+ * 挤出模型
11
+ * 此组件适合自动生成 公路 河流山川等 2d 平面上的模型
12
+ *
13
+ * @export
14
+ * @class ExtrudeMesh
15
+ * @extends {Mesh<BufferGeometry, Material>}
16
+ */
17
+ export default class ExtrudeMesh extends Mesh {
18
+ // 临时使用的二维顶点对象
19
+ static temp1Vector2 = new Vector2();
20
+ static temp2Vector2 = new Vector2();
21
+ static temp3Vector2 = new Vector2();
22
+ // 临时使用的3维顶点对象
23
+ static tempVector3 = new Vector3();
24
+ static temp1Vector3 = new Vector3();
25
+ static temp2Vector3 = new Vector3();
26
+ static temp3Vector3 = new Vector3();
27
+ // 临时使用的矩阵
28
+ static temp1Matrix4 = new Matrix4();
29
+ static temp2Matrix4 = new Matrix4();
30
+ static temp3Matrix4 = new Matrix4();
31
+ constructor(props, material) {
32
+ super(undefined, material);
33
+ this.updateGeometry(props);
34
+ }
35
+ //宽度
36
+ shapePathWidth = 1;
37
+ // 通过 props.paths 和圆角属性 计算出来的 最终路径
38
+ pointerWidthRadius = [];
39
+ // 通过2个顶点和缩放值计算矩阵
40
+ computerMatrix(vector1, vector2, scale) {
41
+ ExtrudeMesh.temp1Matrix4.identity();
42
+ ExtrudeMesh.temp1Matrix4.multiply(ExtrudeMesh.temp2Matrix4.lookAt(ExtrudeMesh.temp1Vector3.set(vector1[0], vector1[1], vector1[2]), ExtrudeMesh.temp2Vector3.set(vector2[0], vector1[1], vector2[2]), ExtrudeMesh.temp3Vector3.set(0, 1, 0)));
43
+ ExtrudeMesh.temp1Matrix4.scale(ExtrudeMesh.temp1Vector3.set(...scale));
44
+ return ExtrudeMesh.temp1Matrix4.transpose().toArray();
45
+ }
46
+ /**
47
+ * @计算渐变值 computerGradient([3,2,4], 0.3);
48
+ * @渐变区间 values:number[]
49
+ * @百分比 percentage:number
50
+ */
51
+ computerGradient(values, percentage) {
52
+ // 过滤有效数字类型
53
+ values = filter(values, v => isNumber(v));
54
+ // 限定取值范围
55
+ let P = clamp(percentage, 0, 1);
56
+ let VL = values.length;
57
+ for (let i = (VL - 1); i >= 0; i--) {
58
+ if (P === (i / (VL - 1))) {
59
+ return values[i];
60
+ }
61
+ else if (P > (i / (VL - 1))) {
62
+ P -= (i / (VL - 1));
63
+ P *= 1 / ((i + 1) / (VL - 1) - (i / (VL - 1)));
64
+ return (values[i + 1] - values[i]) * P + values[i];
65
+ }
66
+ }
67
+ return 0;
68
+ }
69
+ // 计算圆角路径 并存到 this.pointerWidthRadius 上
70
+ computerPointerWidthRadius(paths, closed) {
71
+ // 路径小于2个就不执行计算
72
+ if (paths.length < 2) {
73
+ return;
74
+ }
75
+ // 路径少于3个闭合路径参数不起作用
76
+ if (paths.length < 3) {
77
+ closed = false;
78
+ }
79
+ // 清空圆角路径
80
+ this.pointerWidthRadius = [];
81
+ paths = cloneDeep(paths);
82
+ // 如果是闭合路径的话就头尾相连
83
+ if (closed) {
84
+ Object.defineProperties(paths, {
85
+ [-1]: {
86
+ value: last(paths),
87
+ configurable: false, // 此属性能否删除和修改
88
+ enumerable: false, // 此属性能否被遍历
89
+ writable: false // 此属性的值能否修改
90
+ },
91
+ [paths.length]: {
92
+ value: first(paths),
93
+ configurable: false, // 此属性能否删除和修改
94
+ enumerable: false, // 此属性能否被遍历
95
+ writable: false // 此属性的值能否修改
96
+ }
97
+ });
98
+ }
99
+ paths.map((P, i) => {
100
+ const { vector3, radius = 0.1, segments = 0, scale = { x: 1, y: 1 } } = P;
101
+ //当前点位置前后都有点时就可以做圆角计算
102
+ if (paths[i - 1] && paths[i + 1]) {
103
+ // 第一个向量
104
+ let v1 = ExtrudeMesh.temp1Vector3
105
+ .set(...vector3)
106
+ .sub(ExtrudeMesh.tempVector3.set(...paths[i - 1].vector3))
107
+ .normalize()
108
+ .clone();
109
+ // 第二个向量
110
+ let v2 = ExtrudeMesh.temp2Vector3
111
+ .set(...paths[i + 1].vector3)
112
+ .sub(ExtrudeMesh.tempVector3.set(...vector3))
113
+ .normalize()
114
+ .clone();
115
+ // 夹角
116
+ let innerAngle = v1.clone().multiplyScalar(-1).angleTo(v2);
117
+ // 边长
118
+ let sideLength = radius / Math.tan(innerAngle / 2);
119
+ // 圆角的起点
120
+ let startP = new Vector3(...vector3).sub(v1.clone().multiplyScalar(sideLength));
121
+ // 圆角的终点
122
+ let endP = new Vector3(...vector3).add(v2.clone().multiplyScalar(sideLength));
123
+ // 圆角起点到终点的向量
124
+ let StoE = endP.clone().sub(startP);
125
+ // 弦长
126
+ let chordLength = radius / Math.sin(innerAngle / 2);
127
+ // 圆心位置
128
+ let circleCenter = v2
129
+ .clone()
130
+ .add(v1)
131
+ .multiplyScalar(0.5)
132
+ .sub(v1)
133
+ .setLength(chordLength)
134
+ .add(ExtrudeMesh.tempVector3.set(...vector3));
135
+ //向量2是否在 向量1的左边
136
+ let v2Inv1Left = ExtrudeMesh.temp1Vector3
137
+ .set(-v1.z, 0, v1.x)
138
+ .angleTo(ExtrudeMesh.temp2Vector3.set(v2.x, 0, v2.z))
139
+ < (Math.PI / 2);
140
+ // XZ平面上的夹角
141
+ let innerAngleXZ = ExtrudeMesh.temp1Vector3
142
+ .set(v1.x, 0, v1.z)
143
+ .angleTo(ExtrudeMesh.temp2Vector3.set(v2.x, 0, v2.z));
144
+ // 如果当前点的位置在前后2点的连线上,就不进行分段计算 并且应用上一个点的矩阵
145
+ if (innerAngleXZ === 0) {
146
+ let { x = 1, y = 1 } = scale;
147
+ let lastPointMatrix = last(this.pointerWidthRadius).matrix;
148
+ this.pointerWidthRadius.push({
149
+ vector3,
150
+ matrix: ExtrudeMesh.temp1Matrix4
151
+ .identity()
152
+ .extractRotation(ExtrudeMesh.temp2Matrix4.set(...lastPointMatrix))
153
+ .multiply(ExtrudeMesh.temp3Matrix4
154
+ .identity()
155
+ .scale(ExtrudeMesh.temp1Vector3.set(1, y, x)))
156
+ .transpose()
157
+ .toArray()
158
+ });
159
+ }
160
+ else if (segments === 0) { // 分段数为0时不分段 并在前后各加一个点
161
+ let { x = 1, y = 1 } = scale;
162
+ this.pointerWidthRadius.push({
163
+ vector3,
164
+ matrix: this.computerMatrix((v2Inv1Left ? circleCenter.toArray() : vector3), (v2Inv1Left ? vector3 : circleCenter.toArray()), [1, y, x / Math.sin(innerAngle / 2)])
165
+ });
166
+ }
167
+ else {
168
+ for (let ii = 0; ii <= segments; ii++) {
169
+ // 圆角计算的第n个点的角度
170
+ let Aa = ii * ((Math.PI - innerAngle) / segments);
171
+ //半径对角
172
+ let Cc = Math.PI - Aa - (innerAngle / 2);
173
+ //圆角分段的弦长
174
+ let a = radius * Math.sin(Aa) / Math.sin(Cc);
175
+ // 每段圆角的弦长
176
+ let StoEvector = StoE.clone().setLength(a).add(startP);
177
+ // 当前点的位置
178
+ let ridiusP = StoEvector
179
+ .clone()
180
+ .sub(circleCenter)
181
+ .setLength(radius)
182
+ .add(circleCenter);
183
+ let { x: preX = 1, y: preY = 1 } = get(paths[i - 1], ["scale"]) || {};
184
+ let { x: nextX = 1, y: nextY = 1 } = get(paths[i + 1], ["scale"]) || {};
185
+ let { x = 1, y = 1 } = scale;
186
+ // 缩放值过渡计算
187
+ x = this.computerGradient([(preX + x) / 2, x, (x + nextX) / 2], ii / segments);
188
+ y = this.computerGradient([(preY + y) / 2, y, (y + nextY) / 2], ii / segments);
189
+ // 添加一个带矩阵的点
190
+ this.pointerWidthRadius.push({
191
+ vector3: ridiusP.toArray(),
192
+ matrix: this.computerMatrix((v2Inv1Left ? circleCenter.toArray() : ridiusP.toArray()), (v2Inv1Left ? ridiusP.toArray() : circleCenter.toArray()), [1, y, x])
193
+ });
194
+ }
195
+ }
196
+ }
197
+ else {
198
+ // 最后一个位置
199
+ if (i === paths.length - 1) {
200
+ // 如果是闭合的话 就把第一个点的位置加入最后后面
201
+ if (closed) {
202
+ this.pointerWidthRadius.push(first(this.pointerWidthRadius));
203
+ }
204
+ else {
205
+ // 如果路径未闭合并且遍历到最后一个时特殊处理
206
+ let lastPoint = last(this.pointerWidthRadius);
207
+ // 在没有闭合的情况下添加第一个点的位置
208
+ let v = ExtrudeMesh.temp1Vector3
209
+ .set(...vector3)
210
+ .sub(ExtrudeMesh.temp3Vector3.set(...lastPoint.vector3))
211
+ .normalize();
212
+ let lookAtPoint = ExtrudeMesh.temp2Vector3
213
+ .set(v.z, 0, -v.x)
214
+ .add(ExtrudeMesh.temp3Vector3.set(...vector3))
215
+ .toArray();
216
+ let { x = 1, y = 1 } = scale;
217
+ this.pointerWidthRadius.push({
218
+ vector3,
219
+ matrix: this.computerMatrix(vector3, lookAtPoint, [1, y, x])
220
+ });
221
+ }
222
+ }
223
+ else {
224
+ let { x = 1, y = 1 } = scale;
225
+ // 在没有闭合的情况下添加第一个点的位置
226
+ let v2 = ExtrudeMesh.temp1Vector3
227
+ .set(...paths[i + 1].vector3)
228
+ .sub(ExtrudeMesh.temp2Vector3.set(...vector3))
229
+ .normalize();
230
+ let lookAtPoint = ExtrudeMesh.temp1Vector3
231
+ .set(v2.z, 0, -v2.x)
232
+ .add(ExtrudeMesh.temp2Vector3.set(...vector3))
233
+ .toArray();
234
+ this.pointerWidthRadius.push({
235
+ vector3,
236
+ matrix: this.computerMatrix(vector3, lookAtPoint, [1, y, x])
237
+ });
238
+ }
239
+ } // else
240
+ });
241
+ }
242
+ // 计算三维路径的总长度
243
+ computerPathLength(points) {
244
+ let length = 0;
245
+ points.map((p, index) => {
246
+ if (index < points.length - 1) {
247
+ ExtrudeMesh.temp1Vector3.set(...p);
248
+ ExtrudeMesh.temp2Vector3.set(...points[index + 1]);
249
+ length += ExtrudeMesh.temp1Vector3.distanceTo(ExtrudeMesh.temp2Vector3);
250
+ }
251
+ });
252
+ return length;
253
+ }
254
+ // 通过一条线段计算挤出模型的各个顶点的位置和 uv坐标
255
+ setExtrudeMesh(startP, // 起点位置
256
+ startMatrix4, // 起点位置的矩阵
257
+ endP, // 终点位置
258
+ endMatrix4, // 终点位置的矩阵
259
+ uvx, // uv.x 的起始位置
260
+ shapePath) {
261
+ // 计算二维路径的总长度 作为uv坐标的边长
262
+ let shapePathLength = this.computerPathLength(shapePath.map(p => [...p, 0]));
263
+ // 挤出长度
264
+ let extrudeLength = this.computerPathLength([startP, endP]);
265
+ // 网格模型每个点
266
+ let geometryPoint = [];
267
+ // 网格模型每个点对应的uv坐标
268
+ let uvPoint = [];
269
+ shapePath.map((P, index) => {
270
+ if (index < shapePath.length - 1) {
271
+ // 计算出矩形面的4个顶点
272
+ let Pa = ExtrudeMesh.tempVector3
273
+ .set(0, P[1], -P[0])
274
+ .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...startMatrix4))
275
+ .add(ExtrudeMesh.temp1Vector3.set(...startP))
276
+ .toArray();
277
+ let Pb = ExtrudeMesh.tempVector3
278
+ .set(0, shapePath[index + 1][1], -shapePath[index + 1][0])
279
+ .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...startMatrix4))
280
+ .add(ExtrudeMesh.temp1Vector3.set(...startP))
281
+ .toArray();
282
+ let Pc = ExtrudeMesh.tempVector3
283
+ .set(0, shapePath[index + 1][1], -shapePath[index + 1][0])
284
+ .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...endMatrix4))
285
+ .add(ExtrudeMesh.temp1Vector3.set(...endP))
286
+ .toArray();
287
+ let Pd = ExtrudeMesh.tempVector3
288
+ .set(0, P[1], -P[0])
289
+ .applyMatrix4(ExtrudeMesh.temp1Matrix4.set(...endMatrix4))
290
+ .add(ExtrudeMesh.temp1Vector3.set(...endP))
291
+ .toArray();
292
+ // 组成矩形的2个三角面
293
+ geometryPoint.push(...Pa, ...Pb, ...Pc, ...Pa, ...Pc, ...Pd);
294
+ // 计算出矩形面的4个顶点的uv坐标
295
+ // 当前位置的 uv.y 位置
296
+ let currentUvy = this.computerPathLength([first(shapePath), ...shapePath.slice(0, index + 1)].map(sP => [...sP, 0])) / shapePathLength;
297
+ // 下一个坐标的 uv.y 位置
298
+ let nextUvy = this.computerPathLength([first(shapePath), ...shapePath.slice(0, index + 2)].map(sP => [...sP, 0])) / shapePathLength;
299
+ let Pauv = [uvx / shapePathLength, currentUvy];
300
+ let Pbuv = [uvx / shapePathLength, nextUvy];
301
+ let Pcuv = [(uvx + extrudeLength) / shapePathLength, nextUvy];
302
+ let Pduv = [(uvx + extrudeLength) / shapePathLength, currentUvy];
303
+ uvPoint.push(...Pauv, ...Pbuv, ...Pcuv, ...Pauv, ...Pcuv, ...Pduv);
304
+ }
305
+ });
306
+ return { geometryPoint, uvPoint };
307
+ }
308
+ //设置模型
309
+ updateGeometry(props) {
310
+ const { paths, shapePath, closed } = props;
311
+ this.shapePathWidth = Math.max(...shapePath.map(path => path[0])) - Math.min(...shapePath.map(path => path[0]));
312
+ // 计算圆角路径
313
+ this.computerPointerWidthRadius(paths, closed);
314
+ //网格模型的每个顶点位置
315
+ let geometryPoint = [];
316
+ // 网格模型每个点对应的uv坐标
317
+ let uvPoint = [];
318
+ for (let i = 0; i < this.pointerWidthRadius.length - 1; i++) {
319
+ let Point1 = this.pointerWidthRadius[i];
320
+ let Point2 = this.pointerWidthRadius[i + 1];
321
+ let uvx = this.computerPathLength(this.pointerWidthRadius.slice(0, i + 1).map(p => p.vector3));
322
+ const { geometryPoint: geo, uvPoint: uv } = this.setExtrudeMesh(Point1.vector3, Point1.matrix, Point2.vector3, Point2.matrix, uvx, shapePath);
323
+ // 把挤出的网格模型的顶点收集起来
324
+ geometryPoint.push(...geo);
325
+ // 把挤出的网格模型顶点的uv坐标收集起来
326
+ uvPoint.push(...uv);
327
+ }
328
+ let geometry = new BufferGeometry();
329
+ // 修改模型
330
+ let positionArray = new Float32Array(geometryPoint);
331
+ let position = new BufferAttribute(positionArray, 3, false);
332
+ geometry.setAttribute("position", position);
333
+ let uvArray = new Float32Array(uvPoint);
334
+ let uv = new BufferAttribute(uvArray, 2, false);
335
+ geometry.setAttribute("uv", uv);
336
+ // 计算顶点法线
337
+ geometry.computeVertexNormals();
338
+ this.geometry.dispose();
339
+ this.geometry = geometry;
340
+ this.dispatchEvent({ type: "loaded" });
341
+ }
342
+ }