提交线修改

This commit is contained in:
2026-03-29 21:07:51 +08:00
parent e800e59e9d
commit 54a1b43585
2 changed files with 75 additions and 11 deletions

View File

@@ -119,7 +119,7 @@ namespace NBF
Log.Error($"SetObiRopeStretch={value}");
if (value > 3)
{
value -= 0.2f;
// value -= 0.2f;
}
fishingRope.SetTargetLength(value);
}

View File

@@ -28,6 +28,9 @@ public class Rope : MonoBehaviour
[SerializeField, Range(1, 80), Tooltip("迭代次数。鱼线 10~30 通常够用")]
private int iterations = 20;
[SerializeField, Range(0, 16), Tooltip("主求解后追加的硬长度约束次数。只负责把 poly 拉回到 rest total不改变可变长度逻辑")]
private int hardTightenIterations = 2;
[Header("Length Control (No Min/Max Clamp)")]
[Tooltip("初始总长度(米)。如果为 0则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")]
[SerializeField, Min(0f)]
@@ -65,6 +68,9 @@ public class Rope : MonoBehaviour
[SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次地面约束")]
private int groundUpdateEvery = 2;
[SerializeField, Range(0, 8), Tooltip("地面约束后,再做几次长度约束,减少 poly 被地面抬长")]
private int groundPostConstraintIterations = 2;
private int _groundFrameCounter;
[Header("Simple Water Float (Cheap)")] [SerializeField, Tooltip("绳子落到水面以下时,是否把节点约束回水面")]
@@ -188,6 +194,7 @@ public class Rope : MonoBehaviour
renderSubdivisionsIdle = Mathf.Max(renderSubdivisionsIdle, 1);
renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1);
iterations = Mathf.Clamp(iterations, 1, 80);
hardTightenIterations = Mathf.Clamp(hardTightenIterations, 0, 16);
groundCastDistance = Mathf.Max(groundCastDistance, 0.01f);
groundCastHeight = Mathf.Max(groundCastHeight, 0f);
lineWidth = Mathf.Max(lineWidth, 0.0001f);
@@ -203,6 +210,7 @@ public class Rope : MonoBehaviour
groundSampleStep = Mathf.Max(1, groundSampleStep);
groundUpdateEvery = Mathf.Max(1, groundUpdateEvery);
groundPostConstraintIterations = Mathf.Clamp(groundPostConstraintIterations, 0, 8);
waterSampleStep = Mathf.Max(1, waterSampleStep);
waterUpdateEvery = Mathf.Max(1, waterUpdateEvery);
@@ -302,11 +310,27 @@ public class Rope : MonoBehaviour
public void DebugLength()
{
float solverRestTotal = (_physicsNodes - 2) * physicsSegmentLen + _headRestLen;
float poly = GetPhysicsPolylineLength();
float maxSegDelta = 0f;
float avgSegDelta = 0f;
for (int i = 1; i < _physicsNodes; i++)
{
float rest = (i == 1) ? _headRestLen : physicsSegmentLen;
float segLen = Vector3.Distance(_pCurr[i - 1], _pCurr[i]);
float delta = segLen - rest;
if (delta > maxSegDelta) maxSegDelta = delta;
avgSegDelta += delta;
}
if (_physicsNodes > 1)
avgSegDelta /= (_physicsNodes - 1);
Debug.Log(
$"current={_currentLength}, target={_targetLength}, nodes={_physicsNodes}, " +
$"seg={physicsSegmentLen}, head={_headRestLen}, headMin={headMinLen}, " +
$"solverRestTotal={(_physicsNodes - 2) * physicsSegmentLen + _headRestLen}, " +
$"poly={GetPhysicsPolylineLength()}"
$"solverRestTotal={solverRestTotal}, poly={poly}, delta={poly - solverRestTotal}, " +
$"maxSegDelta={maxSegDelta}, avgSegDelta={avgSegDelta}"
);
}
@@ -336,6 +360,7 @@ public class Rope : MonoBehaviour
SolveDistanceConstraints_HeadOnly_Fast();
}
SolveHardDistanceConstraints(hardTightenIterations);
LockAnchorsHard();
if (constrainToGround)
@@ -345,6 +370,7 @@ public class Rope : MonoBehaviour
{
_groundFrameCounter = 0;
ConstrainToGround();
SolveHardDistanceConstraints(groundPostConstraintIterations);
}
}
@@ -357,10 +383,7 @@ public class Rope : MonoBehaviour
ConstrainToWaterSurface();
// 水面抬升后补几次长度约束,让形状更顺一点
for (int it = 0; it < waterPostConstraintIterations; it++)
{
SolveDistanceConstraints_HeadOnly_Fast();
}
SolveHardDistanceConstraints(waterPostConstraintIterations);
}
}
@@ -522,9 +545,37 @@ public class Rope : MonoBehaviour
private void SolveDistanceConstraints_HeadOnly_Fast()
{
int last = _physicsNodes - 1;
SolveDistanceConstraints_HeadOnly_Bidirectional(stiffness);
}
for (int i = 0; i < last; i++)
private void SolveHardDistanceConstraints(int extraIterations)
{
for (int it = 0; it < extraIterations; it++)
{
LockAnchorsHard();
SolveDistanceConstraints_HeadOnly_Hard();
}
}
private void SolveDistanceConstraints_HeadOnly_Hard()
{
SolveDistanceConstraints_HeadOnly_Bidirectional(1f);
}
private void SolveDistanceConstraints_HeadOnly_Bidirectional(float combinedStiffness)
{
int last = _physicsNodes - 1;
if (last <= 0) return;
float clamped = Mathf.Clamp01(combinedStiffness);
float sweepStiffness = (clamped >= 0.999999f) ? 1f : 1f - Mathf.Sqrt(1f - clamped);
SolveDistanceConstraintsSweep_Fast(0, last, 1, last, sweepStiffness);
SolveDistanceConstraintsSweep_Fast(last - 1, -1, -1, last, sweepStiffness);
}
private void SolveDistanceConstraintsSweep_Fast(int start, int endExclusive, int step, int last, float sweepStiffness)
{
for (int i = start; i != endExclusive; i += step)
{
float rest = (i == 0) ? _headRestLen : physicsSegmentLen;
@@ -537,7 +588,7 @@ public class Rope : MonoBehaviour
float dist = Mathf.Sqrt(sq);
float diff = (dist - rest) / dist;
Vector3 corr = delta * (diff * stiffness);
Vector3 corr = delta * (diff * sweepStiffness);
bool aLocked = (i == 0);
bool bLocked = (i + 1 == last);
@@ -766,7 +817,8 @@ public class Rope : MonoBehaviour
(-p0 + 3f * p1 - 3f * p2 + p3) * t3
);
cr.y = p1.y + (p2.y - p1.y) * t;
// y 也使用平滑曲线,再做单调夹紧;避免垂直时因为线性 y 插值导致切线断裂,看起来像折线。
cr.y = ClampMonotonic(cr.y, p0.y, p1.y, p2.y, p3.y);
_rPoints[idx++] = cr;
}
@@ -778,6 +830,18 @@ public class Rope : MonoBehaviour
_lineRenderer.SetPositions(_rPoints);
}
private static float ClampMonotonic(float value, float p0, float p1, float p2, float p3)
{
bool rising = p0 <= p1 && p1 <= p2 && p2 <= p3;
bool falling = p0 >= p1 && p1 >= p2 && p2 >= p3;
if (!rising && !falling)
return value;
float min = Mathf.Min(p1, p2);
float max = Mathf.Max(p1, p2);
return Mathf.Clamp(value, min, max);
}
private int PickRenderSubdivisions_Fast()
{
int idle = Mathf.Max(1, renderSubdivisionsIdle);