修改鱼线逻辑
This commit is contained in:
@@ -116,6 +116,18 @@ public class Rope : MonoBehaviour
|
|||||||
|
|
||||||
[SerializeField, Min(0.0001f)] private float lineWidth = 0.001f;
|
[SerializeField, Min(0.0001f)] private float lineWidth = 0.001f;
|
||||||
|
|
||||||
|
[Header("Performance")] [SerializeField, Tooltip("远端玩家鱼线不可见时,直接停止整条渲染线的模拟与绘制")]
|
||||||
|
private bool cullRemoteRopeWhenInvisible = true;
|
||||||
|
|
||||||
|
[SerializeField, Tooltip("本地玩家自己的鱼线始终保持完整计算")]
|
||||||
|
private bool localOwnerAlwaysSimulate = true;
|
||||||
|
|
||||||
|
[SerializeField, Range(1, 60), Tooltip("每隔多少个 FixedUpdate 重新判断一次可见性")]
|
||||||
|
private int visibilityCheckEvery = 10;
|
||||||
|
|
||||||
|
[SerializeField, Range(0f, 0.5f), Tooltip("屏幕边缘额外留白,避免刚进视野就闪现")]
|
||||||
|
private float visibilityViewportPadding = 0.08f;
|
||||||
|
|
||||||
[Header("Air Drag (Stable)")] [SerializeField, Range(0f, 5f), Tooltip("空气阻力(Y向),指数衰减,越大越不飘")]
|
[Header("Air Drag (Stable)")] [SerializeField, Range(0f, 5f), Tooltip("空气阻力(Y向),指数衰减,越大越不飘")]
|
||||||
private float airDrag = 0.9f;
|
private float airDrag = 0.9f;
|
||||||
|
|
||||||
@@ -155,9 +167,19 @@ public class Rope : MonoBehaviour
|
|||||||
private float _dt2;
|
private float _dt2;
|
||||||
private float _kY;
|
private float _kY;
|
||||||
private float _kXZ;
|
private float _kXZ;
|
||||||
|
private Transform _cameraTr;
|
||||||
|
private int _visibilityCheckCounter;
|
||||||
|
private bool _isCulledByVisibility;
|
||||||
|
private int _tIdleSubdiv = -1;
|
||||||
|
private int _tMovingSubdiv = -1;
|
||||||
|
|
||||||
private FRod _rod;
|
private FRod _rod;
|
||||||
public void Init(FRod rod) => _rod = rod;
|
public void Init(FRod rod)
|
||||||
|
{
|
||||||
|
_rod = rod;
|
||||||
|
if (Application.isPlaying)
|
||||||
|
RefreshVisibilityState(true);
|
||||||
|
}
|
||||||
|
|
||||||
// Catmull t caches(只缓存 idle/moving 两档,减少每帧重复乘法)
|
// Catmull t caches(只缓存 idle/moving 两档,减少每帧重复乘法)
|
||||||
private struct TCaches
|
private struct TCaches
|
||||||
@@ -175,18 +197,12 @@ public class Rope : MonoBehaviour
|
|||||||
_lineRenderer = GetComponent<LineRenderer>();
|
_lineRenderer = GetComponent<LineRenderer>();
|
||||||
_gravity = new Vector3(0f, -gravityStrength, 0f);
|
_gravity = new Vector3(0f, -gravityStrength, 0f);
|
||||||
|
|
||||||
_startTr = startAnchor ? startAnchor.transform : null;
|
RefreshAnchorTransforms();
|
||||||
_endTr = endAnchor ? endAnchor.transform : null;
|
|
||||||
|
|
||||||
InitLengthSystem();
|
InitLengthSystem();
|
||||||
AllocateAndInitNodes();
|
AllocateAndInitNodes();
|
||||||
|
EnsureRenderCaches();
|
||||||
int maxSubdiv = Mathf.Max(1, renderSubdivisionsIdle);
|
RefreshVisibilityState(true);
|
||||||
_rCapacity = (maxPhysicsNodes - 1) * maxSubdiv + 1;
|
|
||||||
_rPoints = new Vector3[_rCapacity];
|
|
||||||
|
|
||||||
BuildTCaches(renderSubdivisionsIdle, ref _tIdle);
|
|
||||||
BuildTCaches(renderSubdivisionsMoving, ref _tMoving);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnValidate()
|
private void OnValidate()
|
||||||
@@ -217,6 +233,153 @@ public class Rope : MonoBehaviour
|
|||||||
waterSurfaceOffset = Mathf.Max(0f, waterSurfaceOffset);
|
waterSurfaceOffset = Mathf.Max(0f, waterSurfaceOffset);
|
||||||
waterLiftStrength = Mathf.Clamp01(waterLiftStrength);
|
waterLiftStrength = Mathf.Clamp01(waterLiftStrength);
|
||||||
waterPostConstraintIterations = Mathf.Clamp(waterPostConstraintIterations, 0, 8);
|
waterPostConstraintIterations = Mathf.Clamp(waterPostConstraintIterations, 0, 8);
|
||||||
|
visibilityCheckEvery = Mathf.Clamp(visibilityCheckEvery, 1, 60);
|
||||||
|
visibilityViewportPadding = Mathf.Clamp(visibilityViewportPadding, 0f, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshAnchorTransforms()
|
||||||
|
{
|
||||||
|
_startTr = startAnchor ? startAnchor.transform : null;
|
||||||
|
_endTr = endAnchor ? endAnchor.transform : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShouldAlwaysSimulate()
|
||||||
|
{
|
||||||
|
if (!localOwnerAlwaysSimulate)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var owner = _rod?.PlayerItem?.Owner;
|
||||||
|
return owner == null || owner.IsSelf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Transform GetActiveCameraTransform()
|
||||||
|
{
|
||||||
|
Camera main = BaseCamera.Main;
|
||||||
|
if (main)
|
||||||
|
{
|
||||||
|
_cameraTr = main.transform;
|
||||||
|
return _cameraTr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_cameraTr)
|
||||||
|
{
|
||||||
|
Camera fallback = Camera.main;
|
||||||
|
if (fallback)
|
||||||
|
_cameraTr = fallback.transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cameraTr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsViewportPointVisible(Vector3 viewportPoint, float padding)
|
||||||
|
{
|
||||||
|
if (viewportPoint.z <= 0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return viewportPoint.x >= -padding && viewportPoint.x <= 1f + padding &&
|
||||||
|
viewportPoint.y >= -padding && viewportPoint.y <= 1f + padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsVisibleToMainCamera()
|
||||||
|
{
|
||||||
|
Transform camTr = GetActiveCameraTransform();
|
||||||
|
if (!camTr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Camera cam = camTr.GetComponent<Camera>();
|
||||||
|
if (!cam)
|
||||||
|
cam = BaseCamera.Main ? BaseCamera.Main : Camera.main;
|
||||||
|
if (!cam)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Vector3 start = _startTr ? _startTr.position : (startAnchor ? startAnchor.position : transform.position);
|
||||||
|
Vector3 end = _endTr ? _endTr.position : (endAnchor ? endAnchor.position : transform.position);
|
||||||
|
Vector3 middle = (start + end) * 0.5f;
|
||||||
|
float padding = visibilityViewportPadding;
|
||||||
|
|
||||||
|
return IsViewportPointVisible(cam.WorldToViewportPoint(start), padding) ||
|
||||||
|
IsViewportPointVisible(cam.WorldToViewportPoint(end), padding) ||
|
||||||
|
IsViewportPointVisible(cam.WorldToViewportPoint(middle), padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshVisibilityState(bool force = false)
|
||||||
|
{
|
||||||
|
if (!cullRemoteRopeWhenInvisible || ShouldAlwaysSimulate())
|
||||||
|
{
|
||||||
|
_isCulledByVisibility = false;
|
||||||
|
if (_lineRenderer)
|
||||||
|
_lineRenderer.enabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!force)
|
||||||
|
{
|
||||||
|
_visibilityCheckCounter++;
|
||||||
|
if (_visibilityCheckCounter < visibilityCheckEvery)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_visibilityCheckCounter = 0;
|
||||||
|
bool wasCulled = _isCulledByVisibility;
|
||||||
|
_isCulledByVisibility = !IsVisibleToMainCamera();
|
||||||
|
|
||||||
|
if (_lineRenderer)
|
||||||
|
_lineRenderer.enabled = !_isCulledByVisibility;
|
||||||
|
|
||||||
|
if (wasCulled && !_isCulledByVisibility)
|
||||||
|
SyncVisibleStateAfterCulling();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncVisibleStateAfterCulling()
|
||||||
|
{
|
||||||
|
_currentLength = Mathf.Max(_targetLength, 0.01f);
|
||||||
|
UpdateNodesFromLength();
|
||||||
|
UpdateHeadRestLenFromCurrentLength();
|
||||||
|
ResetNodesBetweenAnchors();
|
||||||
|
LockAnchorsHard();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetNodesBetweenAnchors()
|
||||||
|
{
|
||||||
|
if (_physicsNodes < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3 start = _startTr ? _startTr.position : (startAnchor ? startAnchor.position : transform.position);
|
||||||
|
Vector3 end = _endTr ? _endTr.position : (endAnchor ? endAnchor.position : transform.position);
|
||||||
|
int last = _physicsNodes - 1;
|
||||||
|
|
||||||
|
for (int i = 0; i <= last; i++)
|
||||||
|
{
|
||||||
|
float t = (last > 0) ? i / (float)last : 0f;
|
||||||
|
Vector3 pos = Vector3.Lerp(start, end, t);
|
||||||
|
_pCurr[i] = pos;
|
||||||
|
_pPrev[i] = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureRenderCaches()
|
||||||
|
{
|
||||||
|
int idle = Mathf.Max(1, renderSubdivisionsIdle);
|
||||||
|
if (_tIdleSubdiv != idle)
|
||||||
|
{
|
||||||
|
BuildTCaches(idle, ref _tIdle);
|
||||||
|
_tIdleSubdiv = idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int moving = Mathf.Max(1, renderSubdivisionsMoving);
|
||||||
|
if (_tMovingSubdiv != moving)
|
||||||
|
{
|
||||||
|
BuildTCaches(moving, ref _tMoving);
|
||||||
|
_tMovingSubdiv = moving;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxSubdiv = Mathf.Max(idle, moving);
|
||||||
|
int neededCapacity = (maxPhysicsNodes - 1) * maxSubdiv + 1;
|
||||||
|
if (_rPoints == null || neededCapacity > _rCapacity)
|
||||||
|
{
|
||||||
|
_rCapacity = neededCapacity;
|
||||||
|
_rPoints = new Vector3[_rCapacity];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitLengthSystem()
|
private void InitLengthSystem()
|
||||||
@@ -284,6 +447,9 @@ public class Rope : MonoBehaviour
|
|||||||
|
|
||||||
public float GetLengthByPoints()
|
public float GetLengthByPoints()
|
||||||
{
|
{
|
||||||
|
if (!smooth)
|
||||||
|
return GetPhysicsPolylineLength();
|
||||||
|
|
||||||
if (_rPoints == null || _lineRenderer == null) return 0f;
|
if (_rPoints == null || _lineRenderer == null) return 0f;
|
||||||
|
|
||||||
int count = _lineRenderer.positionCount;
|
int count = _lineRenderer.positionCount;
|
||||||
@@ -338,6 +504,11 @@ public class Rope : MonoBehaviour
|
|||||||
{
|
{
|
||||||
if (!startAnchor || !endAnchor) return;
|
if (!startAnchor || !endAnchor) return;
|
||||||
|
|
||||||
|
RefreshAnchorTransforms();
|
||||||
|
RefreshVisibilityState();
|
||||||
|
if (_isCulledByVisibility)
|
||||||
|
return;
|
||||||
|
|
||||||
_dt = Time.fixedDeltaTime;
|
_dt = Time.fixedDeltaTime;
|
||||||
if (_dt < 1e-6f) _dt = 1e-6f;
|
if (_dt < 1e-6f) _dt = 1e-6f;
|
||||||
_dt2 = _dt * _dt;
|
_dt2 = _dt * _dt;
|
||||||
@@ -394,6 +565,12 @@ public class Rope : MonoBehaviour
|
|||||||
{
|
{
|
||||||
if (!startAnchor || !endAnchor || _pCurr == null || _physicsNodes < 2) return;
|
if (!startAnchor || !endAnchor || _pCurr == null || _physicsNodes < 2) return;
|
||||||
|
|
||||||
|
RefreshAnchorTransforms();
|
||||||
|
if (_isCulledByVisibility)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EnsureRenderCaches();
|
||||||
|
|
||||||
int last = _physicsNodes - 1;
|
int last = _physicsNodes - 1;
|
||||||
|
|
||||||
Vector3 s = _startTr.position;
|
Vector3 s = _startTr.position;
|
||||||
|
|||||||
Reference in New Issue
Block a user