提交线修改
This commit is contained in:
@@ -119,7 +119,7 @@ namespace NBF
|
|||||||
Log.Error($"SetObiRopeStretch={value}");
|
Log.Error($"SetObiRopeStretch={value}");
|
||||||
if (value > 3)
|
if (value > 3)
|
||||||
{
|
{
|
||||||
value -= 0.2f;
|
// value -= 0.2f;
|
||||||
}
|
}
|
||||||
fishingRope.SetTargetLength(value);
|
fishingRope.SetTargetLength(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ public class Rope : MonoBehaviour
|
|||||||
[SerializeField, Range(1, 80), Tooltip("迭代次数。鱼线 10~30 通常够用")]
|
[SerializeField, Range(1, 80), Tooltip("迭代次数。鱼线 10~30 通常够用")]
|
||||||
private int iterations = 20;
|
private int iterations = 20;
|
||||||
|
|
||||||
|
[SerializeField, Range(0, 16), Tooltip("主求解后追加的硬长度约束次数。只负责把 poly 拉回到 rest total,不改变可变长度逻辑")]
|
||||||
|
private int hardTightenIterations = 2;
|
||||||
|
|
||||||
[Header("Length Control (No Min/Max Clamp)")]
|
[Header("Length Control (No Min/Max Clamp)")]
|
||||||
[Tooltip("初始总长度(米)。如果为 0,则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")]
|
[Tooltip("初始总长度(米)。如果为 0,则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")]
|
||||||
[SerializeField, Min(0f)]
|
[SerializeField, Min(0f)]
|
||||||
@@ -65,6 +68,9 @@ public class Rope : MonoBehaviour
|
|||||||
[SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次地面约束")]
|
[SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次地面约束")]
|
||||||
private int groundUpdateEvery = 2;
|
private int groundUpdateEvery = 2;
|
||||||
|
|
||||||
|
[SerializeField, Range(0, 8), Tooltip("地面约束后,再做几次长度约束,减少 poly 被地面抬长")]
|
||||||
|
private int groundPostConstraintIterations = 2;
|
||||||
|
|
||||||
private int _groundFrameCounter;
|
private int _groundFrameCounter;
|
||||||
|
|
||||||
[Header("Simple Water Float (Cheap)")] [SerializeField, Tooltip("绳子落到水面以下时,是否把节点约束回水面")]
|
[Header("Simple Water Float (Cheap)")] [SerializeField, Tooltip("绳子落到水面以下时,是否把节点约束回水面")]
|
||||||
@@ -188,6 +194,7 @@ public class Rope : MonoBehaviour
|
|||||||
renderSubdivisionsIdle = Mathf.Max(renderSubdivisionsIdle, 1);
|
renderSubdivisionsIdle = Mathf.Max(renderSubdivisionsIdle, 1);
|
||||||
renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1);
|
renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1);
|
||||||
iterations = Mathf.Clamp(iterations, 1, 80);
|
iterations = Mathf.Clamp(iterations, 1, 80);
|
||||||
|
hardTightenIterations = Mathf.Clamp(hardTightenIterations, 0, 16);
|
||||||
groundCastDistance = Mathf.Max(groundCastDistance, 0.01f);
|
groundCastDistance = Mathf.Max(groundCastDistance, 0.01f);
|
||||||
groundCastHeight = Mathf.Max(groundCastHeight, 0f);
|
groundCastHeight = Mathf.Max(groundCastHeight, 0f);
|
||||||
lineWidth = Mathf.Max(lineWidth, 0.0001f);
|
lineWidth = Mathf.Max(lineWidth, 0.0001f);
|
||||||
@@ -203,6 +210,7 @@ public class Rope : MonoBehaviour
|
|||||||
|
|
||||||
groundSampleStep = Mathf.Max(1, groundSampleStep);
|
groundSampleStep = Mathf.Max(1, groundSampleStep);
|
||||||
groundUpdateEvery = Mathf.Max(1, groundUpdateEvery);
|
groundUpdateEvery = Mathf.Max(1, groundUpdateEvery);
|
||||||
|
groundPostConstraintIterations = Mathf.Clamp(groundPostConstraintIterations, 0, 8);
|
||||||
|
|
||||||
waterSampleStep = Mathf.Max(1, waterSampleStep);
|
waterSampleStep = Mathf.Max(1, waterSampleStep);
|
||||||
waterUpdateEvery = Mathf.Max(1, waterUpdateEvery);
|
waterUpdateEvery = Mathf.Max(1, waterUpdateEvery);
|
||||||
@@ -302,11 +310,27 @@ public class Rope : MonoBehaviour
|
|||||||
|
|
||||||
public void DebugLength()
|
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(
|
Debug.Log(
|
||||||
$"current={_currentLength}, target={_targetLength}, nodes={_physicsNodes}, " +
|
$"current={_currentLength}, target={_targetLength}, nodes={_physicsNodes}, " +
|
||||||
$"seg={physicsSegmentLen}, head={_headRestLen}, headMin={headMinLen}, " +
|
$"seg={physicsSegmentLen}, head={_headRestLen}, headMin={headMinLen}, " +
|
||||||
$"solverRestTotal={(_physicsNodes - 2) * physicsSegmentLen + _headRestLen}, " +
|
$"solverRestTotal={solverRestTotal}, poly={poly}, delta={poly - solverRestTotal}, " +
|
||||||
$"poly={GetPhysicsPolylineLength()}"
|
$"maxSegDelta={maxSegDelta}, avgSegDelta={avgSegDelta}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,6 +360,7 @@ public class Rope : MonoBehaviour
|
|||||||
SolveDistanceConstraints_HeadOnly_Fast();
|
SolveDistanceConstraints_HeadOnly_Fast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SolveHardDistanceConstraints(hardTightenIterations);
|
||||||
LockAnchorsHard();
|
LockAnchorsHard();
|
||||||
|
|
||||||
if (constrainToGround)
|
if (constrainToGround)
|
||||||
@@ -345,6 +370,7 @@ public class Rope : MonoBehaviour
|
|||||||
{
|
{
|
||||||
_groundFrameCounter = 0;
|
_groundFrameCounter = 0;
|
||||||
ConstrainToGround();
|
ConstrainToGround();
|
||||||
|
SolveHardDistanceConstraints(groundPostConstraintIterations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,10 +383,7 @@ public class Rope : MonoBehaviour
|
|||||||
ConstrainToWaterSurface();
|
ConstrainToWaterSurface();
|
||||||
|
|
||||||
// 水面抬升后补几次长度约束,让形状更顺一点
|
// 水面抬升后补几次长度约束,让形状更顺一点
|
||||||
for (int it = 0; it < waterPostConstraintIterations; it++)
|
SolveHardDistanceConstraints(waterPostConstraintIterations);
|
||||||
{
|
|
||||||
SolveDistanceConstraints_HeadOnly_Fast();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,9 +545,37 @@ public class Rope : MonoBehaviour
|
|||||||
|
|
||||||
private void SolveDistanceConstraints_HeadOnly_Fast()
|
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;
|
float rest = (i == 0) ? _headRestLen : physicsSegmentLen;
|
||||||
|
|
||||||
@@ -537,7 +588,7 @@ public class Rope : MonoBehaviour
|
|||||||
|
|
||||||
float dist = Mathf.Sqrt(sq);
|
float dist = Mathf.Sqrt(sq);
|
||||||
float diff = (dist - rest) / dist;
|
float diff = (dist - rest) / dist;
|
||||||
Vector3 corr = delta * (diff * stiffness);
|
Vector3 corr = delta * (diff * sweepStiffness);
|
||||||
|
|
||||||
bool aLocked = (i == 0);
|
bool aLocked = (i == 0);
|
||||||
bool bLocked = (i + 1 == last);
|
bool bLocked = (i + 1 == last);
|
||||||
@@ -766,7 +817,8 @@ public class Rope : MonoBehaviour
|
|||||||
(-p0 + 3f * p1 - 3f * p2 + p3) * t3
|
(-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;
|
_rPoints[idx++] = cr;
|
||||||
}
|
}
|
||||||
@@ -778,6 +830,18 @@ public class Rope : MonoBehaviour
|
|||||||
_lineRenderer.SetPositions(_rPoints);
|
_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()
|
private int PickRenderSubdivisions_Fast()
|
||||||
{
|
{
|
||||||
int idle = Mathf.Max(1, renderSubdivisionsIdle);
|
int idle = Mathf.Max(1, renderSubdivisionsIdle);
|
||||||
|
|||||||
Reference in New Issue
Block a user