diff --git a/Assets/Scenes/BobberTest.unity b/Assets/Scenes/BobberTest.unity index a019c98e1..33c187fc4 100644 --- a/Assets/Scenes/BobberTest.unity +++ b/Assets/Scenes/BobberTest.unity @@ -863,6 +863,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 06d107cece7c4cbb9825557923be567f, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::BuoyancyWaterProvider + Water: {fileID: 0} waterLevel: 0 --- !u!4 &820800910 Transform: @@ -3748,7 +3749,7 @@ RectTransform: m_Father: {fileID: 2256579932936496278} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0.2, y: 1} + m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} @@ -4552,7 +4553,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 0 + m_IsActive: 1 --- !u!1 &2575899344989503316 GameObject: m_ObjectHideFlags: 0 @@ -5308,8 +5309,8 @@ RectTransform: m_Children: [] m_Father: {fileID: 4262266657851529727} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.2, y: 0} - m_AnchorMax: {x: 0.2, y: 1} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 20, y: 0} m_Pivot: {x: 0.5, y: 0.5} @@ -6492,7 +6493,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f91c9d873c83492ca6d5e3e3a67c1760, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::CapsuleBuoyancyStable - WaterBehaviour: {fileID: 820800909} buoyancyScale: 1.6 samplePoints: 9 submergenceCurve: @@ -6526,6 +6526,9 @@ MonoBehaviour: uprightAxis: 1 extraDragInWater: 0.8 extraAngularDragInWater: 0.8 + Water: {fileID: 0} + _Layer: 1 + _ObjectWidth: 3 drawDebug: 0 --- !u!114 &7647511515837834160 MonoBehaviour: @@ -7303,7 +7306,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f91c9d873c83492ca6d5e3e3a67c1760, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::CapsuleBuoyancyStable - WaterBehaviour: {fileID: 820800909} buoyancyScale: 1.6 samplePoints: 9 submergenceCurve: @@ -7337,6 +7339,9 @@ MonoBehaviour: uprightAxis: 1 extraDragInWater: 0.8 extraAngularDragInWater: 0.8 + Water: {fileID: 2531380344179187550} + _Layer: 1 + _ObjectWidth: 0.2 drawDebug: 0 --- !u!153 &8264839114692736908 ConfigurableJoint: diff --git a/Assets/Scripts/Test/BuoyancyCapsuleSphere.cs b/Assets/Scripts/Test/BuoyancyCapsuleSphere.cs index fb75698f1..661d43614 100644 --- a/Assets/Scripts/Test/BuoyancyCapsuleSphere.cs +++ b/Assets/Scripts/Test/BuoyancyCapsuleSphere.cs @@ -6,219 +6,204 @@ public interface IWaterProvider Vector3 GetWaterNormal(Vector3 worldPos); Vector3 GetWaterVelocity(Vector3 worldPos); } - -/// -/// 稳定优先的浮力(只支持 CapsuleCollider / SphereCollider) -/// - 竖直方向:目标吃水深度 + PD 控制(稳定,不抖、不弹飞) -/// - 姿态:Righting Torque 扶正(受 Rigidbody.centerOfMass 影响) -/// - 入水比例:带平滑(避免水面附近开关抖动) -/// -[DisallowMultipleComponent] -[RequireComponent(typeof(Rigidbody))] -public class BuoyancyCapsuleSphere : MonoBehaviour -{ - [Header("Collider (choose one)")] - public CapsuleCollider capsule; - public SphereCollider sphere; - - [Header("Water")] - public MonoBehaviour waterProviderBehaviour; // 可选 - private IWaterProvider waterProvider; - - [Tooltip("没有 provider 时的水面高度")] - public float waterLevel = 0f; - - [Header("Density -> Draft")] - [Tooltip("水密度 kg/m^3(淡水约1000)")] - public float waterDensity = 1000f; - - [Tooltip("物体等效密度 kg/m^3。越小越浮。浮漂可 80~400 之间调")] - public float objectDensity = 250f; - - [Tooltip("额外浮力比例(手感调整)。1=按密度算")] - public float buoyancyScale = 1f; - - [Header("Vertical PD (Stability key)")] - [Tooltip("竖直弹簧强度(越大越“顶住”目标吃水)")] - public float verticalKp = 35f; - - [Tooltip("竖直阻尼(越大越不弹、不抖)")] - public float verticalKd = 12f; - - [Tooltip("最大向上加速度 m/s^2(防止从高处落下入水被顶飞)")] - public float maxUpAccel = 25f; - - [Tooltip("最大向下加速度 m/s^2(防止强行拉下去造成抖动)")] - public float maxDownAccel = 10f; - - [Header("Submergence smoothing")] - [Tooltip("入水比例变化速度(1/s)。越大越快响应,越小越稳")] - public float submergenceSpeed = 8f; - - [Tooltip("水面外的缓冲(m),让浮力更平滑接管")] - public float surfaceMargin = 0.01f; - - [Header("Righting (Rotation)")] - [Tooltip("扶正强度(把 transform.up 拉向水面法线/世界上)")] - public float rightingKp = 8f; - - [Tooltip("扶正阻尼(抑制旋转抖动)")] - public float rightingKd = 3f; - - [Header("Water drag (optional but helpful)")] - [Tooltip("入水时额外线阻尼(通过 rb.drag 混合)")] - public float extraLinearDragInWater = 2.5f; - - [Tooltip("入水时额外角阻尼(通过 rb.angularDrag 混合)")] - public float extraAngularDragInWater = 2.0f; - - [Header("Center of Mass")] - [Tooltip("本地重心偏移:例如 (0,-0.02,0) 让底部更重、更容易站漂")] - public Vector3 centerOfMassOffset = Vector3.zero; - - private Rigidbody rb; - private float baseDrag, baseAngularDrag; - - // 关键:入水比例必须有“记忆”(滤波),否则水面边界必抖 - private float subFiltered = 0f; - - void Reset() - { - rb = GetComponent(); - rb.useGravity = true; - rb.interpolation = RigidbodyInterpolation.Interpolate; - rb.collisionDetectionMode = CollisionDetectionMode.Continuous; - - capsule = GetComponent(); - sphere = GetComponent(); - } - - void Awake() - { - rb = GetComponent(); - rb.centerOfMass = centerOfMassOffset; - - baseDrag = rb.linearDamping; - baseAngularDrag = rb.angularDamping; - - waterProvider = waterProviderBehaviour as IWaterProvider; - - // 只允许一个 - if (capsule != null && sphere != null) - sphere = null; - } - - void OnValidate() - { - objectDensity = Mathf.Max(1e-3f, objectDensity); - waterDensity = Mathf.Max(1e-3f, waterDensity); - submergenceSpeed = Mathf.Max(0.1f, submergenceSpeed); - surfaceMargin = Mathf.Max(0f, surfaceMargin); - maxUpAccel = Mathf.Max(0f, maxUpAccel); - maxDownAccel = Mathf.Max(0f, maxDownAccel); - } - - void FixedUpdate() - { - if (!capsule && !sphere) return; - - waterProvider = waterProviderBehaviour as IWaterProvider; - - // 取“浮体中心点”作为控制点(稳定,不戳点) - Vector3 centerWorld; - float shapeHeight; // 近似“高度”(sphere=直径,capsule=高度) - GetCenterAndHeight(out centerWorld, out shapeHeight); - - // 水面信息 - float waterH = (waterProvider != null) ? waterProvider.GetWaterHeight(centerWorld) : waterLevel; - Vector3 waterN = (waterProvider != null) ? waterProvider.GetWaterNormal(centerWorld) : Vector3.up; - if (waterN.sqrMagnitude < 1e-6f) waterN = Vector3.up; - waterN.Normalize(); - - // 当前中心“浸没深度”(>0 表示中心在水下) - float centerDepth = waterH - centerWorld.y; - - // 近似入水比例:centerDepth = -H/2 -> 0; centerDepth = +H/2 -> 1 - float rawSub = Mathf.Clamp01((centerDepth + (shapeHeight * 0.5f) + surfaceMargin) / (shapeHeight + 2f * surfaceMargin)); - - // 入水比例滤波(非常关键) - float dt = Time.fixedDeltaTime; - subFiltered = Mathf.MoveTowards(subFiltered, rawSub, submergenceSpeed * dt); - - // 混合拖拽(让水中更稳) - rb.linearDamping = Mathf.Lerp(baseDrag, baseDrag + extraLinearDragInWater, subFiltered); - rb.angularDamping = Mathf.Lerp(baseAngularDrag, baseAngularDrag + extraAngularDragInWater, subFiltered); - - if (subFiltered <= 1e-4f) - return; // 基本没入水,不做任何浮力/扶正 - - // 目标吃水比例:理想静态平衡 ≈ objectDensity / waterDensity(<1 才会浮) - float desiredSub = Mathf.Clamp01((objectDensity / waterDensity) * buoyancyScale); - - // 把 desiredSub 转成目标中心深度 - // desiredSub=0 -> centerDepthTarget = -H/2(完全出水) - // desiredSub=1 -> centerDepthTarget = +H/2(完全入水) - float centerDepthTarget = desiredSub * shapeHeight - shapeHeight * 0.5f; - - // 竖直 PD:只沿“世界上/重力反方向”控制,最稳 - Vector3 up = (-Physics.gravity).sqrMagnitude > 1e-6f ? (-Physics.gravity).normalized : Vector3.up; - float vUp = Vector3.Dot(rb.linearVelocity, up); - - float error = centerDepth - centerDepthTarget; // 深了为正 -> 需要向上推 - float accelUp = (-verticalKp * error) - (verticalKd * vUp); - - // 限制上下加速度,避免顶飞或强拉抖动 - accelUp = Mathf.Clamp(accelUp, -maxDownAccel, maxUpAccel); - - // 随入水比例渐入(避免水面边界突然接管) - accelUp *= subFiltered; - - // 施加竖直加速度(Acceleration 不受质量影响,更稳定) - rb.AddForce(up * accelUp, ForceMode.Acceleration); - - // 扶正力矩:把物体 up 拉向 waterN(平静水就是 Vector3.up) - // 注意:这个扶正与重心偏移一起工作,会形成“站漂/躺漂”的稳定姿态 - Vector3 currentUp = transform.up; - Vector3 axis = Vector3.Cross(currentUp, waterN); - - // 小角度近似:axis 的大小约等于 sin(theta) - // 扶正加速度型扭矩(同样用 Acceleration,减少质量/惯量差带来的抖动) - Vector3 angVel = rb.angularVelocity; - Vector3 torqueAccel = axis * rightingKp - angVel * rightingKd; - - torqueAccel *= subFiltered; - - rb.AddTorque(torqueAccel, ForceMode.Acceleration); - } - - private void GetCenterAndHeight(out Vector3 centerWorld, out float heightWorld) - { - if (sphere) - { - // sphere:center + 半径*缩放(近似取最大缩放) - Transform t = sphere.transform; - centerWorld = t.TransformPoint(sphere.center); - - Vector3 s = t.lossyScale; - float r = sphere.radius * Mathf.Max(Mathf.Abs(s.x), Mathf.Abs(s.y), Mathf.Abs(s.z)); - heightWorld = Mathf.Max(1e-6f, r * 2f); - return; - } - - // capsule - Transform ct = capsule.transform; - centerWorld = ct.TransformPoint(capsule.center); - - Vector3 ls = ct.lossyScale; - float sx = Mathf.Abs(ls.x), sy = Mathf.Abs(ls.y), sz = Mathf.Abs(ls.z); - - float heightScale = capsule.direction switch - { - 0 => sx, - 1 => sy, - _ => sz, - }; - - heightWorld = Mathf.Max(1e-6f, capsule.height * heightScale); - } -} \ No newline at end of file +// +// /// +// /// 稳定优先的浮力(只支持 CapsuleCollider / SphereCollider) +// /// - 竖直方向:目标吃水深度 + PD 控制(稳定,不抖、不弹飞) +// /// - 姿态:Righting Torque 扶正(受 Rigidbody.centerOfMass 影响) +// /// - 入水比例:带平滑(避免水面附近开关抖动) +// /// +// [DisallowMultipleComponent] +// [RequireComponent(typeof(Rigidbody))] +// public class BuoyancyCapsuleSphere : MonoBehaviour +// { +// [Header("Collider (choose one)")] public CapsuleCollider capsule; +// public SphereCollider sphere; +// +// [Header("Water")] public MonoBehaviour waterProviderBehaviour; // 可选 +// private IWaterProvider waterProvider; +// +// [Tooltip("没有 provider 时的水面高度")] public float waterLevel = 0f; +// +// [Header("Density -> Draft")] [Tooltip("水密度 kg/m^3(淡水约1000)")] +// public float waterDensity = 1000f; +// +// [Tooltip("物体等效密度 kg/m^3。越小越浮。浮漂可 80~400 之间调")] +// public float objectDensity = 250f; +// +// [Tooltip("额外浮力比例(手感调整)。1=按密度算")] public float buoyancyScale = 1f; +// +// [Header("Vertical PD (Stability key)")] [Tooltip("竖直弹簧强度(越大越“顶住”目标吃水)")] +// public float verticalKp = 35f; +// +// [Tooltip("竖直阻尼(越大越不弹、不抖)")] public float verticalKd = 12f; +// +// [Tooltip("最大向上加速度 m/s^2(防止从高处落下入水被顶飞)")] +// public float maxUpAccel = 25f; +// +// [Tooltip("最大向下加速度 m/s^2(防止强行拉下去造成抖动)")] +// public float maxDownAccel = 10f; +// +// [Header("Submergence smoothing")] [Tooltip("入水比例变化速度(1/s)。越大越快响应,越小越稳")] +// public float submergenceSpeed = 8f; +// +// [Tooltip("水面外的缓冲(m),让浮力更平滑接管")] public float surfaceMargin = 0.01f; +// +// [Header("Righting (Rotation)")] [Tooltip("扶正强度(把 transform.up 拉向水面法线/世界上)")] +// public float rightingKp = 8f; +// +// [Tooltip("扶正阻尼(抑制旋转抖动)")] public float rightingKd = 3f; +// +// [Header("Water drag (optional but helpful)")] [Tooltip("入水时额外线阻尼(通过 rb.drag 混合)")] +// public float extraLinearDragInWater = 2.5f; +// +// [Tooltip("入水时额外角阻尼(通过 rb.angularDrag 混合)")] +// public float extraAngularDragInWater = 2.0f; +// +// [Header("Center of Mass")] [Tooltip("本地重心偏移:例如 (0,-0.02,0) 让底部更重、更容易站漂")] +// public Vector3 centerOfMassOffset = Vector3.zero; +// +// private Rigidbody rb; +// private float baseDrag, baseAngularDrag; +// +// // 关键:入水比例必须有“记忆”(滤波),否则水面边界必抖 +// private float subFiltered = 0f; +// +// void Reset() +// { +// rb = GetComponent(); +// rb.useGravity = true; +// rb.interpolation = RigidbodyInterpolation.Interpolate; +// rb.collisionDetectionMode = CollisionDetectionMode.Continuous; +// +// capsule = GetComponent(); +// sphere = GetComponent(); +// } +// +// void Awake() +// { +// rb = GetComponent(); +// rb.centerOfMass = centerOfMassOffset; +// +// baseDrag = rb.linearDamping; +// baseAngularDrag = rb.angularDamping; +// +// waterProvider = waterProviderBehaviour as IWaterProvider; +// +// // 只允许一个 +// if (capsule != null && sphere != null) +// sphere = null; +// } +// +// void OnValidate() +// { +// objectDensity = Mathf.Max(1e-3f, objectDensity); +// waterDensity = Mathf.Max(1e-3f, waterDensity); +// submergenceSpeed = Mathf.Max(0.1f, submergenceSpeed); +// surfaceMargin = Mathf.Max(0f, surfaceMargin); +// maxUpAccel = Mathf.Max(0f, maxUpAccel); +// maxDownAccel = Mathf.Max(0f, maxDownAccel); +// } +// +// void FixedUpdate() +// { +// if (!capsule && !sphere) return; +// +// waterProvider = waterProviderBehaviour as IWaterProvider; +// +// GetCenterAndHeight(out var centerWorld, out var shapeHeight); +// +// // 水面信息 +// float waterH = waterProvider?.GetWaterHeight(centerWorld) ?? waterLevel; +// Vector3 waterN = waterProvider?.GetWaterNormal(centerWorld) ?? Vector3.up; +// if (waterN.sqrMagnitude < 1e-6f) waterN = Vector3.up; +// waterN.Normalize(); +// +// // 当前中心“浸没深度”(>0 表示中心在水下) +// float centerDepth = waterH - centerWorld.y; +// +// // 近似入水比例:centerDepth = -H/2 -> 0; centerDepth = +H/2 -> 1 +// float rawSub = Mathf.Clamp01((centerDepth + (shapeHeight * 0.5f) + surfaceMargin) / +// (shapeHeight + 2f * surfaceMargin)); +// +// // 入水比例滤波(非常关键) +// float dt = Time.fixedDeltaTime; +// subFiltered = Mathf.MoveTowards(subFiltered, rawSub, submergenceSpeed * dt); +// +// // 混合拖拽(让水中更稳) +// rb.linearDamping = Mathf.Lerp(baseDrag, baseDrag + extraLinearDragInWater, subFiltered); +// rb.angularDamping = Mathf.Lerp(baseAngularDrag, baseAngularDrag + extraAngularDragInWater, subFiltered); +// +// if (subFiltered <= 1e-4f) +// return; // 基本没入水,不做任何浮力/扶正 +// +// // 目标吃水比例:理想静态平衡 ≈ objectDensity / waterDensity(<1 才会浮) +// float desiredSub = Mathf.Clamp01((objectDensity / waterDensity) * buoyancyScale); +// +// // 把 desiredSub 转成目标中心深度 +// // desiredSub=0 -> centerDepthTarget = -H/2(完全出水) +// // desiredSub=1 -> centerDepthTarget = +H/2(完全入水) +// float centerDepthTarget = desiredSub * shapeHeight - shapeHeight * 0.5f; +// +// // 竖直 PD:只沿“世界上/重力反方向”控制,最稳 +// Vector3 up = (-Physics.gravity).sqrMagnitude > 1e-6f ? (-Physics.gravity).normalized : Vector3.up; +// float vUp = Vector3.Dot(rb.linearVelocity, up); +// +// float error = centerDepth - centerDepthTarget; // 深了为正 -> 需要向上推 +// float accelUp = (-verticalKp * error) - (verticalKd * vUp); +// +// // 限制上下加速度,避免顶飞或强拉抖动 +// accelUp = Mathf.Clamp(accelUp, -maxDownAccel, maxUpAccel); +// +// // 随入水比例渐入(避免水面边界突然接管) +// accelUp *= subFiltered; +// +// // 施加竖直加速度(Acceleration 不受质量影响,更稳定) +// rb.AddForce(up * accelUp, ForceMode.Acceleration); +// +// // 扶正力矩:把物体 up 拉向 waterN(平静水就是 Vector3.up) +// // 注意:这个扶正与重心偏移一起工作,会形成“站漂/躺漂”的稳定姿态 +// Vector3 currentUp = transform.up; +// Vector3 axis = Vector3.Cross(currentUp, waterN); +// +// // 小角度近似:axis 的大小约等于 sin(theta) +// // 扶正加速度型扭矩(同样用 Acceleration,减少质量/惯量差带来的抖动) +// Vector3 angVel = rb.angularVelocity; +// Vector3 torqueAccel = axis * rightingKp - angVel * rightingKd; +// +// torqueAccel *= subFiltered; +// +// rb.AddTorque(torqueAccel, ForceMode.Acceleration); +// } +// +// private void GetCenterAndHeight(out Vector3 centerWorld, out float heightWorld) +// { +// if (sphere) +// { +// // sphere:center + 半径*缩放(近似取最大缩放) +// Transform t = sphere.transform; +// centerWorld = t.TransformPoint(sphere.center); +// +// Vector3 s = t.lossyScale; +// float r = sphere.radius * Mathf.Max(Mathf.Abs(s.x), Mathf.Abs(s.y), Mathf.Abs(s.z)); +// heightWorld = Mathf.Max(1e-6f, r * 2f); +// return; +// } +// +// // capsule +// Transform ct = capsule.transform; +// centerWorld = ct.TransformPoint(capsule.center); +// +// Vector3 ls = ct.lossyScale; +// float sx = Mathf.Abs(ls.x), sy = Mathf.Abs(ls.y), sz = Mathf.Abs(ls.z); +// +// float heightScale = capsule.direction switch +// { +// 0 => sx, +// 1 => sy, +// _ => sz, +// }; +// +// heightWorld = Mathf.Max(1e-6f, capsule.height * heightScale); +// } +// } \ No newline at end of file diff --git a/Assets/Scripts/Test/BuoyancyWaterProvider.cs b/Assets/Scripts/Test/BuoyancyWaterProvider.cs index 0d41fd8f6..f4af21b5f 100644 --- a/Assets/Scripts/Test/BuoyancyWaterProvider.cs +++ b/Assets/Scripts/Test/BuoyancyWaterProvider.cs @@ -1,7 +1,10 @@ using UnityEngine; +using WaveHarmonic.Crest; public class BuoyancyWaterProvider : MonoBehaviour, IWaterProvider { + public WaterRenderer Water; + readonly SampleFlowHelper _SampleFlowHelper = new(); public float waterLevel = 0f; public float GetWaterHeight(Vector3 worldPos) diff --git a/Assets/Scripts/Test/CapsuleBuoyancyStable.cs b/Assets/Scripts/Test/CapsuleBuoyancyStable.cs index 5f8cb469c..a5d152043 100644 --- a/Assets/Scripts/Test/CapsuleBuoyancyStable.cs +++ b/Assets/Scripts/Test/CapsuleBuoyancyStable.cs @@ -1,46 +1,62 @@ -using UnityEngine; +using System; +using Gaia; +using UnityEngine; +using WaveHarmonic.Crest; [DisallowMultipleComponent] [RequireComponent(typeof(Rigidbody), typeof(CapsuleCollider))] public class CapsuleBuoyancyStable : MonoBehaviour { - [Header("References")] - public MonoBehaviour WaterBehaviour; // 实现 IWaterProvider - private IWaterProvider Water => WaterBehaviour as IWaterProvider; - - [Header("Buoyancy")] - [Tooltip("完全浸没时总浮力 = mass*g*buoyancyScale。>1 更浮。")] + [Header("Buoyancy")] [Tooltip("完全浸没时总浮力 = mass*g*buoyancyScale。>1 更浮。")] public float buoyancyScale = 1.6f; - [Tooltip("沿胶囊轴向采样点数量(建议 7~11)。")] - [Range(3, 15)] public int samplePoints = 9; + [Tooltip("沿胶囊轴向采样点数量(建议 7~11)。")] [Range(3, 15)] + public int samplePoints = 9; - [Tooltip("浸没比例曲线(0=刚碰水, 1=充分在水下)。")] - public AnimationCurve submergenceCurve = AnimationCurve.Linear(0, 0, 1, 1); + [Tooltip("浸没比例曲线(0=刚碰水, 1=充分在水下)。")] public AnimationCurve submergenceCurve = AnimationCurve.Linear(0, 0, 1, 1); - [Header("Damping")] - [Tooltip("上浮方向速度阻尼(越大越不弹)。")] + [Header("Damping")] [Tooltip("上浮方向速度阻尼(越大越不弹)。")] public float verticalDamping = 3.0f; - [Tooltip("整体角速度阻尼(只施加一次,不要太大)。")] - public float angularDamping = 0.6f; + [Tooltip("整体角速度阻尼(只施加一次,不要太大)。")] public float angularDamping = 0.6f; - [Header("Optional Upright Stabilizer (Recommended for bobber)")] - [Tooltip("让胶囊轴向更倾向于对齐世界Up。0=关闭。")] + [Header("Optional Upright Stabilizer (Recommended for bobber)")] [Tooltip("让胶囊轴向更倾向于对齐世界Up。0=关闭。")] public float uprightSpring = 0.0f; - [Tooltip("upright 的角速度阻尼。")] - public float uprightDamping = 0.5f; + [Tooltip("upright 的角速度阻尼。")] public float uprightDamping = 0.5f; [Tooltip("胶囊轴向:0=X,1=Y,2=Z(通常 CapsuleCollider.direction 也一样)。")] public int uprightAxis = 1; - [Header("Water Drag")] - public float extraDragInWater = 0.8f; + [Header("Water Drag")] public float extraDragInWater = 0.8f; public float extraAngularDragInWater = 0.8f; - [Header("Debug")] - public bool drawDebug = false; + #region Crest5相关信息 + + public Transform Water; + + private WaterRenderer _waterRenderer; + + [Tooltip("要瞄准哪一层水的碰撞层。")] [SerializeField] + CollisionLayer _Layer = CollisionLayer.AfterAnimatedWaves; + + [Header("波响应")] [Tooltip("用于物理计算的物体宽度。\n\n此值越大,波响应的滤波效果和平滑程度就越高。如果无法对较大波长进行滤波,则应增加 LOD 级别。")] [SerializeField] + float _ObjectWidth = 3f; + + readonly SampleFlowHelper _SampleFlowHelper = new(); + + /// + /// 查询水面信息点位 + /// + Vector3[] _QueryPoints; + + Vector3[] _QueryResultDisplacements; + Vector3[] _QueryResultVelocities; + Vector3[] _QueryResultNormal; + + #endregion + + [Header("Debug")] public bool drawDebug = false; Rigidbody _rb; CapsuleCollider _cap; @@ -52,15 +68,30 @@ public class CapsuleBuoyancyStable : MonoBehaviour _cap = GetComponent(); _baseDrag = _rb.linearDamping; _baseAngularDrag = _rb.angularDamping; + } - if (WaterBehaviour != null && Water == null) - Debug.LogError($"{name}: WaterBehaviour 没有实现 IWaterProvider。", this); + private void Start() + { + int length = Mathf.Max(3, samplePoints); + _QueryPoints = new Vector3[length]; + _QueryResultDisplacements = new Vector3[length]; + _QueryResultVelocities = new Vector3[length]; + _QueryResultNormal = new Vector3[length]; + if(Water) + _waterRenderer = Water.GetComponent(); } void FixedUpdate() { - if (Water == null) return; + if (Water) + { + + } + if (!_waterRenderer) + { + return; + } GetWorldCapsule(out Vector3 a, out Vector3 b, out float radius); int n = Mathf.Max(3, samplePoints); @@ -70,12 +101,27 @@ public class CapsuleBuoyancyStable : MonoBehaviour float subSum = 0f; int wetCount = 0; + for (int i = 0; i < _QueryPoints.Length; i++) + { + float t = (float)i / (n - 1); + Vector3 p = Vector3.Lerp(a, b, t); + _QueryPoints[i] = p; + } + + + // 查询 + var collisions = _waterRenderer.AnimatedWavesLod.Provider; + collisions.Query(GetHashCode(), _ObjectWidth, _QueryPoints, _QueryResultDisplacements, + _QueryResultNormal, _QueryResultVelocities, _Layer); + + for (int i = 0; i < n; i++) { float t = (float)i / (n - 1); Vector3 p = Vector3.Lerp(a, b, t); - float waterH = Water.GetWaterHeight(p); + float waterH = + _QueryResultDisplacements[i].y + _waterRenderer.SeaLevel; //GaiaConstants.Water.GetWaterHeight(p); float depth = waterH - p.y; // >0 在水下 float sub = Mathf.InverseLerp(-radius, radius, depth); // 0..1 @@ -87,7 +133,8 @@ public class CapsuleBuoyancyStable : MonoBehaviour Vector3 buoyDir = Vector3.up; - Vector3 waterVel = Water.GetWaterVelocity(p); + // Vector3 waterVel = GaiaConstants.Water.GetWaterVelocity(p); + Vector3 waterVel = _QueryResultVelocities[i]; Vector3 pointVel = _rb.GetPointVelocity(p); Vector3 relVel = pointVel - waterVel; @@ -184,8 +231,8 @@ public class CapsuleBuoyancyStable : MonoBehaviour a = center - half; b = center + half; } - - + + private void OnDrawGizmosSelected() { if (drawDebug)