three-base 2.0.169 → 2.0.172
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.
- package/FPScontrol.d.ts +41 -7
- package/FPScontrol.js +232 -155
- package/FPScontrol.ts +129 -55
- package/Ground1/Ground1.js +6 -6
- package/Ground1/Ground1.ts +6 -6
- package/MktMesh/MktMesh.d.ts +5 -1
- package/MktMesh/MktMesh.js +16 -6
- package/MktMesh/MktMesh.ts +16 -6
- package/MktMesh/types.d.ts +5 -1
- package/MktMesh/types.ts +5 -1
- package/ThreeBase.d.ts +2 -11
- package/ThreeBase.js +14 -26
- package/ThreeBase.ts +14 -26
- package/WaterFlow/WaterFlow.d.ts +1 -1
- package/WaterFlow/WaterFlow.js +1 -1
- package/WaterFlow/WaterFlow.ts +1 -1
- package/package.json +1 -1
- package/pass/bloom_pass.js +7 -14
- package/pass/bloom_pass.ts +7 -16
- package/pass/cover_pass.js +7 -15
- package/pass/cover_pass.ts +7 -17
- package/pass/debugDepthState.d.ts +2 -2
- package/pass/debugDepthState.ts +2 -2
- package/pass/glow_pass.js +8 -16
- package/pass/glow_pass.ts +8 -18
- package/pass/ssao_pass.d.ts +13 -44
- package/pass/ssao_pass.js +60 -78
- package/pass/ssao_pass.ts +74 -88
- package/pass/stroke_pass.js +10 -16
- package/pass/stroke_pass.ts +10 -18
- package/shaders/baseDepthVisShader.d.ts +1 -1
- package/shaders/baseDepthVisShader.js +1 -1
- package/shaders/baseDepthVisShader.ts +1 -1
- package/shaders/debugDepthCompareShader.d.ts +1 -1
- package/shaders/debugDepthCompareShader.js +1 -1
- package/shaders/debugDepthCompareShader.ts +1 -1
- package/shaders/debugExcludedShader.d.ts +6 -4
- package/shaders/debugExcludedShader.js +6 -4
- package/shaders/debugExcludedShader.ts +6 -4
package/FPScontrol.ts
CHANGED
|
@@ -305,17 +305,19 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
305
305
|
// far = R√2。菱形几何一个数没变(R=1.06 → 外接框 2.12×2.12、斜弦 45°、首尾闭合),
|
|
306
306
|
// 只是不再经过「局部单位」这道换算。竖向的 2cm 探测余量见 `VERTICAL_SKIN`。
|
|
307
307
|
//
|
|
308
|
-
// 【停位口径(现行唯一,皇上 2026-
|
|
309
|
-
//
|
|
310
|
-
// 减去当前垂距 = deficit
|
|
311
|
-
//
|
|
308
|
+
// 【停位口径(现行唯一,皇上 2026-10-11 A 档改判 = 「解析贴合 + 只削法向速度」)】
|
|
309
|
+
// 射线在 far 内命中 = 碰撞;「还差多远才脱开」= 菱形沿墙法线的可达距离
|
|
310
|
+
// reach = R·max(|n·右|, |n·前|) ∈ [R/√2, R] 减去当前垂距 = deficit,取全轮**最大**者当读数;
|
|
311
|
+
// 位置修正沿该面法线一格一格推,每格 = min(RETREAT_SKIN, deficit) ⇒ 大欠距仍走整格,
|
|
312
|
+
// **收尾那一格按欠距截短** ⇒ 落点正好贴在包络边上(旧写法最后一格也推满 1cm → 过冲 → 来回甩)。
|
|
313
|
+
// 速度只削「往墙里」那一份(v −(v·n)n),切向保留 ⇒ 贴墙能滑,撞墙不再「加速→清零」锯齿。
|
|
312
314
|
// ⇒ 停位仍只由 **R** 一个数决定(R=1.06 → 沿法线 0.749~1.06m);胶囊半径 0.35 ⇒ 身体与墙之间
|
|
313
315
|
// 还留 0.40~0.71m 空气隙,这是皇上 2026-09-06 终裁布局自带、且亲眼验收过的量,不要当 bug 修。
|
|
314
316
|
/**
|
|
315
317
|
* 单步最大位移(连续碰撞检测用):每帧位移会被切成若干 ≤ 本值的小步,逐步做碰撞检测。
|
|
316
318
|
* ⚠️ 必须明显小于水平包络的可达距离(R=1.06 时沿法线 0.749~1.06m),否则掉帧时一步就跨过墙体。
|
|
317
319
|
* ⚠️ 本值同时决定「单次碰撞需要修正多深」——子步越小,玩家每次陷进墙里越浅,
|
|
318
|
-
*
|
|
320
|
+
* 迭代要走的格数就越少(一格 ≤ RETREAT_SKIN,总位移 ≈ 该子步的穿透深度),
|
|
319
321
|
* 不会出现「一下子回弹很多」。
|
|
320
322
|
* 0.25 → 0.1:单次最大穿透从 0.25 降到 0.1,回弹量同比变小(子步数相应上调)。
|
|
321
323
|
*/
|
|
@@ -456,6 +458,12 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
456
458
|
* ⇒ 取 **0.6**:保证停位垂距 > 玩家胶囊半径(0.35),不再穿模。
|
|
457
459
|
* ⭐ 2026-10-08 皇上旨:下限放宽到 **0.2**、上限收到 **1.0**(编辑框范围 0.2~1.0)。
|
|
458
460
|
* ⚠️ R<0.6 仍会贴墙穿模(R=0.5 贴到墙面、R=0.3 明显穿模),皇上按需拧;下限放开是给窄通道/贴墙演示留余地。
|
|
461
|
+
* ⭐ 2026-10-11 A 档复核(tmp→test/fpsCollideFit.test.ts,正对 1m 墙、胶囊半径 0.35):
|
|
462
|
+
* 停位现在**逐位等于 R**(眼停在面前 R 处 ⇒ 身体入墙深度 = 0.35 − R,一条直线):
|
|
463
|
+
* R=0.20 → 入墙 **0.1500m** R=0.30 → **0.0500m** R=0.35 → **0.0000m**
|
|
464
|
+
* R=0.50 / 0.60 / 1.00 → **0.0000m**(身体不出面)
|
|
465
|
+
* ⇒ 抖不抖与 R 无关(A 档后全档抖动 0.0000m);R<0.35 只剩「身体陷进墙多少」这一件事,
|
|
466
|
+
* 皇上 10-11 定「旋钮不动,只把数字写明」⇒ 要真焊死得改这里的下限,别在推离公式里偷偷加夹取。
|
|
459
467
|
*/
|
|
460
468
|
public static readonly MIN_HORIZONTAL_RAY_RADIUS: number = 0.2;
|
|
461
469
|
/** 水平射线半径 R 的安全上限(⭐ 2026-10-08 皇上旨收到 1.0:再大包络远大于停位需求、回弹精度已够,白烧射程) */
|
|
@@ -518,7 +526,8 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
518
526
|
digits: 2,
|
|
519
527
|
unit: "m",
|
|
520
528
|
frozen: true,
|
|
521
|
-
desc: "菱形半对角线 R,外接框边长 = 2R(= 离墙多远开始判定碰撞的半径)。越大包络越大、回弹方向越准;R<0.6 仍会贴墙穿模(R=0.5 贴墙面、R=0.3 明显穿模),已放宽到 0.2~1.0
|
|
529
|
+
desc: "菱形半对角线 R,外接框边长 = 2R(= 离墙多远开始判定碰撞的半径)。越大包络越大、回弹方向越准;R<0.6 仍会贴墙穿模(R=0.5 贴墙面、R=0.3 明显穿模),已放宽到 0.2~1.0 供按需拧。" +
|
|
530
|
+
"⭐ 2026-10-11 A 档实测:停位逐位等于 R ⇒ 身体入墙深度 = 0.35 − R(R=0.2 → 0.15m、R=0.3 → 0.05m、R≥0.35 → 0m);抖动与 R 无关(全档 0.0000m),旋钮范围按皇上旨不动",
|
|
522
531
|
get: (fps) => fps.CHORD_RHOMBUS_R,
|
|
523
532
|
set: (fps, v) => fps.setHorizontalRayRadius(v),
|
|
524
533
|
},
|
|
@@ -635,7 +644,7 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
635
644
|
step: 0.005,
|
|
636
645
|
digits: 3,
|
|
637
646
|
unit: "m",
|
|
638
|
-
desc: "⭐ 2026-
|
|
647
|
+
desc: "⭐ 2026-10-11 皇上 A 档改判:每轮**只沿「欠距最大那一面」的法线**推一格,且这一格取 min(本值, 该面欠距) ⇒ 大欠距仍是一格一格往外走(皇上 10-07「1 个单位 1 个单位的修正」),只有**收尾那一格按欠距截短**,落点贴在包络边上(旧写法每条命中射线各推满一格、最后一格也推满 ⇒ 过冲 ⇒ 贴墙来回甩 = 抖动)。" +
|
|
639
648
|
"⚠️ 上限以下别贪小:0.03/0.02/0.01 体检台判级完全相同,拧到 0.005 才有改善但「跳跃+冲刺+掉帧」那个现场开始穿墙(格长 = 每帧出水量)。迭代推到全部射线脱开为止",
|
|
640
649
|
},
|
|
641
650
|
{
|
|
@@ -814,11 +823,6 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
814
823
|
// 缓存本帧的按键输入单位方向(水平)。initPlayerInputDir() 每物理步刷新一次;
|
|
815
824
|
// 零向量表示「本帧没按方向键」→ 最终方向退化为纯反弹方向。
|
|
816
825
|
private _inputDirVec: Vector3 = new Vector3();
|
|
817
|
-
/**
|
|
818
|
-
* 本帧**进碰撞之前**的水平速率(米/秒)。皇上八旨要求「移动向量的长度保持不变」,
|
|
819
|
-
* 而碰撞会把 `playerVelocity.x/z` 清零,所以必须在 updatePlayer 入口先记一份。
|
|
820
|
-
*/
|
|
821
|
-
private _preCollideHorizSpeed: number = 0;
|
|
822
826
|
// ========== 回弹预览(皇上 2026-09-25 旨:「加个开关可以关闭碰撞修正位置的计算,方便观察回弹向量」)==========
|
|
823
827
|
// 打开后:**不写位置**(见 playerCollisions 末尾唯一的 translate 闸门),但方向/推离量照常算、
|
|
824
828
|
// 黄→白方向线照常画 → 肉眼核对「算出来的方向对不对」而不被人推开。
|
|
@@ -926,10 +930,20 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
926
930
|
private _probeRaycaster: Raycaster = new Raycaster();
|
|
927
931
|
// 临时向量(复用避免 GC)
|
|
928
932
|
private _tempVec3: Vector3 = new Vector3();
|
|
929
|
-
// xsh 移植(2026-09-28):候选位置(= 控制器位置 + positionIncremental
|
|
930
|
-
// 与推离向量专用临时量(复用避免 GC)
|
|
933
|
+
// xsh 移植(2026-09-28):候选位置(= 控制器位置 + positionIncremental,射线原点锚)临时量
|
|
931
934
|
private _candPos: Vector3 = new Vector3();
|
|
932
|
-
|
|
935
|
+
/**
|
|
936
|
+
* ⭐ 2026-10-11 A 档(解析贴合)专用临时量,全部复用避免 GC:
|
|
937
|
+
* · `_fitNormal` = 助手里「本轮这条命中面」指向玩家一侧的单位水平法线;
|
|
938
|
+
* · `_horizNormal` = 本轮**欠距最大**那面的法线(推离方向 + 速度闸门共用一个方向,绝不各算一遍);
|
|
939
|
+
* · `_fitVec` = (候选中心 − 命中点) 临时量;
|
|
940
|
+
* · `_rhombusAxisX/_rhombusAxisZ` = 本帧菱形两条对角轴的世界方向(随 yaw 转,恒水平)。
|
|
941
|
+
*/
|
|
942
|
+
private _fitNormal: Vector3 = new Vector3();
|
|
943
|
+
private _horizNormal: Vector3 = new Vector3();
|
|
944
|
+
private _fitVec: Vector3 = new Vector3();
|
|
945
|
+
private _rhombusAxisX: Vector3 = new Vector3(1, 0, 0);
|
|
946
|
+
private _rhombusAxisZ: Vector3 = new Vector3(0, 0, 1);
|
|
933
947
|
private _tempVec4: Vector3 = new Vector3();
|
|
934
948
|
// 位移细分用的临时向量(与 playerCollisions 内的 _tempVec4 分开,避免被覆盖)
|
|
935
949
|
private _tempVec5: Vector3 = new Vector3();
|
|
@@ -1119,6 +1133,40 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1119
1133
|
if (!this._transformFaceNormalWorld(interset, n)) return null;
|
|
1120
1134
|
return n.normalize().y;
|
|
1121
1135
|
}
|
|
1136
|
+
/**
|
|
1137
|
+
* ⭐⭐ 2026-10-11 皇上改判 A 档「解析贴合」:一条水平命中射线**沿本面法线还差多少才脱开**。
|
|
1138
|
+
* 同时把该面的单位水平法线(指向玩家所在的一侧)写进 `this._fitNormal` 供调用方取用。
|
|
1139
|
+
*
|
|
1140
|
+
* 为什么要它:旧写法每轮对每条命中射线**整格**推 `RETREAT_SKIN`(1cm),而退出判据是「8 条射线
|
|
1141
|
+
* 全部脱开」⇒ 落点必然**过冲最多一格**(实测弹回 1.05cm),下一帧再从过冲处走回来 =
|
|
1142
|
+
* 皇上所见「顶进去又弹回来一直抖」(无头复现:抖峰峰 0.0193m,60fps 下 34 次往复/40 帧,
|
|
1143
|
+
* 与 R / 墙厚 / 入射角 / 帧率全无关)。按欠距推到「刚好脱开」就不再有过冲。
|
|
1144
|
+
*
|
|
1145
|
+
* 判据(恒等式,不是拍的):碰撞包络是顶点在 ±R·x̂、±R·ẑ 的**菱形**,它沿方向 n 的支持距离
|
|
1146
|
+
* req = R·max(|n·x̂|, |n·ẑ|) ∈ [R/√2, R]。候选中心沿 n 到命中面的垂距为 perp(在实体内为负),
|
|
1147
|
+
* 那么「还差 deficit = req − perp」推满就正好贴在包络边上。
|
|
1148
|
+
*
|
|
1149
|
+
* 法线取向:**与射线行进方向相反**的一侧(three 对 FrontSide 只回正面命中,所以常态天然满足;
|
|
1150
|
+
* DoubleSide 拿到背面时按此翻号)。⚠️ 不能按「指向中心」翻号——中心已经陷进 1m 厚墙板时,
|
|
1151
|
+
* 那样翻会把人往墙体更深处推(旧写法正是靠两侧票互相抵消才卡在板正中)。
|
|
1152
|
+
*
|
|
1153
|
+
* @returns deficit(米,≤0 = 已经脱开)。退化场景返回 0:
|
|
1154
|
+
* · 拿不到面法线(无 face / 零向量)
|
|
1155
|
+
* · 命中面近乎水平(法线压平后是零向量,如贴着地面/台面掠射)⇒ 不该把它当墙侧推
|
|
1156
|
+
*/
|
|
1157
|
+
private _horizFitDeficit(worldPos: Vector3, rayDir: Vector3, interset: Intersection): number {
|
|
1158
|
+
const n = this._fitNormal;
|
|
1159
|
+
if (!this._transformFaceNormalWorld(interset, n)) return 0;
|
|
1160
|
+
n.y = 0; // 本布局水平射线在 y=−0.7/−0.75(皇上 09-26 五旨),推离必须纯水平(同旧「偏差①」)
|
|
1161
|
+
if (n.lengthSq() < 1e-8) return 0;
|
|
1162
|
+
n.normalize();
|
|
1163
|
+
// 指向「射线来的那一侧」= 逆着射线行进方向,即离开实体的方向
|
|
1164
|
+
if (n.dot(rayDir) > 0) n.negate();
|
|
1165
|
+
const perp = n.dot(this._fitVec.copy(worldPos).sub(interset.point));
|
|
1166
|
+
const ax = Math.abs(n.dot(this._rhombusAxisX));
|
|
1167
|
+
const az = Math.abs(n.dot(this._rhombusAxisZ));
|
|
1168
|
+
return this.CHORD_RHOMBUS_R * Math.max(ax, az) - perp;
|
|
1169
|
+
}
|
|
1122
1170
|
/**
|
|
1123
1171
|
* 脚下深探:往下问 VOID_PROBE_DOWN 这么长一段,有没有地面(2026-09-25,穿地板自救用)。
|
|
1124
1172
|
* @returns true = 下方有地面 → 只是正常腾空/下落,不是穿模
|
|
@@ -1397,11 +1445,10 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1397
1445
|
controls = (deltaTime: number): void => {
|
|
1398
1446
|
const speedDelta = deltaTime * (this.playerOnFloor ? 25 : 8) * this.speed;
|
|
1399
1447
|
// ⭐ 2026-09-26 皇上旨「碰撞就是按射线拾取算的,不用搞太复杂」:
|
|
1400
|
-
// 旧的「接触法线缓存 + 加速度保速投影」整块删除 ——
|
|
1401
|
-
//
|
|
1402
|
-
//
|
|
1403
|
-
//
|
|
1404
|
-
// 见 playerCollisions 末尾那段。清零本身照旧。
|
|
1448
|
+
// 旧的「接触法线缓存 + 加速度保速投影」整块删除 —— 这里**只管往输入方向加速**,
|
|
1449
|
+
// 撞墙的手感全部由 playerCollisions 负责:位置侧「解析贴合」(欠距最大那面推格、
|
|
1450
|
+
// 最后一格截短),速度侧「只削往墙里那一份」(⚠️ 2026-10-11 A 档改判,此处不再是
|
|
1451
|
+
// playerVelocity.x/z 整条清零 ⇒ 贴墙能沿墙滑行,见 playerCollisions 末尾那段)。
|
|
1405
1452
|
const accel = this._accelVec.set(0, 0, 0);
|
|
1406
1453
|
if (this.keyStates["KeyW"]) {
|
|
1407
1454
|
accel.addScaledVector(this.getForwardVector(), speedDelta);
|
|
@@ -1442,9 +1489,6 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1442
1489
|
damping *= 0.1;
|
|
1443
1490
|
}
|
|
1444
1491
|
this.playerVelocity.addScaledVector(this.playerVelocity, damping);
|
|
1445
|
-
// ⭐ 2026-09-26 皇上八旨「位置修正结束后…移动向量的长度保持不变」:本帧**进碰撞前**的
|
|
1446
|
-
// 水平速率快照。碰撞会把速度清零,子步跑完再想要「原来的长度」就没有了,必须在入口取。
|
|
1447
|
-
this._preCollideHorizSpeed = Math.hypot(this.playerVelocity.x, this.playerVelocity.z);
|
|
1448
1492
|
// 位移细分(连续碰撞):把本帧位移切成若干 ≤ MAX_STEP_DISTANCE 的小步,逐步推进并检测。
|
|
1449
1493
|
// 不细分的话,掉帧(deltaTime 被 clamp 到 0.05)时单步位移可达 25×0.025 ≈ 0.6,
|
|
1450
1494
|
// 远大于射线的检测余量(沿法线最小 reach R/√2 = 0.749 − 子步 0.1)→ 直接跨过墙体(穿墙)。
|
|
@@ -1512,11 +1556,15 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1512
1556
|
// ⇒ 本方法整体 = xsh `FPSControls.tsx → computerPosition()` 的忠实移植,骨架只有:
|
|
1513
1557
|
// ① while 循环(皇上 09-03 定「一帧合计不超过 100」,10-03 旨改到 500;骨架与 xsh 的 i<100 同形);
|
|
1514
1558
|
// ② 每轮在「候选位置」(真实位置 + positionIncremental)上打 8 条水平斜弦射线,
|
|
1515
|
-
//
|
|
1516
|
-
//
|
|
1517
|
-
//
|
|
1559
|
+
// ⭐ 2026-10-11 皇上 A 档改判:每条命中算「沿本面法线还差多少才脱开」(deficit),
|
|
1560
|
+
// **只取欠距最大的那一面**,沿它的法线推 min(RETREAT_SKIN, deficit) ——
|
|
1561
|
+
// 一格一格的外形保留(皇上 10-07 旨「应该 1 个单位 1 个单位的修正」⇒ RETREAT_SKIN=0.01),
|
|
1562
|
+
// 但收尾那一格按欠距截短 ⇒ 落点贴包络边,不再整格过冲(旧 xsh 各票各推一整格 ⇒ 必过冲);
|
|
1563
|
+
// 累加进 positionIncremental,并 goOnComputer=true 续命下一轮;
|
|
1518
1564
|
// ③ 下射线命中 ⇒ 竖直速度清零 + y 钉到「命中面之上 DOWN_RANGE」(xsh: cv − distance);
|
|
1519
|
-
// 上射线命中 ⇒ 竖直速度清零 +
|
|
1565
|
+
// 上射线命中 ⇒ 竖直速度清零 + 修正(含三道闸天花板的血案守卫)
|
|
1566
|
+
// —— ⭐ 10-11 修好少括号的 bug 后,上射线**每轮都测**(旧代码被关进「下射线命中」分支里
|
|
1567
|
+
// ⇒ 腾空时跳起来顶不到天花板);
|
|
1520
1568
|
// ④ 某一轮全部射线脱开 ⇒ 收工;循环外唯一一次 translate 落地(血案护栏不变)。
|
|
1521
1569
|
// ⭐⭐ 2026-10-02 皇上旨「模拟修正,不是真实修正,把最终结果算好了再应用到真实的第一人称
|
|
1522
1570
|
// 控制器上面」⇒ 那个 translate 落的是**「本步位移 + 允许的修正」一次到位**:
|
|
@@ -1529,7 +1577,12 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1529
1577
|
// 本布局射线在 y=−0.7/−0.75(皇上 09-26 五旨),不压平会把 y 混进推离;
|
|
1530
1578
|
// · 水平射线 8 条(皇上 09-06/09-14 亲加的 6-9 共线反向组),xsh 原版 4 条;
|
|
1531
1579
|
// · 竖向保留 faceUp / 天花板三道闸守卫(「掉出世界」血案修复)。
|
|
1580
|
+
// · ⭐ 2026-10-11 A 档:**只沿「欠距最大那一面」的法线**推,且最后一格按欠距截短
|
|
1581
|
+
// (xsh 是每条命中各推一整格 ⇒ 4 条命中同一面墙一轮推 4cm,退出时必过冲)。
|
|
1532
1582
|
// 原 deficit / 票面合成(finalDir) / 逐格推离 / 白推保险丝 / 胶囊兜底机器整条拆除。
|
|
1583
|
+
// ⚠️ 措辞校正(10-11):上面这句里「deficit」那半已随 A 档**回归**(`_horizFitDeficit()`:
|
|
1584
|
+
// 沿命中面法线的菱形可达距离 R·max(|n·x̂|,|n·ẑ|) 减当前垂距);
|
|
1585
|
+
// 仍拆除的是「票面合成 finalDir / 白推保险丝 / 胶囊兜底」三件 —— 别照旧文案把它们捡回来。
|
|
1533
1586
|
const positionIncremental = this._tempVec4.set(0, 0, 0);
|
|
1534
1587
|
this._refreshInputDir(); // 台账 ix/iz 列还要用(与碰撞计算无关)
|
|
1535
1588
|
const recordDebug = (this.dev || this.thirdPerson) && isFinalStep;
|
|
@@ -1561,12 +1614,21 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1561
1614
|
for (const ray of this._rays) {
|
|
1562
1615
|
ray.updateWorld(yawQuat, worldPos);
|
|
1563
1616
|
}
|
|
1617
|
+
// ⭐ 2026-10-11 A 档:菱形两条对角轴的世界方向(只随 yaw,恒水平)——贴合量 req 要用它
|
|
1618
|
+
this._rhombusAxisX.set(1, 0, 0).applyQuaternion(yawQuat);
|
|
1619
|
+
this._rhombusAxisZ.set(0, 0, 1).applyQuaternion(yawQuat);
|
|
1564
1620
|
const horizontalFar = this.HORIZONTAL_FAR; // = R√2(xsh: far = direction.length())
|
|
1565
1621
|
const downFar = downRange + this.VERTICAL_SKIN;
|
|
1566
1622
|
const upFar = upRange + this.VERTICAL_SKIN;
|
|
1567
1623
|
const devVisualFarD = downRange;
|
|
1568
1624
|
const devVisualFarU = upRange;
|
|
1569
|
-
// ==========
|
|
1625
|
+
// ========== 水平半区(⭐ 2026-10-11 皇上改判 A 档 = 解析贴合,替代「每条命中各推一整格」)==========
|
|
1626
|
+
// 每轮:所有命中射线各算「沿本面法线还差多少才脱开」(deficit),**只取欠距最大的那一面**,
|
|
1627
|
+
// 沿它的法线推 `min(RETREAT_SKIN, deficit)` —— 一格 1cm 的上限照旧(皇上 10-07「1 个单位
|
|
1628
|
+
// 1 个单位的修正」),但**最后一格只推欠距本身**,落点贴在包络边上,不再整格过冲。
|
|
1629
|
+
// · 为什么不再各票相加:4 条命中同一面墙时旧写法一轮推 4cm,退出时必然过头;
|
|
1630
|
+
// · 为什么只取最大:墙角两面墙各欠 3cm 时,先脱开深的那面,下一轮再补另一面(≤2~3 轮)。
|
|
1631
|
+
let bestDeficit = 0;
|
|
1570
1632
|
for (let ri = 2; ri < this._rays.length; ri++) {
|
|
1571
1633
|
const ray = this._rays[ri];
|
|
1572
1634
|
ray.far = horizontalFar;
|
|
@@ -1595,24 +1657,23 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1595
1657
|
interset = intersets[j];
|
|
1596
1658
|
}
|
|
1597
1659
|
}
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
}
|
|
1660
|
+
const deficit = this._horizFitDeficit(worldPos, ray.direction, interset);
|
|
1661
|
+
if (deficit > bestDeficit) {
|
|
1662
|
+
bestDeficit = deficit;
|
|
1663
|
+
this._horizNormal.copy(this._fitNormal); // 与推离方向同一个数,绝不分两处算
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
if (bestDeficit > 1e-6) {
|
|
1667
|
+
if (i > roundCap) {
|
|
1668
|
+
// ⭐ **轮次上限**用完 ⇒ 这一轮起水平一格都不再推。
|
|
1669
|
+
// 常态帧 = 皇上 10-07 点头新加的 ROUNDS_PER_SUBSTEP(默认 500 ⇒ 与旧行为同形)。
|
|
1670
|
+
// ⚠️ 只拦水平:竖向(踩地/顶头)仍照常,否则人会往地心沉(皇上 09-25 冻结口径)。
|
|
1671
|
+
} else {
|
|
1672
|
+
// ⭐ 皇上 10-07 旨「每执行一次,偏移量是多少」⇒ 一格一行、带累计的形态保留:
|
|
1673
|
+
// 大欠距仍是一格一格往外走,只有收尾那一格按欠距截短。
|
|
1674
|
+
positionIncremental.addScaledVector(this._horizNormal, Math.min(this.RETREAT_SKIN, bestDeficit));
|
|
1675
|
+
goOnComputer = true;
|
|
1676
|
+
this._horizHit = true;
|
|
1616
1677
|
}
|
|
1617
1678
|
}
|
|
1618
1679
|
// ========== 向下射线(索引 0 = upTodwomRay)==========
|
|
@@ -1675,6 +1736,13 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1675
1736
|
// **不能**沿用旧探针的 `!debugRecorded`:`debugRecorded = !recordDebug`,而 `recordDebug`
|
|
1676
1737
|
// 跟着面板「碰撞射线」(dev) 走 → dev 关着时恒 true → 整段被跳过,
|
|
1677
1738
|
// 这正是皇上「在控制台里根本看不到下射线数值」的原因。
|
|
1739
|
+
// ⭐ 2026-10-11 皇上旨「少括号的 bug 一起修」:这个 `}` 是 `if (downIntersets.length > 0)` 的
|
|
1740
|
+
// 闭合括号,历史上被吃掉了 ⇒ 下面整段「向上射线」被关进「下射线命中」分支里。
|
|
1741
|
+
// 症状:腾空时脚下射线打不到地面 → 上射线**一次都不测** → 跳起来顶不到天花板(穿板顶)。
|
|
1742
|
+
// 顺带的第二个坑:while 的闭合括号跟着后移到「应用推离」注释之后(原 1843 行那个 `}`),
|
|
1743
|
+
// 于是「更新调试射线」那段也在每轮迭代里跑一遍 —— 删掉那个多余括号后它回到循环外,
|
|
1744
|
+
// 正好对上它自己的标签「dev 模式的**最后一步**」,且每帧只做一次。
|
|
1745
|
+
}
|
|
1678
1746
|
// ========== 向上射线(索引 1 = dwomToUpRay)==========
|
|
1679
1747
|
const upRay = this._rays[1];
|
|
1680
1748
|
upRay.far = upFar;
|
|
@@ -1786,7 +1854,6 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1786
1854
|
// ⚠️ 只跳「写位置」,不跳「记账」:`playerVelocity.y = 0`、`playerOnFloor = true`
|
|
1787
1855
|
// 与削速度/方向票全部保留 → 观察时不会一帧帧攒重力陷到地心,也不会触发
|
|
1788
1856
|
// camera.y ≤ −10 的掉出世界复位。
|
|
1789
|
-
}
|
|
1790
1857
|
// ⭐⭐ 2026-10-02 皇上旨(原话):「在修正位置的时候,我希望的是**模拟修正**,而不是**真实的
|
|
1791
1858
|
// 修正**,在模拟修正中把最终结果计算好了,再应用到真实的第一人称控制器上面」。
|
|
1792
1859
|
// ⇒ 上面那个 while 全在**模拟位置**(真实位置 + 本步位移 `_subStep`)上跑;真实 collider
|
|
@@ -1824,15 +1891,22 @@ export default class FPScontrol extends EventDispatcher<FPScontrolEventTypeMap>
|
|
|
1824
1891
|
// 本步已消费:归零,面板那两颗直接调 playerCollisions 的按钮不会重复走一步
|
|
1825
1892
|
this._subStep.set(0, 0, 0);
|
|
1826
1893
|
|
|
1827
|
-
// ⭐⭐ 2026-10-
|
|
1828
|
-
//
|
|
1829
|
-
//
|
|
1830
|
-
//
|
|
1831
|
-
//
|
|
1832
|
-
//
|
|
1894
|
+
// ⭐⭐ 2026-10-11 皇上旨「撞墙会进入墙体然后反弹回来,一直抖动」→ A 档改判:
|
|
1895
|
+
// **只削掉「往墙里」那一份速度**(沿命中面法线的负分量),切向分量原样保留。
|
|
1896
|
+
// 旧口径(2026-10-07「撞到墙后,加速度置为 0」)是 x/z 双双归零,两处毛病:
|
|
1897
|
+
// ① 斜着撞墙 = 连「沿墙滑行」那份一起抹掉 → 手感像被墙吸停,且人是沿坐标轴方向被清,
|
|
1898
|
+
// 不是沿墙法线;速度被清零的方向与实际推离方向不共线 → 推离与加速度交替占上风;
|
|
1899
|
+
// ② 全清 ⇒ 每帧「输入重新加速 → 立刻清零」的锯齿,正是他看到的抖动的另一半来源
|
|
1900
|
+
// (实测峰峰 0.0193m、60fps 下约 17 次/秒翻向)。
|
|
1901
|
+
// 新口径:`into = v·n`(n = 本轮欠距最大那面的**外法线**,指向玩家一侧),只在 into<0
|
|
1902
|
+
// (= 正在往墙里冲)时减掉 `into·n` 那份 ⇒ 撞后 v·n = 0(非穿透),切向 v−(v·n)n 完整保留。
|
|
1903
|
+
// ⚠️ 方向与推离用的是**同一个** `_horizNormal`(水平半区那轮算好、就地复用),绝不另算一遍。
|
|
1904
|
+
// ⚠️ 竖向 y 一字不动(重力/跳跃照旧);观察模式(回弹预览)不改速度,口径与 10-07 一致。
|
|
1833
1905
|
if (this._horizHit && !this.previewRetreat) {
|
|
1834
|
-
this.playerVelocity.
|
|
1835
|
-
|
|
1906
|
+
const into = this.playerVelocity.dot(this._horizNormal);
|
|
1907
|
+
if (into < 0) {
|
|
1908
|
+
this.playerVelocity.addScaledVector(this._horizNormal, -into);
|
|
1909
|
+
}
|
|
1836
1910
|
}
|
|
1837
1911
|
// ⭐ 十旨:一帧一条的抖动台账。**只由子步循环的最后一步(isFinalStep)记** ——
|
|
1838
1912
|
// 中间小步是碰撞细分的过渡状态,记了就变成「一帧好几条」,翻向/跳变的口径全乱。
|
package/Ground1/Ground1.js
CHANGED
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
*
|
|
22
22
|
* ⚠️ 改动红线(这几条被别处依赖,**不许顺手改**):
|
|
23
23
|
* - `userData.fpsCollision = true`:FPScontrol 把地板当碰撞体(见 FPScontrol.ts 地面处理段)。
|
|
24
|
-
* - `userData.aoFloor = true
|
|
25
|
-
*
|
|
24
|
+
* - ⚠️ 2026-10-11 皇上旨「物体的深度都要进深度图」⇒ 原第三条红线 `userData.aoFloor = true`
|
|
25
|
+
* (把地板从可见深度图里排除的那条例外)**整条拆除**:它的前提是地板半透明可透视,与本文件
|
|
26
|
+
* ② 的「不透明改造」自相矛盾。地板现在按普通实心面写进深度图,被它挡住的描边/辉光/覆盖色/
|
|
27
|
+
* 磨砂会被裁掉。见 three-base/pass/ssao_pass.ts 文件头。
|
|
26
28
|
* - ShaderMaterial 必须含 logdepthbuf chunk;linear 输出必须 `#include <colorspace_fragment>`;
|
|
27
29
|
* 否则末端 sRGB 编码会二次编码 → 发白。
|
|
28
30
|
*/
|
|
@@ -36,10 +38,8 @@ export default class Ground1 extends Mesh {
|
|
|
36
38
|
super();
|
|
37
39
|
// 标记为自己参与 FPS 碰撞检测
|
|
38
40
|
this.userData.fpsCollision = true;
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
// 见 three-base/pass/ssao_pass.ts 的复合守卫说明。
|
|
42
|
-
this.userData.aoFloor = true;
|
|
41
|
+
// ⚠️ 这里原来还有 `this.userData.aoFloor = true;`(把本地板从可见深度图里排除的特例标记),
|
|
42
|
+
// 2026-10-11 皇上旨「物体的深度都要进深度图」⇒ 连同 ssao_pass 的特例分支一起整条删除。
|
|
43
43
|
}
|
|
44
44
|
renderOrder = -1;
|
|
45
45
|
geometry = (() => {
|
package/Ground1/Ground1.ts
CHANGED
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
*
|
|
22
22
|
* ⚠️ 改动红线(这几条被别处依赖,**不许顺手改**):
|
|
23
23
|
* - `userData.fpsCollision = true`:FPScontrol 把地板当碰撞体(见 FPScontrol.ts 地面处理段)。
|
|
24
|
-
* - `userData.aoFloor = true
|
|
25
|
-
*
|
|
24
|
+
* - ⚠️ 2026-10-11 皇上旨「物体的深度都要进深度图」⇒ 原第三条红线 `userData.aoFloor = true`
|
|
25
|
+
* (把地板从可见深度图里排除的那条例外)**整条拆除**:它的前提是地板半透明可透视,与本文件
|
|
26
|
+
* ② 的「不透明改造」自相矛盾。地板现在按普通实心面写进深度图,被它挡住的描边/辉光/覆盖色/
|
|
27
|
+
* 磨砂会被裁掉。见 three-base/pass/ssao_pass.ts 文件头。
|
|
26
28
|
* - ShaderMaterial 必须含 logdepthbuf chunk;linear 输出必须 `#include <colorspace_fragment>`;
|
|
27
29
|
* 否则末端 sRGB 编码会二次编码 → 发白。
|
|
28
30
|
*/
|
|
@@ -37,10 +39,8 @@ export default class Ground1 extends Mesh {
|
|
|
37
39
|
super();
|
|
38
40
|
// 标记为自己参与 FPS 碰撞检测
|
|
39
41
|
this.userData.fpsCollision = true;
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
// 见 three-base/pass/ssao_pass.ts 的复合守卫说明。
|
|
43
|
-
this.userData.aoFloor = true;
|
|
42
|
+
// ⚠️ 这里原来还有 `this.userData.aoFloor = true;`(把本地板从可见深度图里排除的特例标记),
|
|
43
|
+
// 2026-10-11 皇上旨「物体的深度都要进深度图」⇒ 连同 ssao_pass 的特例分支一起整条删除。
|
|
44
44
|
}
|
|
45
45
|
renderOrder: number = -1;
|
|
46
46
|
geometry: PlaneGeometry = (() => {
|
package/MktMesh/MktMesh.d.ts
CHANGED
|
@@ -72,9 +72,13 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
72
72
|
* · 只读 XZ ⇒ 与名册历代那把「水平距离」尺同一把(09-28 旨),高度差不进尺子。
|
|
73
73
|
* · `null` ⇒ 回落 `camera.position`(老口径):发布页那一路没有控制器引用,不注入就一切照旧。
|
|
74
74
|
* · 存的是**引用**(OrbitControls 原地改它那个 Vector3)⇒ 消费方设一次即可,不必每帧重设。
|
|
75
|
-
* ·
|
|
75
|
+
* · 注入的是**世界坐标**;`updateTexture` 里先 `worldToLocal` 换算到本网格局部空间再比距离
|
|
76
|
+
* (全景矩阵与着色器取图的 `vProjPos` 都在局部空间,见那里的 2026-10-11 丙旨说明)。
|
|
77
|
+
* ⛔ 反过来去给全景矩阵乘 `matrixWorld` 是错的:那会让 JS 侧的尺子和 shader 里的取图各走一路。
|
|
76
78
|
*/
|
|
77
79
|
private _rosterCenter;
|
|
80
|
+
/** 锚点换算到局部空间的落点(每帧复用同一只临时量,避免分配) */
|
|
81
|
+
private _rosterAnchorLocal;
|
|
78
82
|
/**
|
|
79
83
|
* ⭐ 皇上旨 2026-10-03「整套搬进库(彻底同源)」:库侧不再自养「按全景序号取整槽、齐活才写」那一路,
|
|
80
84
|
* 改成与编辑态**同一份换绑策略**(`./panoSlotBind`)+ 同一口径的三张表:
|
package/MktMesh/MktMesh.js
CHANGED
|
@@ -118,9 +118,13 @@ export default class MktMesh extends Mesh {
|
|
|
118
118
|
* · 只读 XZ ⇒ 与名册历代那把「水平距离」尺同一把(09-28 旨),高度差不进尺子。
|
|
119
119
|
* · `null` ⇒ 回落 `camera.position`(老口径):发布页那一路没有控制器引用,不注入就一切照旧。
|
|
120
120
|
* · 存的是**引用**(OrbitControls 原地改它那个 Vector3)⇒ 消费方设一次即可,不必每帧重设。
|
|
121
|
-
* ·
|
|
121
|
+
* · 注入的是**世界坐标**;`updateTexture` 里先 `worldToLocal` 换算到本网格局部空间再比距离
|
|
122
|
+
* (全景矩阵与着色器取图的 `vProjPos` 都在局部空间,见那里的 2026-10-11 丙旨说明)。
|
|
123
|
+
* ⛔ 反过来去给全景矩阵乘 `matrixWorld` 是错的:那会让 JS 侧的尺子和 shader 里的取图各走一路。
|
|
122
124
|
*/
|
|
123
125
|
_rosterCenter = null;
|
|
126
|
+
/** 锚点换算到局部空间的落点(每帧复用同一只临时量,避免分配) */
|
|
127
|
+
_rosterAnchorLocal = new Vector3();
|
|
124
128
|
/**
|
|
125
129
|
* ⭐ 皇上旨 2026-10-03「整套搬进库(彻底同源)」:库侧不再自养「按全景序号取整槽、齐活才写」那一路,
|
|
126
130
|
* 改成与编辑态**同一份换绑策略**(`./panoSlotBind`)+ 同一口径的三张表:
|
|
@@ -691,15 +695,21 @@ export default class MktMesh extends Mesh {
|
|
|
691
695
|
this.activeIndex = -1;
|
|
692
696
|
return;
|
|
693
697
|
}
|
|
694
|
-
|
|
698
|
+
// ⭐ 皇上旨 2026-10-11 丙:尺子的两端必须落在**同一个空间**。注入的锚点是世界坐标,而下面那把尺子量的
|
|
699
|
+
// 全景位置记在本网格的**局部(制图)空间** —— 依据是着色器自己:`vProjPos = uProjInvMatrix·modelMatrix·pos`
|
|
700
|
+
// = M⁻¹·M·pos = 局部(`uProjInvMatrix` 正是 `syncProjInvMatrix` 里那句 `matrixWorld` 求逆),片元再拿
|
|
701
|
+
// `dir = vProjPos - tm[3].xyz` 取图 ⇒ 全景矩阵只可能和 `vProjPos` 同空间,即局部。
|
|
702
|
+
// 所以换算放在**锚点这一端**(`worldToLocal`),⛔ 不去给全景矩阵乘 `matrixWorld`:那是把 JS 的尺子
|
|
703
|
+
// 和 shader 的取图拆成两路。网格无变换时这一步是恒等 ⇒ 老项目逐字不变;有旋转时(消费方给 mkt 加了
|
|
704
|
+
// `rotation.y`)原来会把「往世界的某一头走」量成「往局部的另一头走」,人走到位了名册还不动。
|
|
705
|
+
const ref = this._rosterAnchorLocal.copy(this._rosterCenter ?? camera.position);
|
|
706
|
+
this.worldToLocal(ref);
|
|
695
707
|
const dists = [];
|
|
696
708
|
for (let i = 0; i < n; i++) {
|
|
697
709
|
const e = this.textures[i].matrix.elements;
|
|
698
710
|
this._tmpV3.set(e[12], e[13], e[14]);
|
|
699
|
-
// ⚠️
|
|
700
|
-
//
|
|
701
|
-
// MktMesh 一有整体变换就会算错「离锚点最近的是哪张」(选错全景)。
|
|
702
|
-
// (2026-09-19 曾误以为它记在模型空间而多乘了一次,趁 MktDevMesh 对齐时一并纠正。)
|
|
711
|
+
// ⚠️ 全景点矩阵记在本网格的局部空间(与 `wallPoints` 同一空间,见上面丙旨那段着色器推导),
|
|
712
|
+
// 所以拿来直接和**已换算到局部**的 `ref` 比距离;⛔ 这里绝不乘 `matrixWorld`(双重变换 = 选错全景)。
|
|
703
713
|
// ⭐ 09-28 09:33 旨:挑图与编辑器取图同一把「**水平距离**」尺(XZ 平面,不含高度差)。
|
|
704
714
|
// const d = this._tmpV3.distanceTo(camera.position); // 旧原理:三维直线距离——全景点同高(y 恒 1.6)时与本式排序等价,注释保留备查
|
|
705
715
|
// ⭐ 10-07 第二十一道旨:尺子的另一端从相机位置换成 `ref`(控制器中心点;未注入时它就是相机位置)。
|
package/MktMesh/MktMesh.ts
CHANGED
|
@@ -141,9 +141,13 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
141
141
|
* · 只读 XZ ⇒ 与名册历代那把「水平距离」尺同一把(09-28 旨),高度差不进尺子。
|
|
142
142
|
* · `null` ⇒ 回落 `camera.position`(老口径):发布页那一路没有控制器引用,不注入就一切照旧。
|
|
143
143
|
* · 存的是**引用**(OrbitControls 原地改它那个 Vector3)⇒ 消费方设一次即可,不必每帧重设。
|
|
144
|
-
* ·
|
|
144
|
+
* · 注入的是**世界坐标**;`updateTexture` 里先 `worldToLocal` 换算到本网格局部空间再比距离
|
|
145
|
+
* (全景矩阵与着色器取图的 `vProjPos` 都在局部空间,见那里的 2026-10-11 丙旨说明)。
|
|
146
|
+
* ⛔ 反过来去给全景矩阵乘 `matrixWorld` 是错的:那会让 JS 侧的尺子和 shader 里的取图各走一路。
|
|
145
147
|
*/
|
|
146
148
|
private _rosterCenter: Vector3 | null = null;
|
|
149
|
+
/** 锚点换算到局部空间的落点(每帧复用同一只临时量,避免分配) */
|
|
150
|
+
private _rosterAnchorLocal: Vector3 = new Vector3();
|
|
147
151
|
/**
|
|
148
152
|
* ⭐ 皇上旨 2026-10-03「整套搬进库(彻底同源)」:库侧不再自养「按全景序号取整槽、齐活才写」那一路,
|
|
149
153
|
* 改成与编辑态**同一份换绑策略**(`./panoSlotBind`)+ 同一口径的三张表:
|
|
@@ -716,15 +720,21 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
716
720
|
this.activeIndex = -1;
|
|
717
721
|
return;
|
|
718
722
|
}
|
|
719
|
-
|
|
723
|
+
// ⭐ 皇上旨 2026-10-11 丙:尺子的两端必须落在**同一个空间**。注入的锚点是世界坐标,而下面那把尺子量的
|
|
724
|
+
// 全景位置记在本网格的**局部(制图)空间** —— 依据是着色器自己:`vProjPos = uProjInvMatrix·modelMatrix·pos`
|
|
725
|
+
// = M⁻¹·M·pos = 局部(`uProjInvMatrix` 正是 `syncProjInvMatrix` 里那句 `matrixWorld` 求逆),片元再拿
|
|
726
|
+
// `dir = vProjPos - tm[3].xyz` 取图 ⇒ 全景矩阵只可能和 `vProjPos` 同空间,即局部。
|
|
727
|
+
// 所以换算放在**锚点这一端**(`worldToLocal`),⛔ 不去给全景矩阵乘 `matrixWorld`:那是把 JS 的尺子
|
|
728
|
+
// 和 shader 的取图拆成两路。网格无变换时这一步是恒等 ⇒ 老项目逐字不变;有旋转时(消费方给 mkt 加了
|
|
729
|
+
// `rotation.y`)原来会把「往世界的某一头走」量成「往局部的另一头走」,人走到位了名册还不动。
|
|
730
|
+
const ref = this._rosterAnchorLocal.copy(this._rosterCenter ?? camera.position);
|
|
731
|
+
this.worldToLocal(ref);
|
|
720
732
|
const dists: { t: MktTextureInfo; d: number }[] = [];
|
|
721
733
|
for (let i = 0; i < n; i++) {
|
|
722
734
|
const e = this.textures[i].matrix.elements;
|
|
723
735
|
this._tmpV3.set(e[12], e[13], e[14]);
|
|
724
|
-
// ⚠️
|
|
725
|
-
//
|
|
726
|
-
// MktMesh 一有整体变换就会算错「离锚点最近的是哪张」(选错全景)。
|
|
727
|
-
// (2026-09-19 曾误以为它记在模型空间而多乘了一次,趁 MktDevMesh 对齐时一并纠正。)
|
|
736
|
+
// ⚠️ 全景点矩阵记在本网格的局部空间(与 `wallPoints` 同一空间,见上面丙旨那段着色器推导),
|
|
737
|
+
// 所以拿来直接和**已换算到局部**的 `ref` 比距离;⛔ 这里绝不乘 `matrixWorld`(双重变换 = 选错全景)。
|
|
728
738
|
// ⭐ 09-28 09:33 旨:挑图与编辑器取图同一把「**水平距离**」尺(XZ 平面,不含高度差)。
|
|
729
739
|
// const d = this._tmpV3.distanceTo(camera.position); // 旧原理:三维直线距离——全景点同高(y 恒 1.6)时与本式排序等价,注释保留备查
|
|
730
740
|
// ⭐ 10-07 第二十一道旨:尺子的另一端从相机位置换成 `ref`(控制器中心点;未注入时它就是相机位置)。
|
package/MktMesh/types.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Matrix4 } from "three";
|
|
2
2
|
/**
|
|
3
|
-
* 单个纹理的运行时信息:url +
|
|
3
|
+
* 单个纹理的运行时信息:url + 矩阵(位置 + 旋转,缩放忽略)。
|
|
4
|
+
* ⚠️ 这个矩阵记在 MktMesh **自身局部(制图)空间**,与 `wallPoints` 同一空间 —— 不是世界矩阵:
|
|
5
|
+
* 着色器里 `vProjPos = uProjInvMatrix·modelMatrix·position` 恰好把顶点拉回局部,片元再拿
|
|
6
|
+
* `vProjPos - 矩阵位置` 求投影方向,两端必须同空间纹理才贴得住(网格整体旋转/平移时尤其要紧,
|
|
7
|
+
* 名册挑图那把尺子也因此先把世界锚点 `worldToLocal` 再比距离,见 `MktMesh.updateTexture`)。
|
|
4
8
|
* 纹理矩阵的「位置」即墨卡托投影的中心点(shader 里以它为原点求方向向量)。
|
|
5
9
|
*/
|
|
6
10
|
export interface MktTextureInfo {
|
package/MktMesh/types.ts
CHANGED
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
import type { Matrix4 } from "three";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* 单个纹理的运行时信息:url +
|
|
11
|
+
* 单个纹理的运行时信息:url + 矩阵(位置 + 旋转,缩放忽略)。
|
|
12
|
+
* ⚠️ 这个矩阵记在 MktMesh **自身局部(制图)空间**,与 `wallPoints` 同一空间 —— 不是世界矩阵:
|
|
13
|
+
* 着色器里 `vProjPos = uProjInvMatrix·modelMatrix·position` 恰好把顶点拉回局部,片元再拿
|
|
14
|
+
* `vProjPos - 矩阵位置` 求投影方向,两端必须同空间纹理才贴得住(网格整体旋转/平移时尤其要紧,
|
|
15
|
+
* 名册挑图那把尺子也因此先把世界锚点 `worldToLocal` 再比距离,见 `MktMesh.updateTexture`)。
|
|
12
16
|
* 纹理矩阵的「位置」即墨卡托投影的中心点(shader 里以它为原点求方向向量)。
|
|
13
17
|
*/
|
|
14
18
|
export interface MktTextureInfo {
|
package/ThreeBase.d.ts
CHANGED
|
@@ -90,8 +90,8 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
90
90
|
/**
|
|
91
91
|
* 调试用:深度预览模式。由面板「深度调试」切换,便于逐一看各深度图排查"深度测试全部失效"根因。
|
|
92
92
|
* - "none" :正常渲染(默认)
|
|
93
|
-
* - "global"
|
|
94
|
-
* - "ao" :仅预览 AO 深度图(aoDepthTexture = 法线 pass
|
|
93
|
+
* - "global" :仅预览可见深度图(baseDepthTexture,含地板)。全白=深度为空→renderVisibleDepthPass 没写进深度。
|
|
94
|
+
* - "ao" :仅预览 AO 深度图(aoDepthTexture = 法线 pass 顺带写入)。用于确认深度管线本身是否工作。
|
|
95
95
|
* - "compare" :R=全局 base 深度,G=最近一次 glow/stroke 选区 select 深度。两路任一全白即该侧写入失败。
|
|
96
96
|
* - "excluded":深度图灰度 + 「被排除出深度图的面」叠红(红=该面写不进深度,永远挡不住后处理)。
|
|
97
97
|
* 物体区域(G 暗)若 B 全黑 → 判定从不触发;再看该区 R/G 谁大即可定位是谁缺深度。
|
|
@@ -99,15 +99,6 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
99
99
|
* 通用控制台入口:任意页面都可 `window.__TB_DEBUG_DEPTH = "judge"`(优先级高于面板属性)。
|
|
100
100
|
*/
|
|
101
101
|
debugDepthPreview: DebugDepthMode;
|
|
102
|
-
/**
|
|
103
|
-
* 可见深度图是否包含「标了 userData.aoFloor 的地板」(如 Ground1)。
|
|
104
|
-
*
|
|
105
|
-
* 默认 false —— 原设计:地板可透视,透过地板看到的物体照常显示(不被地板挡住)。
|
|
106
|
-
* 置 true 后地板会写进 baseDepthTexture,**被地板挡住的描边/辉光/毛玻璃/覆盖色会被正确遮挡**。
|
|
107
|
-
* 排查"怎么都挡不住"时先开这个试一下:若开了就正常,说明挡你的正是可透视地板。
|
|
108
|
-
*/
|
|
109
|
-
get baseDepthIncludeFloor(): boolean;
|
|
110
|
-
set baseDepthIncludeFloor(v: boolean);
|
|
111
102
|
normalRenderTarget: WebGLRenderTarget<Texture>;
|
|
112
103
|
screenRenderTarget: WebGLRenderTarget<Texture>;
|
|
113
104
|
screenCopyShader: import("three").ShaderMaterial;
|