three-base 2.0.134 → 2.0.142

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 (305) hide show
  1. package/DirectionalLight.d.ts +6 -6
  2. package/DirectionalLight.js +68 -68
  3. package/DirectionalLight.ts +70 -0
  4. package/EventMap.d.ts +103 -0
  5. package/EventMap.js +17 -0
  6. package/EventMap.ts +139 -0
  7. package/EventMesh.d.ts +18 -18
  8. package/EventMesh.js +59 -59
  9. package/EventMesh.ts +60 -0
  10. package/ExtrudeMesh.d.ts +112 -112
  11. package/ExtrudeMesh.js +342 -366
  12. package/ExtrudeMesh.ts +553 -0
  13. package/FPScontrol.d.ts +511 -71
  14. package/FPScontrol.js +1799 -505
  15. package/FPScontrol.ts +1855 -0
  16. package/Fire/Fire.d.ts +28 -28
  17. package/Fire/Fire.js +80 -79
  18. package/Fire/Fire.ts +89 -0
  19. package/Fire/{FireGromtry.d.ts → FireGeometry.d.ts} +9 -9
  20. package/Fire/{FireGromtry.js → FireGeometry.js} +40 -40
  21. package/Fire/FireGeometry.ts +40 -0
  22. package/Fire/FireMaterial.d.ts +28 -28
  23. package/Fire/FireMaterial.js +32 -32
  24. package/Fire/FireMaterial.ts +89 -0
  25. package/Fire/index.d.ts +2 -1
  26. package/Fire/index.js +2 -1
  27. package/Fire/index.ts +2 -0
  28. package/GLTFDracoLoader.d.ts +71 -0
  29. package/GLTFDracoLoader.js +266 -0
  30. package/GLTFDracoLoader.ts +430 -0
  31. package/Grass/Grass.d.ts +8 -8
  32. package/Grass/Grass.js +38 -38
  33. package/Grass/Grass.ts +38 -0
  34. package/Grass/index.d.ts +2 -1
  35. package/Grass/index.js +2 -1
  36. package/Grass/index.ts +2 -0
  37. package/Ground1/Ground1.d.ts +10 -11
  38. package/Ground1/Ground1.js +95 -91
  39. package/Ground1/Ground1.ts +114 -0
  40. package/Ground1/index.d.ts +1 -1
  41. package/Ground1/index.js +1 -1
  42. package/Ground1/index.ts +1 -0
  43. package/MeshBase.d.ts +36 -35
  44. package/MeshBase.js +247 -223
  45. package/MeshBase.ts +253 -0
  46. package/Mirror.d.ts +25 -25
  47. package/Mirror.js +143 -139
  48. package/Mirror.ts +203 -0
  49. package/MktMesh/MktMesh.d.ts +291 -0
  50. package/MktMesh/MktMesh.js +1045 -0
  51. package/MktMesh/MktMesh.ts +1075 -0
  52. package/MktMesh/assetUrl.d.ts +35 -0
  53. package/MktMesh/assetUrl.js +69 -0
  54. package/MktMesh/assetUrl.ts +69 -0
  55. package/MktMesh/mktMappingShader.d.ts +12 -0
  56. package/MktMesh/mktMappingShader.js +139 -0
  57. package/MktMesh/mktMappingShader.ts +139 -0
  58. package/MktMesh/mktShader.d.ts +263 -0
  59. package/MktMesh/mktShader.js +1248 -0
  60. package/MktMesh/mktShader.ts +1344 -0
  61. package/MktMesh/panoBitmapTexture.d.ts +25 -0
  62. package/MktMesh/panoBitmapTexture.js +52 -0
  63. package/MktMesh/panoBitmapTexture.ts +54 -0
  64. package/MktMesh/panoSlotBind.d.ts +29 -0
  65. package/MktMesh/panoSlotBind.js +106 -0
  66. package/MktMesh/panoSlotBind.ts +153 -0
  67. package/MktMesh/panoSlotRoster.d.ts +22 -0
  68. package/MktMesh/panoSlotRoster.js +169 -0
  69. package/MktMesh/panoSlotRoster.ts +168 -0
  70. package/MktMesh/panoTileStitcher.d.ts +119 -0
  71. package/MktMesh/panoTileStitcher.js +533 -0
  72. package/MktMesh/panoTileStitcher.ts +616 -0
  73. package/MktMesh/types.d.ts +75 -0
  74. package/MktMesh/types.js +1 -0
  75. package/MktMesh/types.ts +87 -0
  76. package/MktMesh/wallCapTessellate.d.ts +33 -0
  77. package/MktMesh/wallCapTessellate.js +97 -0
  78. package/MktMesh/wallCapTessellate.ts +68 -0
  79. package/PipeMesh/PathGeometry.d.ts +44 -44
  80. package/PipeMesh/PathGeometry.js +307 -300
  81. package/PipeMesh/PathGeometry.ts +343 -0
  82. package/PipeMesh/PathPoint.d.ts +17 -17
  83. package/PipeMesh/PathPoint.js +31 -31
  84. package/PipeMesh/PathPoint.ts +36 -0
  85. package/PipeMesh/PathPointList.d.ts +31 -31
  86. package/PipeMesh/PathPointList.js +209 -208
  87. package/PipeMesh/PathPointList.ts +227 -0
  88. package/PipeMesh/PathTubeGeometry.d.ts +25 -25
  89. package/PipeMesh/PathTubeGeometry.js +130 -130
  90. package/PipeMesh/PathTubeGeometry.ts +146 -0
  91. package/PipeMesh/PipeMesh.d.ts +25 -25
  92. package/PipeMesh/PipeMesh.js +63 -63
  93. package/PipeMesh/PipeMesh.ts +76 -0
  94. package/PipeMesh/index.d.ts +1 -1
  95. package/PipeMesh/index.js +1 -1
  96. package/PipeMesh/index.ts +1 -0
  97. package/PlaneModal1/PlaneModal1.d.ts +34 -31
  98. package/PlaneModal1/PlaneModal1.js +109 -105
  99. package/PlaneModal1/PlaneModal1.ts +138 -0
  100. package/PlaneModal1/index.d.ts +1 -1
  101. package/PlaneModal1/index.js +1 -1
  102. package/PlaneModal1/index.ts +1 -0
  103. package/PlaneText.d.ts +27 -39
  104. package/PlaneText.js +35 -30
  105. package/PlaneText.ts +55 -0
  106. package/PlaneWithHtml.d.ts +13 -11
  107. package/PlaneWithHtml.js +64 -63
  108. package/PlaneWithHtml.ts +70 -0
  109. package/PointLight/PointLight.d.ts +13 -14
  110. package/PointLight/PointLight.js +64 -70
  111. package/PointLight/PointLight.ts +67 -0
  112. package/PointLight/index.d.ts +1 -1
  113. package/PointLight/index.js +1 -1
  114. package/PointLight/index.ts +1 -0
  115. package/README.md +110 -79
  116. package/Sky/Sky.d.ts +9 -9
  117. package/Sky/Sky.js +22 -22
  118. package/Sky/Sky.ts +22 -0
  119. package/Sky/index.d.ts +1 -1
  120. package/Sky/index.js +1 -1
  121. package/Sky/index.ts +1 -0
  122. package/SpotLight.d.ts +6 -6
  123. package/SpotLight.js +72 -72
  124. package/SpotLight.ts +74 -0
  125. package/SpriteModal1/SpriteModal1.d.ts +33 -30
  126. package/SpriteModal1/SpriteModal1.js +116 -110
  127. package/SpriteModal1/SpriteModal1.ts +146 -0
  128. package/SpriteModal1/index.d.ts +1 -1
  129. package/SpriteModal1/index.js +1 -1
  130. package/SpriteModal1/index.ts +1 -0
  131. package/SpriteText.d.ts +46 -45
  132. package/SpriteText.js +176 -163
  133. package/SpriteText.ts +205 -0
  134. package/SpriteText2.d.ts +48 -47
  135. package/SpriteText2.js +223 -198
  136. package/SpriteText2.ts +258 -0
  137. package/SpriteText3.d.ts +86 -0
  138. package/SpriteText3.js +519 -0
  139. package/SpriteText3.ts +599 -0
  140. package/SpriteWithHtml.d.ts +9 -7
  141. package/SpriteWithHtml.js +44 -44
  142. package/SpriteWithHtml.ts +50 -0
  143. package/Text3D/Text3D.d.ts +20 -20
  144. package/Text3D/Text3D.js +58 -62
  145. package/Text3D/Text3D.ts +77 -0
  146. package/Text3D/fontController.d.ts +60 -59
  147. package/Text3D/fontController.js +166 -199
  148. package/Text3D/fontController.ts +209 -0
  149. package/Text3D/index.d.ts +1 -1
  150. package/Text3D/index.js +1 -1
  151. package/Text3D/index.ts +1 -0
  152. package/ThreeBase.d.ts +248 -97
  153. package/ThreeBase.js +1202 -613
  154. package/ThreeBase.ts +1314 -0
  155. package/ThreeMouse.d.ts +54 -40
  156. package/ThreeMouse.js +453 -407
  157. package/ThreeMouse.ts +472 -0
  158. package/Transition.d.ts +45 -40
  159. package/Transition.js +209 -210
  160. package/Transition.ts +242 -0
  161. package/Water/Water.d.ts +5 -5
  162. package/Water/Water.js +44 -26
  163. package/Water/Water.ts +45 -0
  164. package/Water/index.d.ts +2 -0
  165. package/Water/index.js +2 -0
  166. package/Water/index.ts +2 -0
  167. package/WaterFlow/FloatingDuck.d.ts +88 -0
  168. package/WaterFlow/FloatingDuck.js +307 -0
  169. package/WaterFlow/FloatingDuck.ts +445 -0
  170. package/WaterFlow/GPUFluidSimulation.d.ts +56 -0
  171. package/WaterFlow/GPUFluidSimulation.js +785 -0
  172. package/WaterFlow/GPUFluidSimulation.ts +827 -0
  173. package/WaterFlow/ReservoirSystem.d.ts +106 -0
  174. package/WaterFlow/ReservoirSystem.js +621 -0
  175. package/WaterFlow/ReservoirSystem.ts +754 -0
  176. package/WaterFlow/SPHField.d.ts +35 -0
  177. package/WaterFlow/SPHField.js +204 -0
  178. package/WaterFlow/SPHField.ts +228 -0
  179. package/WaterFlow/ScreenSpaceFluidPass.d.ts +69 -0
  180. package/WaterFlow/ScreenSpaceFluidPass.js +736 -0
  181. package/WaterFlow/ScreenSpaceFluidPass.ts +789 -0
  182. package/WaterFlow/ShallowWaterSurface.d.ts +45 -0
  183. package/WaterFlow/ShallowWaterSurface.js +441 -0
  184. package/WaterFlow/ShallowWaterSurface.ts +510 -0
  185. package/WaterFlow/WaterFlow.d.ts +87 -0
  186. package/WaterFlow/WaterFlow.js +171 -0
  187. package/WaterFlow/WaterFlow.ts +219 -0
  188. package/WaterFlow/types.d.ts +161 -0
  189. package/WaterFlow/types.js +1 -0
  190. package/WaterFlow/types.ts +189 -0
  191. package/WaterFlow/waterFlowPass.d.ts +3 -0
  192. package/WaterFlow/waterFlowPass.js +20 -0
  193. package/WaterFlow/waterFlowPass.ts +40 -0
  194. package/collisionOBB.d.ts +42 -0
  195. package/collisionOBB.js +112 -0
  196. package/collisionOBB.ts +108 -0
  197. package/declare.d.ts +23 -165
  198. package/index.d.ts +1 -1
  199. package/index.js +1 -2
  200. package/index.ts +1 -0
  201. package/instanced/InstancedBatch.d.ts +57 -0
  202. package/instanced/InstancedBatch.js +348 -0
  203. package/instanced/InstancedBatch.ts +406 -0
  204. package/instanced/InstancedChild.d.ts +174 -0
  205. package/instanced/InstancedChild.js +264 -0
  206. package/instanced/InstancedChild.ts +327 -0
  207. package/instanced/InstancedGroup.d.ts +43 -0
  208. package/instanced/InstancedGroup.js +126 -0
  209. package/instanced/InstancedGroup.ts +137 -0
  210. package/{InstancedMeshBase.d.ts → instanced/InstancedMeshBase.d.ts} +38 -39
  211. package/{InstancedMeshBase.js → instanced/InstancedMeshBase.js} +282 -293
  212. package/instanced/InstancedMeshBase.ts +292 -0
  213. package/instanced/InstancedTemplate.d.ts +46 -0
  214. package/instanced/InstancedTemplate.js +125 -0
  215. package/instanced/InstancedTemplate.ts +188 -0
  216. package/keyControls.d.ts +30 -0
  217. package/{keyContorls.js → keyControls.js} +101 -98
  218. package/keyControls.ts +107 -0
  219. package/lensflare/LensFlare.d.ts +39 -0
  220. package/lensflare/LensFlare.js +373 -0
  221. package/lensflare/LensFlare.ts +448 -0
  222. package/lensflare/lensflare0.png +0 -0
  223. package/lensflare/lensflare3.png +0 -0
  224. package/lensflare/lensflare_custom.png +0 -0
  225. package/lensflare/lensflare_hex_ghost.png +0 -0
  226. package/lensflare/lensflare_hex_main.png +0 -0
  227. package/package.json +101 -26
  228. package/pass/bloom_pass.d.ts +2 -2
  229. package/pass/bloom_pass.js +188 -101
  230. package/pass/bloom_pass.ts +243 -0
  231. package/pass/cover_pass.d.ts +2 -2
  232. package/pass/cover_pass.js +122 -99
  233. package/pass/cover_pass.ts +182 -0
  234. package/pass/debugDepthState.d.ts +20 -0
  235. package/pass/debugDepthState.js +9 -0
  236. package/pass/debugDepthState.ts +22 -0
  237. package/pass/depthTestBias.d.ts +12 -0
  238. package/pass/depthTestBias.js +12 -0
  239. package/pass/depthTestBias.ts +12 -0
  240. package/pass/effectUserData.d.ts +27 -0
  241. package/pass/effectUserData.js +1 -0
  242. package/pass/effectUserData.ts +46 -0
  243. package/pass/frosted_glass_pass.d.ts +2 -2
  244. package/pass/frosted_glass_pass.js +167 -186
  245. package/pass/frosted_glass_pass.ts +288 -0
  246. package/pass/fsQuad.d.ts +9 -9
  247. package/pass/fsQuad.js +28 -28
  248. package/pass/fsQuad.ts +34 -0
  249. package/pass/glow_pass.d.ts +2 -2
  250. package/pass/glow_pass.js +449 -233
  251. package/pass/glow_pass.ts +654 -0
  252. package/pass/screen_bloom_pass.d.ts +11 -0
  253. package/pass/screen_bloom_pass.js +235 -0
  254. package/pass/screen_bloom_pass.ts +263 -0
  255. package/pass/ssao_pass.d.ts +88 -11
  256. package/pass/ssao_pass.js +802 -288
  257. package/pass/ssao_pass.ts +918 -0
  258. package/pass/stroke_pass.d.ts +2 -2
  259. package/pass/stroke_pass.js +329 -258
  260. package/pass/stroke_pass.ts +638 -0
  261. package/shaders/FXAAShaderMaterial.d.ts +3 -3
  262. package/shaders/FXAAShaderMaterial.js +23 -66
  263. package/shaders/FXAAShaderMaterial.ts +201 -0
  264. package/shaders/baseDepthVisShader.d.ts +11 -0
  265. package/shaders/baseDepthVisShader.js +36 -0
  266. package/shaders/baseDepthVisShader.ts +36 -0
  267. package/shaders/baseTextureToRenderShader.d.ts +2 -2
  268. package/shaders/baseTextureToRenderShader.js +55 -60
  269. package/shaders/baseTextureToRenderShader.ts +232 -0
  270. package/shaders/copyShader.d.ts +3 -3
  271. package/shaders/copyShader.js +13 -14
  272. package/shaders/copyShader.ts +32 -0
  273. package/shaders/debugDepthCompareShader.d.ts +14 -0
  274. package/shaders/debugDepthCompareShader.js +49 -0
  275. package/shaders/debugDepthCompareShader.ts +50 -0
  276. package/shaders/debugDepthJudgeShader.d.ts +18 -0
  277. package/shaders/debugDepthJudgeShader.js +52 -0
  278. package/shaders/debugDepthJudgeShader.ts +54 -0
  279. package/shaders/debugExcludedShader.d.ts +13 -0
  280. package/shaders/debugExcludedShader.js +46 -0
  281. package/shaders/debugExcludedShader.ts +48 -0
  282. package/spriteTextBg.d.ts +1 -0
  283. package/spriteTextBg.js +20 -0
  284. package/spriteTextBg.ts +20 -0
  285. package/threeLoader.d.ts +35 -34
  286. package/threeLoader.js +518 -527
  287. package/threeLoader.ts +525 -0
  288. package/threeUtils.d.ts +53 -52
  289. package/threeUtils.js +329 -330
  290. package/threeUtils.ts +373 -0
  291. package/types.d.ts +2 -0
  292. package/types.js +6 -0
  293. package/types.ts +8 -0
  294. package/ApngTexture.d.ts +0 -13
  295. package/ApngTexture.js +0 -61
  296. package/ApngTextureManage.d.ts +0 -18
  297. package/ApngTextureManage.js +0 -87
  298. package/KeyFrameAnimation.d.ts +0 -25
  299. package/KeyFrameAnimation.js +0 -78
  300. package/keyContorls.d.ts +0 -25
  301. package/lib/draco/draco_decoder.js +0 -34
  302. package/lib/draco/draco_decoder.wasm +0 -0
  303. package/lib/draco/draco_wasm_wrapper.js +0 -117
  304. package/shaders.d.ts +0 -5
  305. package/shaders.js +0 -93
package/FPScontrol.d.ts CHANGED
@@ -1,71 +1,511 @@
1
- import { Camera, Clock, EventDispatcher, Scene, Vector3 } from "three";
2
- import { Capsule } from "three/examples/jsm/math/Capsule";
3
- /** 第一/三人称控制器(6 射线 + 迭代推离,userData.fpsCollision 标记碰撞体) */
4
- export default class FPScontrol extends EventDispatcher {
5
- canvas: HTMLCanvasElement;
6
- /**
7
- * @param camera 相机
8
- * @param canvas canvas 元素
9
- * @param scene 场景,用于射线碰撞检测(会递归检测所有子对象)
10
- */
11
- constructor(camera: Camera, canvas: HTMLCanvasElement, scene: Scene);
12
- enable: boolean;
13
- GRAVITY: number;
14
- STEPS_PER_FRAME: number;
15
- speed: number;
16
- camera: Camera;
17
- inertia: boolean;
18
- scene: Scene;
19
- dev: boolean;
20
- thirdPerson: boolean;
21
- thirdPersonDistance: number;
22
- thirdPersonHeight: number;
23
- private _thirdPersonAngleY;
24
- private _thirdPersonAngleX;
25
- private _prevThirdPerson;
26
- COLLIDE_VOLUME: number;
27
- private readonly PUSH_DISTANCE;
28
- private readonly MAX_ITERATIONS;
29
- private _raycaster;
30
- private _tempVec;
31
- private _tempVec2;
32
- private _tempVec3;
33
- private _tempVec4;
34
- private readonly HORIZONTAL_RAY_DIRECTIONS;
35
- private readonly VERTICAL_DOWN;
36
- private readonly VERTICAL_UP;
37
- private _colliders;
38
- private _getColliders;
39
- playerCollider: Capsule;
40
- clock: Clock;
41
- prePlayerVelocity: Vector3;
42
- playerVelocity: Vector3;
43
- jumping: boolean;
44
- playerDirection: Vector3;
45
- prePlayerOnFloor: boolean;
46
- playerOnFloor: boolean;
47
- mouseTime: number;
48
- isMousedown: boolean;
49
- keyStates: {
50
- [key: string]: boolean;
51
- };
52
- private _debugRayGroup;
53
- private _debugLines;
54
- private _initDebugLines;
55
- private _updateDebugLine;
56
- private _disposeDebugLines;
57
- init(canvas: HTMLCanvasElement): void;
58
- keydown: (event: KeyboardEvent) => void;
59
- keyup: (event: KeyboardEvent) => void;
60
- mousedown: () => void;
61
- mouseup: () => void;
62
- mousemove: (event: MouseEvent) => void;
63
- getForwardVector: () => Vector3;
64
- getSideVector: () => Vector3;
65
- controls: (deltaTime: number) => void;
66
- updatePlayer: (deltaTime: number) => void;
67
- playerCollisions(): void;
68
- teleportPlayerIfOob: () => void;
69
- update(): void;
70
- disposer(): void;
71
- }
1
+ import { Camera, Clock, EventDispatcher, Quaternion, Ray, Raycaster, Scene, Vector3 } from "three";
2
+ import { Capsule } from "three/examples/jsm/math/Capsule";
3
+ import { LineSegments2 } from "three/examples/jsm/lines/LineSegments2.js";
4
+ import type { FPScontrolEventTypeMap } from "./EventMap";
5
+ /** 全局 FPScontrol 实例注册表。
6
+ * InstancedBatch 在「异步创建碰撞体 InstancedMesh」后,通过本表通知所有已创建的 FPScontrol
7
+ * 重新收集碰撞体,确保晚于控制器初始化的实例化碰撞体也能被碰撞射线命中(否则会出现"墙建出来了却穿过去"的时序 bug)。 */
8
+ export declare const fpsControlRegistry: Set<FPScontrol>;
9
+ /**
10
+ * 单条碰撞射线 + 其专属辅助线的封装(皇上 2026-09-06 旨:每一条射线都必须拥有一个
11
+ * 一一对应、且由射线自身数据驱动的辅助线,杜绝「调试线索引与射线索引错位 / 漂移」)。
12
+ * 继承 THREE.Ray(天然持有 worldOrigin=this.origin、worldDir=this.direction),
13
+ * 额外携带:局部定义(localOrigin/localDir)、本帧碰撞 far、专属 debugLine、本帧命中/响应态。
14
+ *
15
+ * ⭐ 2026-09-21 皇上旨「就在 FPScontrol.ts 加 export」:对外导出以便复用。
16
+ * 本类**零业务耦合**(只依赖 three 的 Ray / Vector3 / LineSegments2),拿到别处可直接独立使用,
17
+ * 四步走:`new FpsRay(localOrigin, localDir, debugLine?, isSideRay?)`
18
+ * → `updateWorld(yawQuat, worldPos)`(每帧世界化)
19
+ * → `applyToRaycaster(raycaster)`(注入碰撞检测)
20
+ * → `recordHit(hitPointOrNull, visualFar)`(冻结本帧命中态 + 辅助线起终点)
21
+ * → `syncDebugLine()`(写入几何 + 三态配色:红=命中 / 青=探测余量 / 白末端)。
22
+ * `debugLine` 由调用方自备:一条**只有 1 段**的 `LineSegments2`(几何由
23
+ * `LineSegmentsGeometry.setPositions/setColors` 各给 6 个 float = 起点+终点;
24
+ * 材质照抄 FPScontrol._createDebugLine:LineMaterial + vertexColors + linewidth(px) +
25
+ * depthTest(射线线 true=正常遮挡 / 向量线 false=保持穿透)+ depthWrite:false +
26
+ * transparent:true + toneMapped:false + renderOrder:9999)。
27
+ * 不传 debugLine 也可纯当「带局部定义与命中态的 Ray」用,syncDebugLine 会自动跳过。
28
+ *
29
+ * ⚠️ 副作用提醒(皇上已悉,定案保留):从本模块 import 会执行文件顶层的 three-mesh-bvh 原型补丁
30
+ * (`Mesh.prototype.raycast = acceleratedRaycast`)。若哪天只要这个类、不想要该全局补丁,
31
+ * 需把 FpsRay 搬到独立文件(如 three-base/FpsRay.ts)。
32
+ */
33
+ export declare class FpsRay extends Ray {
34
+ /** 局部定义(随布局冻结,单位就是**世界米**;世界空间 = 跟随 yaw 旋转 + 加玩家位置) */
35
+ readonly localOrigin: Vector3;
36
+ readonly localDir: Vector3;
37
+ /** 本帧碰撞 far(由 FPScontrol 按射线类型注入:水平=horizontalFar,下=downFar,上=upFar) */
38
+ far: number;
39
+ /** 专属辅助线(与射线一一对应;懒初始化,未开调试时为 null) */
40
+ debugLine: LineSegments2 | null;
41
+ /** ⭐ 是否为「侧向射线」(±X 直射线,原 6/7)。用于调试线绘制默认隐藏开关(debugHideSideRays)。
42
+ * 当前「矩形射线法」10 条布局**无侧向射线**,全部 false;若日后加回 ±X 侧向直射线,给那条置 true。
43
+ * 反向水平斜弦 6-9 不是侧向(是 2-5 的反方向探测),保持 false → 调试线可见(皇上要「看到区别」)。 */
44
+ isSideRay: boolean;
45
+ /** 本帧调试态:是否命中 / 是否真触发碰撞响应(供三态配色) */
46
+ hit: boolean;
47
+ responded: boolean;
48
+ /**
49
+ * 本条线的辅助线是否参与正常深度遮挡(= debugLine 材质的 depthTest)。
50
+ * 2026-09-25 皇上旨「射线辅助线应该是正常的遮挡状态」→ 10 条射线线全为 true;
51
+ * 两条回弹向量线按同日定案保持穿透显示(它们不挂在 FpsRay 上)。
52
+ * 挂在同一 Line 上的 `renderOrder:9999` 不再代表「盖住一切」,故把真值记在这里供核对/回归断言。
53
+ */
54
+ depthTestEnabled: boolean;
55
+ /** 辅助线起点(命中记录时按本帧 world origin 冻结,避免迭代间 worldPos 漂移) */
56
+ readonly debugOrigin: Vector3;
57
+ /** 辅助线终点:恒 = origin+direction*visualFar 画满(命中点不参与绘制,命中态看颜色) */
58
+ readonly debugFarPoint: Vector3;
59
+ constructor(localOrigin: Vector3, localDir: Vector3, debugLine?: LineSegments2 | null, isSideRay?: boolean);
60
+ /** 每帧:把局部定义转为世界空间(局部已是米,只需跟随 yaw 旋转 + 加玩家位置) */
61
+ updateWorld(yawQuat: Quaternion, worldPos: Vector3): void;
62
+ /** 把本射线注入射线器(碰撞用) */
63
+ applyToRaycaster(raycaster: Raycaster): void;
64
+ /**
65
+ * 记录本帧命中态 + 冻结辅助线起终点。
66
+ * ⚠️ 辅助线**恒按 visualFar 画满**:命中点不参与绘制。
67
+ * 2026-09-25 皇上两次旨意(先是「下射线一落地就从 1.5 缩到 1.0,看着像射线变短了」,
68
+ * 后是「拾取到物体后辅助线都变短了」)定案:**长度不再兼职表达命中**,
69
+ * 命中态只由颜色指示(红 = 命中 / 亮青 = 未命中)。附带好处:菱形包络恒闭合。
70
+ * ⚠️ 想让线收在命中点是回退这条口径,动之前先问过皇上。
71
+ */
72
+ recordHit(intersetPoint: Vector3 | null, visualFar: number): void;
73
+ /** 把 debugOrigin→debugFarPoint 写入专属辅助线几何 + 三态配色(红=命中 / 青=探测余量 / 白末端) */
74
+ syncDebugLine(): void;
75
+ }
76
+ /**
77
+ * ⭐ 2026-09-26 皇上旨「你把能调节的参数都给我做的滚定输入的输入框,然后一键打印,把参数打印到控制台」
78
+ * —— 一个「参数旋钮」的描述。
79
+ *
80
+ * 为什么要做成一张表,而不是在面板里手写二十个输入框:
81
+ * 面板的输入框和「一键打印」必须列**同一批**旋钮、显示**同一个当前值**。
82
+ * 分头写就必然出现「面板有这个、打印少那个」对不上账(皇上照着控制台抄回去改,抄到的是旧值)。
83
+ * ⇒ 表是唯一数据源:面板按表建行、打印按表出行、`setParamValue` 按表夹范围。
84
+ * 以后加/减旋钮只改 `FPScontrol.PARAM_SPECS` 一处。
85
+ */
86
+ export interface FpsParamSpec {
87
+ /** 分组小标题:面板里同组的排在一起,「一键打印」也按组分段 */
88
+ group: string;
89
+ /** 中文名(面板标签 + 打印都显示这个,皇上看到的就是它) */
90
+ label: string;
91
+ /** FPScontrol 上的字段名;`get`/`set` 缺省时直接读写该字段 */
92
+ key: string;
93
+ min: number;
94
+ max: number;
95
+ /** 滚上一格 / 上下方向键一格的量 */
96
+ step: number;
97
+ /** 小数位:面板与打印统一按它格式化,避免两处显示不一致 */
98
+ digits: number;
99
+ /** 单位后缀("m"、"次"、"px";缺省 = 无量纲) */
100
+ unit?: string;
101
+ /** 一句话:拧了它当场会看见什么变化。面板悬停提示 + 打印都带,皇上抄完直接知道往哪拧 */
102
+ desc: string;
103
+ /** 皇上有旨定下的基线:面板/打印标注「⚠️已冻结」,提示这不是臣随手给的档位 */
104
+ frozen?: boolean;
105
+ /** 特殊读法(字段存法与面板显示口径不一致时用,如取整/换算单位;普通公共数值字段不必写) */
106
+ get?: (fps: FPScontrol) => number;
107
+ /** 特殊写法(如 R 必须走 setHorizontalRayRadius 才能保持菱形闭合) */
108
+ set?: (fps: FPScontrol, v: number) => void;
109
+ }
110
+ /** 第一/三人称控制器(「矩形射线法」10 条射线:4 斜弦 + 0/1 竖向 + 6-9 反向斜弦 + 迭代推离,
111
+ * userData.fpsCollision 标记碰撞体)。详见下方 `_localRayOrigins` 上方的「★矩形射线法★」权威规格块。
112
+ * ⭐ 射线布局 = 矩形射线法 / Rectangle-Ray Method(皇上 2026-09-06 命名,唯一数据源 = _localRayOrigins/_localRayDirs):
113
+ * 0/1 竖向(下/上)+ 2-5 斜弦(菱形,R=1.06,四弦闭合)+ 6-9 反向斜弦(2-5 的反方向、起点 xy 重合、
114
+ * 比 2-5 再低 0.05m —— 皇上 2026-09-26 五旨定案:HORIZ_FWD_RAY_Y = −0.7m、HORIZ_REVERSE_RAY_Y = −0.75m,
115
+ * 即离地 0.8m / 0.75m;此前 0 / −0.5 / −0.7 各版均已作废),
116
+ * 用于反向探测玩家身后墙)。6/7 ±X 侧向与 8-13 共线延长线已于 2026-09-06 精简删除。
117
+ * 以后说「矩形射线法」即可按规格块精确还原(含冻结常量表 / 10 条逐条表 / 局部→世界变换 / 关键不变量)。 */
118
+ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap> {
119
+ canvas: HTMLCanvasElement;
120
+ /**
121
+ * @param camera 相机
122
+ * @param canvas canvas 元素
123
+ * @param scene 场景,用于射线碰撞检测(会递归检测所有子对象)
124
+ */
125
+ constructor(camera: Camera, canvas: HTMLCanvasElement, scene: Scene);
126
+ enable: boolean;
127
+ /**
128
+ * 重力加速度。⭐ 皇上 2026-10-03 旨「重力 固定 10m/s 不需要编辑」⇒ 30 → **10**,
129
+ * 并且从面板旋钮表(PARAM_SPECS)与 meta 右侧表单整条删除,从此不是可调参数。
130
+ * ⚠️ 跳跃顶点 = jumpSpeed²/(2×GRAVITY),滞空时间 = 2×jumpSpeed/GRAVITY ⇒ 重力降到 1/3
131
+ * 等于同一初速度跳得高 3 倍、在空里多待 3 倍(jumpSpeed 的默认值要跟这一点连着看)。
132
+ */
133
+ readonly GRAVITY: number;
134
+ STEPS_PER_FRAME: number;
135
+ speed: number;
136
+ camera: Camera;
137
+ inertia: boolean;
138
+ /** 是否允许跳跃(空格触发)。false 时按空格不跳。默认 true */
139
+ jumpEnabled: boolean;
140
+ /** 跳跃初速度(垂直方向,m/s)。
141
+ * ⚠️ 2026-09-27 治「跳跃翻墙」:原 15(当时重力 30)→ 顶点 3.75m 远超墙高 2m,跳起后胶囊底越过墙顶
142
+ * 造成水平失明窗口,人带着水平速度飞越墙平面、落地在墙外侧被越推越远(探针实测 z=-187)。
143
+ * 定案 8 ⇒ 顶点 1.07m:仍可跳上 0.8m 高台,且 yBottom 恒低于「墙顶 2.0 − 步高 0.1」,
144
+ * 与主循环竖直门配合后失明窗口彻底消失。**顶点**才是防翻墙的那条线,不是初速度本身。
145
+ * ⭐ 2026-10-03 皇上旨「重力固定 10」⇒ 顶点 = jumpSpeed²/20,原 8 会把顶点抬到 3.2m(>墙顶 2m)
146
+ * = 09-27 那个翻墙窗口原地复活,所以按「**实测跳跃弧线不变**」倒推出 **5**(5²/20 = 1.25m 理论值,
147
+ * 实测脚底最高 1.57m 与 8@重力30 同一档;离散积分每帧扣 0.167 + 腾空阻尼,比理论值少约 0.15m)。
148
+ * 代价:同一顶点高度下滞空时间 0.53s → 1.0s(重力变 1/3 的直接后果,也就是皇上要的手感)。
149
+ * 调大此值会重新打开翻墙窗口。 */
150
+ jumpSpeed: number;
151
+ /** 惯性关闭(inertia=false)时,每帧水平速度保留率(×0.85 旧值)。越小停得越快。默认 0.85 */
152
+ inertiaDamp: number;
153
+ scene: Scene;
154
+ dev: boolean;
155
+ devCameraOffset: Vector3;
156
+ thirdPerson: boolean;
157
+ thirdPersonDistance: number;
158
+ thirdPersonHeight: number;
159
+ private _thirdPersonAngleY;
160
+ private _thirdPersonAngleX;
161
+ private _prevThirdPerson;
162
+ /**
163
+ * 单步最大位移(连续碰撞检测用):每帧位移会被切成若干 ≤ 本值的小步,逐步做碰撞检测。
164
+ * ⚠️ 必须明显小于水平包络的可达距离(R=1.06 时沿法线 0.749~1.06m),否则掉帧时一步就跨过墙体。
165
+ * ⚠️ 本值同时决定「单次碰撞需要修正多深」——子步越小,玩家每次陷进墙里越浅,
166
+ * 迭代要走的格数就越少(一格恒 RETREAT_SKIN,总位移 ≈ 该子步的穿透深度),
167
+ * 不会出现「一下子回弹很多」。
168
+ * 0.25 → 0.1:单次最大穿透从 0.25 降到 0.1,回弹量同比变小(子步数相应上调)。
169
+ */
170
+ MAX_STEP_DISTANCE: number;
171
+ /** 位移细分的最大段数(防止极端速度/长卡顿把一帧切成几百步拖垮帧率) */
172
+ MAX_STEP_COUNT: number;
173
+ DOWN_RANGE: number;
174
+ UP_RANGE: number;
175
+ /**
176
+ * 「脚下到底还有没有地面」的深探长度(2026-09-25,仅用于穿地板自救的判据)。
177
+ * 竖向两条射线只够得着 下 (DOWN_RANGE+SKIN)=1.52m / 上 (UP_RANGE+SKIN)=0.32m,
178
+ * 正常跳跃顶点 ≈ jumpSpeed²/(2·GRAVITY) = 5²/20 = 1.25m(实测脚底最高 ≈ 1.5m)
179
+ * → 腾空时脚下射线天然全瞎。
180
+ * 若此时头顶又撞到东西,就分不清
181
+ * 「跳起来顶到天花板」(该往下压)和「穿过地板掉进无底洞」(该顶出来)。
182
+ * 判据:往下再问 VOID_PROBE_DOWN 一段,问得到地面 = 正常腾空/下落,问不到 = 已经穿模。
183
+ * 取 8m ≈ 2 跳多一点;比它更深的地面在 demo 里不存在。
184
+ */
185
+ VOID_PROBE_DOWN: number;
186
+ /**
187
+ * 竖向两条射线的探测余量(2cm)。⚠️ 它**不是**水平参数:水平侧的「离墙多远」全由 R 决定
188
+ * (见上方停位口径),这里只是给「脚底离地 1.5m / 眼离顶 0.3m」两条基准各留一点富余,
189
+ * 避免落地那一帧量到的距离恰好等于基准 → 判据在阈值上抖动。
190
+ * 2026-09-26 皇上旨「把贴墙余量这类可以去掉的参数都去掉」→ 名字里「贴墙」的语义已不存在
191
+ * (水平不再读它),面板格子一并删除,改私有;数值 0.02 一字未动(竖向已冻结)。
192
+ */
193
+ private VERTICAL_SKIN;
194
+ /**
195
+ * ⭐ 皇上 2026-09-06 定案:射线围成的**菱形**(旋转 45° 的正方形)**半对角线 R = 1.06 m**
196
+ * → 外接框 **2.12 × 2.12 m**(皇上原话「横向你也改成 2.12m」+「要正方形不要 X 形状」)。
197
+ *
198
+ * ⭐⭐ 菱形的几何约束:**起点外扩量 a 就是半对角线 R,画长 L = R√2**。
199
+ * 起点 (±a,0,0) + 方向朝内 45° + 长 L → 末端 (a − L/√2, 0, ∓L/√2)
200
+ * 要末端正好落在顶点 (0,0,∓R) 使四弦**首尾闭合**:a = L/√2 = R。
201
+ * ⇒ 起点一旦挪回**玩家中心**(a=0),四弦就从同一点发散 → 变成**X 形状**(皇上否决)。
202
+ * ⇒ 要菱形多大,起点就得外扩多少;两者是同一个数。
203
+ *
204
+ * ⚠️ 臣曾误判:以为起点外扩越大,命中点切向偏移越大、回弹方向越歪。
205
+ * **实测相反**:R=0.5(旧) 平均偏离 17.89°、R=0(中心) 7.88°、**R=1.06 只有 4.20°**(最准)。
206
+ *
207
+ * ⛔⛔ **2026-09-06 19:32 皇上终裁:布局冻结** —— 原话「终于对了,这个布局千万不要改了」。
208
+ * 当日 21:56 再旨删掉 6/7 两条 ±X 侧向射线;2026-09-25 晚否决「均匀放射 N=12」方案、
209
+ * 令回退矩形布局(「我最开始用射线组合的矩形,就是最好的方案」)。
210
+ * **已验收通过,不得再动**(含 R 本身与射线条数)。皇上未发话前,任何调整——
211
+ * 哪怕只是「再调大一点」「再精简一条」——都必须**先请旨**。
212
+ * (几何上要改大小只动 `CHORD_RHOMBUS_R` 一个数,far = R√2 自动跟着闭合。)
213
+ * ⭐ 2026-10-08 皇上旨(明确发话,覆盖本段冻结):默认 R 改 **0.5**、可调范围放宽到 **[0.2, 1.0]**,
214
+ * 见下方 `CHORD_RHOMBUS_R` 默认值、`MIN/MAX_HORIZONTAL_RAY_RADIUS` 与 `PARAM_SPECS` 编辑框。
215
+ */
216
+ /** 菱形半对角线 R(水平射线半径,单位=世界米)。
217
+ * ⭐ 2026-10-08 皇上旨:默认 **0.5**(覆盖 09-06 终裁的 1.06);运行时可写公共字段,
218
+ * 走 setHorizontalRayRadius(r) 调整,clamp 到 [0.2, 1.0](见 MIN/MAX_HORIZONTAL_RAY_RADIUS)。 */
219
+ CHORD_RHOMBUS_R: number;
220
+ /**
221
+ * 6-9 这组「共线反向」射线的起点高度(**世界米**,相对控制器中心;负 = 低于中心)。
222
+ *
223
+ * ⭐ 2026-09-26 皇上五道旨(当日反复,全部记录在此,别再拿任意一版当定案):
224
+ * ①「平行的射线往下移动一点」⇒ 与 2-5 重合(0);②「2 组不要重合,要整体下移」⇒ −0.5;
225
+ * ③「平行射线高度 改成 −0.7」⇒ −0.7;④「按面板打印的那份日志参数设初始默认值」⇒ 回 −0.5;
226
+ * ⑤**定案:两组 = −0.7(2-5)与 −0.75(6-9)**⇒ 本值 **−0.75m**。
227
+ * 站定时眼在脚底以上 1.5m ⇒ 2-5 离地 0.8m、6-9 离地 0.75m,两组只差 5cm(皇上旨「不用间隔的太宽」)。
228
+ * ⚠️ 副作用(皇上已知):两组都从「与眼同高」降到胸口/腰,矮桌、栏杆、地毯边、
229
+ * 低台阶沿都会变成「撞得上的墙」;1.5m 以上只靠 0/1 竖向射线与顶部判定。
230
+ * ⚠️ 本字段有**两处**消费:`_localRayOrigins` 初值 + `setHorizontalRayRadius()`(面板「水平射线框」
231
+ * 滑动条每次拖动都重写 6-9 起点)。只改初值 = 拖一下滑动条就被悄悄改回去,所以两处必须同源。
232
+ * 旧字段存的是「局部单位」(× cv 才是米),2026-09-26 随 cv 一并废除换算,本字段从此就是米数。
233
+ */
234
+ HORIZ_REVERSE_RAY_Y: number;
235
+ /**
236
+ * 2-5 这组斜弦的起点高度(**世界米**,相对控制器中心;负 = 低于中心)。
237
+ *
238
+ * ⭐ 2026-09-26 皇上问「平行线的高度怎么只有一组可以调」—— 因为这一组此前**没有字段**,
239
+ * y=0 直接内联在 `_localRayOrigins[2..5]` 与 `setHorizontalRayRadius()` 两处 = 死值。
240
+ * 现在补成字段 + 旋钮,与 6-9 对称。
241
+ * ⚠️ 同样有**两处**消费(初值 + `setHorizontalRayRadius()`),只改一处就是死旋钮。
242
+ * ⭐ 定案见下方 6-9 那条「五道旨」:本值 **−0.7m**(离地 0.8m)。
243
+ * ⚠️ 这一改**动了 09-06 终裁布局里「2-5 与眼同高」那条**(皇上 09-26 五旨点名要 −0.7);
244
+ * 菱形闭合(R / far=R√2 / 停位距离)与此无关,一字未动。
245
+ */
246
+ HORIZ_FWD_RAY_Y: number;
247
+ /**
248
+ * ⭐ 2026-09-26 皇上旨「2 组平行射线不用间隔的太宽了,你把能调节的参数都做成滚轮输入框」→
249
+ * 6-9 那组的高度从此由皇上自己在面板「参数旋钮」里拧,不再由臣定档位。
250
+ * 参数就是**世界米**(相对控制器中心,负 = 低于中心),字段存什么面板就显示什么。
251
+ * ⚠️ 写入口必须**两处同时写**(`_localRayOrigins[6..9]` + `_rays[6..9].localOrigin`),
252
+ * 少一处 = 拖一下「水平射线框」滑动条就把高度悄悄改回去的死旋钮(皇上多次踩过)。
253
+ * @param worldY 世界米 y 偏移(相对控制器中心)
254
+ */
255
+ setHorizReverseRayY(worldY: number): void;
256
+ /**
257
+ * ⭐ 2026-09-26 皇上旨「平行线的高度怎么只有一组可以调」→ 2-5 那组也做成可拧的,两处写入口同源。
258
+ * @param worldY 世界米 y 偏移(相对控制器中心);皇上 09-26 五旨定案默认 −0.75(2-5 是 −0.7)
259
+ */
260
+ setHorizFwdRayY(worldY: number): void;
261
+ /**
262
+ * 水平射线半径 R 的安全下限(⭐ 2026-09-22 补,皇上滑动条可调后暴露)。
263
+ * **几何事实**:斜弦沿法线的可达距离 = **R**(far = R√2、斜弦 45° → R√2·cos45° = R),
264
+ * 即 R 就是「玩家中心离墙多远开始判定碰撞」的半径。若 R 小于停位需求,人必须**先陷进墙里**
265
+ * 才会被射线检测到,随后每帧被位置修正弹回一点 → 皇上所见「侧撞弹很远」。
266
+ * 探针实测(`tmp/TMP_R_side_effect.mjs`,斜 45° 撞墙角 / 正对单墙同口径):
267
+ * R=0.30 → 停位垂距 **0.2128**(< 胶囊半径 0.35,**明显穿模**)每帧被推 0.040
268
+ * R=0.50 → 0.3541(贴到墙面) 每帧 0.036
269
+ * R=0.60 → 0.4243(勉强 > 胶囊半径)0.034
270
+ * R=0.80 → 0.5448 ✓ / R=1.06 → 0.7247 ✓(每帧修正仅 0.002)
271
+ * ⇒ 取 **0.6**:保证停位垂距 > 玩家胶囊半径(0.35),不再穿模。
272
+ * ⭐ 2026-10-08 皇上旨:下限放宽到 **0.2**、上限收到 **1.0**(编辑框范围 0.2~1.0)。
273
+ * ⚠️ R<0.6 仍会贴墙穿模(R=0.5 贴到墙面、R=0.3 明显穿模),皇上按需拧;下限放开是给窄通道/贴墙演示留余地。
274
+ */
275
+ static readonly MIN_HORIZONTAL_RAY_RADIUS: number;
276
+ /** 水平射线半径 R 的安全上限(⭐ 2026-10-08 皇上旨收到 1.0:再大包络远大于停位需求、回弹精度已够,白烧射程) */
277
+ static readonly MAX_HORIZONTAL_RAY_RADIUS: number;
278
+ /** 水平射线(斜弦)的 far = R√2 —— 四弦首尾闭合的几何解,随 R 一个数走。 */
279
+ private get HORIZONTAL_FAR();
280
+ /**
281
+ * 运行时设置水平射线(菱形)半对角线半径 R(单位:世界米)。
282
+ * 改变后 4 条斜弦起点 x = ±R、4 条反向弦起点 z = ±R **原地更新**
283
+ * (同时更新碰撞检测用的 `_localRayOrigins` 与调试线用的 `_rays[i].localOrigin`,两处保持一致)。
284
+ * ⚠️ R 越大碰撞包络越大、回弹越准(R=1.06 约 4.20°);R 越小包络越小、贴墙余量越小、回弹偏离越大(R=0.5 旧值约 17.89°)。
285
+ * 整束水平射线的大小只由此一个数决定(far = R√2 自动跟随,菱形闭合不破)。
286
+ */
287
+ setHorizontalRayRadius(r: number): void;
288
+ /**
289
+ * ⭐⭐ 2026-09-26 皇上旨「2 组平行射线不用间隔的太宽了,你把能调节的参数都给我做的滚轮输入的输入框,
290
+ * 然后一键打印,把参数打印到控制台」—— 全部可调旋钮的**唯一数据源**。
291
+ *
292
+ * 面板「参数旋钮」分组按本表逐行生成滚轮输入框;「打印参数(全量·控制台)」按本表逐行出行;
293
+ * `setParamValue()` 按本表夹范围并走各自的 `set`(该走 setter 的一个都不能漏,否则又是死旋钮)。
294
+ *
295
+ * ⚠️ 表里 `frozen: true` 的行 = 皇上已下旨定死基线(布局冻结 09-06、竖向 09-25、撞墙清零 09-25),
296
+ * 做成输入框只是让皇上自己能拧,**不代表臣可以改默认值**;默认值一律保持基线原样。
297
+ */
298
+ static readonly PARAM_SPECS: FpsParamSpec[];
299
+ /** 读某个旋钮的当前值(表里没有该 key 时返回 NaN,面板/打印据此跳过,不会崩) */
300
+ getParamValue(key: string): number;
301
+ /**
302
+ * 写某个旋钮:先夹到 [min,max],再走该旋钮自己的 `set`(缺省 = 直接写字段)。
303
+ * @returns 真正落进去的值(夹过之后的),面板拿它回显,避免显示的和实际的两张皮
304
+ */
305
+ setParamValue(key: string, v: number): number;
306
+ /**
307
+ * 辅助线粗细(**像素**)。2026-09-25 皇上旨「辅助线能调粗一点」+ 定案 2px。
308
+ * ⚠️ 这个旋钮只有在 `LineMaterial`(LineSegments2)上才活着:`LineBasicMaterial.linewidth`
309
+ * 被 WebGL 驱动一律钳成 1px,改大完全无效果。像素宽依赖 `resolution` = 画布 CSS 尺寸,
310
+ * 已在 _createDebugLine / _syncDebugLineResolution 里跟上。
311
+ */
312
+ debugLineWidth: number;
313
+ private _accelVec;
314
+ /**
315
+ * 本次调用在**模拟位置**上算出的水平弹出总量(= xsh while 收敛所需的推离长度)。
316
+ * ⭐ 2026-10-02 模拟修正后它不再等于「真实位置陷了多深」—— 真实位置不再先被写进墙里,
317
+ * 它是「这一步要是真走进去、需要弹多少才干净」的模拟读数。
318
+ */
319
+ private _horizHit;
320
+ private _inputDirVec;
321
+ /**
322
+ * 本帧**进碰撞之前**的水平速率(米/秒)。皇上八旨要求「移动向量的长度保持不变」,
323
+ * 而碰撞会把 `playerVelocity.x/z` 清零,所以必须在 updatePlayer 入口先记一份。
324
+ */
325
+ private _preCollideHorizSpeed;
326
+ private _previewRetreat;
327
+ /** 开启预览那一刻的胶囊两端(关闭时整体还原回去) */
328
+ private _obsSavedStart;
329
+ private _obsSavedEnd;
330
+ /** 是否已有可还原的暂存(没进过观察模式就没有,避免构造期赋值把人还原到原点) */
331
+ private _obsHasSave;
332
+ /** 进观察模式(回弹预览 / 单步):记下当前胶囊位置,退出时还原 */
333
+ private _saveObsPos;
334
+ /**
335
+ * 退观察模式:把位置整份还原到进入那一刻,并清掉水平速度。
336
+ * ⚠️ 只清 x/z(竖向已冻结):观察模式刻意不削速度 ⇒ 人攒着一身的行走终端速度
337
+ * (speed=6 ⇒ 37.5m/s ⇒ 每帧 0.62m),还原位置后若不清掉,下一帧又是一个大跨步再次穿墙。
338
+ */
339
+ private _restoreObsPos;
340
+ get previewRetreat(): boolean;
341
+ set previewRetreat(on: boolean);
342
+ /**
343
+ * 每轮迭代沿回弹方向推出去的**固定格长**(米)。
344
+ * ⭐ 皇上 2026-10-07 旨「这个修正距离一看就不正常,应该 1 个单位 1 个单位的修正」⇒ 默认从 xsh
345
+ * 源码 `setLength(0.03)` 那个写死的数**改成 0.01**(一次一格 = 1cm)。
346
+ * ⚠️ 别往下拧太多:体检台 34 现场实测 0.03 / 0.02 / 0.01 判级完全相同(❌0·⚠️20·✅14),
347
+ * 拧到 0.005 才有 6 个 ⚠️ 转 ✅,但同一趟「跳跃 + 冲刺 + 掉帧」现场判 **❌穿墙**
348
+ * —— 格长就是每帧的出水量,格子越小一帧 500 轮预算能挤出去的总量越小,高速顶墙时抵不过往里挤的位移。
349
+ */
350
+ RETREAT_SKIN: number;
351
+ /**
352
+ * dev 视图里是否**隐藏**纯 ±X 射线(6/7 侧向,默认 true = 不画)。
353
+ * ⚠️ 皇上 2026-09-03:这几条从玩家中心左右各伸出,连起来是一根**横贯视野中央**的线,
354
+ * 是全场最扎眼的一根(原话「中间的横着的那根线不要」)。
355
+ * ⚠️⚠️ **只是不画,碰撞射线照常发射**——左右方向的探测全靠 6/7(2026-09-06 起延长线已删),
356
+ * 真删掉侧向墙就要等玩家中心陷进去才被挡住(老 bug 立刻回来)。
357
+ * 想恢复显示(例如排查侧向碰撞):本字段置 false。
358
+ */
359
+ debugHideSideRays: boolean;
360
+ private _tempEuler;
361
+ MAX_ITERATIONS: number;
362
+ /**
363
+ * 一个**物理小帧**里 while 最多走几轮就落地(皇上 2026-10-07 裁决「加一个每小帧轮数上限」)。
364
+ * 默认 500 = 与 `MAX_ITERATIONS` 同档 ⇒ 现状一字不变;拧小才是他要的「一次只修几格、下一小帧再修」。
365
+ * ⭐ 为什么拧格长没用(10-07 实测):常态帧会一直迭代到「8 条射线全部脱开」才落地 ⇒
366
+ * **每次落地量 = 这一小帧往墙里挤进多深**,与一格多远无关(格长 0.03→0.01 判级一字未变)。
367
+ * 一格 = 一轮里每条命中各推的距离 ⇒ 要限制"一次修多少"只能限制**轮数**。
368
+ * ⚠️ 代价(不许瞒):出水量 = 轮数 × 每轮票数 × 格长,默认每帧 2 个小帧。拧到 1 轮 + 1cm 格长 ⇒
369
+ * 一秒最多挤出约 120cm 的量看着够,但高速冲刺顶墙时「这一帧挤进来的」可能比「两小帧推出去的」多
370
+ * ⇒ 越陷越深,格长拧到 0.005 那一档体检台 40 号现场就是这么判 **❌穿墙** 的。
371
+ * 所以默认不动,先让他在线上拧着看手感。
372
+ */
373
+ ROUNDS_PER_SUBSTEP: number;
374
+ private _frameIterBudget;
375
+ private _tempQuat;
376
+ private _raycaster;
377
+ private _probeRaycaster;
378
+ private _tempVec3;
379
+ private _candPos;
380
+ private _corrVec;
381
+ private _tempVec4;
382
+ private _tempVec5;
383
+ /**
384
+ * ⭐⭐ 2026-10-02 皇上旨「在修正位置的时候,我希望的是**模拟修正**,而不是**真实的修正**,
385
+ * 在模拟修正中把最终结果计算好了,再应用到真实的第一人称控制器上面」。
386
+ * 本小步(位移细分的一份)**尚未写进真实位置**的位移:playerCollisions 先在
387
+ * 「真实位置 + 本位移」的**模拟位置**上跑 xsh 的 while,算出干净落点后,
388
+ * 才由那唯一一次 translate 落到真实控制器上(见 playerCollisions 末尾)。
389
+ * ⇒ 真实位置不再「先走进墙里 0.04m,再被弹出来 0.06m」= 一个渲染帧两趟来回甩 = 超级抖。
390
+ * 消费掉(落地)后归零,所以面板那颗直接调 playerCollisions 的按钮不会重复走一步。
391
+ */
392
+ private _subStep;
393
+ /** 模拟算完之后本小步真正写进真实位置的那一份(本步位移 + 最终修正)= 唯一一次 translate */
394
+ private _appliedMove;
395
+ private _wallQuat;
396
+ private _wallMat3;
397
+ private _wallMatrix4;
398
+ private _vertNormal;
399
+ private readonly _localRayOrigins;
400
+ private readonly _localRayDirs;
401
+ private readonly _rays;
402
+ private _colliders;
403
+ private _collidersDirty;
404
+ private _colliderSceneVersion;
405
+ /**
406
+ * 把命中面的法线变换到**世界空间**(含 InstancedMesh 的实例旋转/缩放;
407
+ * 非均匀缩放下必须用 3×3 逆转置,不能直接 applyMatrix3)。
408
+ * ⚠️ 原样返回:不抹平 y、不归一化、不翻向 —— 都由调用方按需处理。
409
+ * ⚠️ 只用 _wallQuat/_wallMatrix4/_wallMat3 这三个专用临时量,可安全嵌套调用其它射线流程。
410
+ * @returns false = 无 face 或法线是零向量(调用方须自行兜底)
411
+ */
412
+ private _transformFaceNormalWorld;
413
+ /**
414
+ * ⭐ 2026-09-27 射线为主方案恢复(与 HEAD 旧射线口径一字不差,内部复用 _transformFaceNormalWorld):
415
+ * 解析一个射线命中点的「墙法线」与「沿法线的垂距」。
416
+ * @param worldPos 玩家中心(本子步候选位置)
417
+ * @param interset 射线命中点
418
+ * @param pushDir 输出「命中点→玩家」的水平推离向量(未归一化;退化时被换成 fallbackDir)
419
+ * @param outN 输出「指向玩家一侧」的单位水平墙面法线(退化时同样有效)
420
+ * @param fallbackDir 射线反方向(已水平归一化),退化(命中点≈玩家中心)时兜底推离方向
421
+ * @returns 垂距 perpDist(≥0)。退化时返回 0(视为最深穿透),并置 _perpDegenerate
422
+ */
423
+ /**
424
+ * 竖向(上/下)射线专用:取命中面**世界法线的 y 分量**(已归一化)。
425
+ * > 0 = 朝上的面(可行走顶面,如 Ground1 地板、箱体顶面)
426
+ * < 0 = 朝下的面(天花板 / 箱体底面)
427
+ * @returns null = 拿不到法线(无 face 或零向量)→ 调用方按「维持旧行为」处理
428
+ */
429
+ private _faceNormalWorldY;
430
+ /**
431
+ * 脚下深探:往下问 VOID_PROBE_DOWN 这么长一段,有没有地面(2026-09-25,穿地板自救用)。
432
+ * @returns true = 下方有地面 → 只是正常腾空/下落,不是穿模
433
+ */
434
+ private _floorBelow;
435
+ /**
436
+ * ⭐⭐ 刷新本帧的**按键输入方向**(水平单位向量)—— 皇上 2026-09-21 旨:
437
+ * 「移动方向」取**按键输入方向**(WASD 相对相机),用于与回弹方向相加。
438
+ * 算法与 `controls()` 里的加速度合成**同源**(同用 getForwardVector / getSideVector),
439
+ * 保证「输入方向」与「实际加速方向」严格一致(不会因两处各写一遍而漂移)。
440
+ * ⚠️ 与 `controls()` 的区别:这里**只要方向**,不乘 speedDelta、不进速度 ——
441
+ * 取的是「玩家意图往哪走」这个纯方向。
442
+ * 无按键 / 前后或左右互相抵消 → 零向量(调用方据此退化为纯回弹方向)。
443
+ * 每物理步调用一次(在 `playerCollisions` 入口)。
444
+ */
445
+ private _refreshInputDir;
446
+ private _getColliders;
447
+ markCollidersDirty(): void;
448
+ /** 通知所有已创建的 FPScontrol 重新收集碰撞体(InstancedBatch 异步创建碰撞 InstancedMesh 后调用) */
449
+ static markAllCollidersDirty(): void;
450
+ /** 复位玩家到指定世界坐标(默认原点),清空速度;第一人称 demo 的"回到起点"用得到 */
451
+ resetPlayer(position?: Vector3): void;
452
+ playerCollider: Capsule;
453
+ clock: Clock;
454
+ prePlayerVelocity: Vector3;
455
+ playerVelocity: Vector3;
456
+ jumping: boolean;
457
+ playerDirection: Vector3;
458
+ prePlayerOnFloor: boolean;
459
+ playerOnFloor: boolean;
460
+ mouseTime: number;
461
+ isMousedown: boolean;
462
+ keyStates: {
463
+ [key: string]: boolean;
464
+ };
465
+ private _debugRayGroup;
466
+ /** 全部调试线的材质(含 10 条射线线),只为统一同步 `resolution`(粗细按像素算,必须知道画布尺寸) */
467
+ private _debugLineMats;
468
+ private _initDebugLines;
469
+ /**
470
+ * 创建一条标准调试线(几何/材质统一,debugLine 复用);不被射线检测命中。
471
+ * @param depthTest 是否参与正常深度遮挡 —— **两种口径按皇上 2026-09-25 逐条定案**:
472
+ * - 射线辅助线(10 条)= **true**:「射线辅助线 / 下射线的辅助线应该是正常的遮挡状态」。
473
+ * 旧值 false + renderOrder:9999 是当年为治 2026-09-03「贴地辅助线被地面挡掉看不见」而定,
474
+ * 代价是穿透一切浮在最前 —— 下射线画满 1.5 后埋进地里那半截被直接画在地板之上,
475
+ * 就是皇上所见「像没开深度测试」。能挡住它们的前提:地面 Ground1 已是不透明且
476
+ * `depthWrite:true`(three-base/Ground1/Ground1.ts:107);哪天地板改回
477
+ * transparent + depthWrite:false,射线线会重新穿地浮出来。
478
+ * - 回弹方向线(黄→白)= **false**:「回弹向量线保持穿透显示」。
479
+ * 它是「本帧要看的向量」,起点在胶囊内部、方向常指着墙里,开遮挡会被自己的身子
480
+ * 或墙面吃掉半截 → 观察目的直接落空,故保持常显在最前。
481
+ */
482
+ private _createDebugLine;
483
+ /** 画布 CSS 宽(LineMaterial 的像素宽按它折算;DOM 缺席时兜 1,绝不喂 NaN/0) */
484
+ private _canvasCssWidth;
485
+ /** 画布 CSS 高,口径同 _canvasCssWidth */
486
+ private _canvasCssHeight;
487
+ /** 把画布当前尺寸同步进所有调试线材质(resize / 改粗细都要走一次) */
488
+ private _syncDebugLineResolution;
489
+ private _disposeDebugLines;
490
+ init(canvas: HTMLCanvasElement): void;
491
+ keydown: (event: KeyboardEvent) => void;
492
+ keyup: (event: KeyboardEvent) => void;
493
+ mousedown: () => void;
494
+ mouseup: () => void;
495
+ mousemove: (event: MouseEvent) => void;
496
+ getForwardVector: () => Vector3;
497
+ getSideVector: () => Vector3;
498
+ controls: (deltaTime: number) => void;
499
+ updatePlayer: (deltaTime: number) => void;
500
+ /**
501
+ * 碰撞检测(完全参考 xsh-react-three FPSControls.tsx 的 computerPosition 方法)
502
+ * @param isFinalStep 是否为位移细分的最后一步:
503
+ * 只有最后一步才记录调试射线数据、分发移动/跳跃落地事件,中间小步只做推离。
504
+ */
505
+ /** 输出一条碰撞日志(唯一出口 = 浏览器控制台;皇上:「日志就是浏览器的控制台」) */
506
+ /** 第一人称碰撞主入口:xsh `computerPosition` 移植的迭代推离主循环。 */
507
+ playerCollisions(isFinalStep?: boolean): void;
508
+ teleportPlayerIfOob: () => void;
509
+ update(): void;
510
+ disposer(): void;
511
+ }