From ca3cdb89ab21900fd48dfa483b2040d1edab4234 Mon Sep 17 00:00:00 2001 From: Danny Whittaker Date: Mon, 12 Dec 2022 23:18:21 +0000 Subject: [PATCH 1/5] Make Buoyant objects update on FixedUpdate if that's where they're doing the work. Also fixed up the Buoyant editor so it uses consistent foldouts and doesn't show unnecessary stuff in Editor. --- Editor/BuoyantObjectEditor.cs | 29 ++++++----- Runtime/Materials/UnlitDebug.mat | 2 +- Runtime/Physics/BuoyantObject.cs | 87 ++++++++++++++++++-------------- 3 files changed, 67 insertions(+), 51 deletions(-) diff --git a/Editor/BuoyantObjectEditor.cs b/Editor/BuoyantObjectEditor.cs index e8093c2..64c15b5 100644 --- a/Editor/BuoyantObjectEditor.cs +++ b/Editor/BuoyantObjectEditor.cs @@ -7,32 +7,38 @@ namespace WaterSystem.Physics [CustomEditor(typeof(BuoyantObject))] public class BuoyantObjectEditor : Editor { - private BuoyantObject obj; + private BuoyantObject Obj => serializedObject.targetObject as BuoyantObject; + [SerializeField] private bool _heightsDebugBool; + [SerializeField] private bool _generalSettingsBool; - private void OnEnable() - { - obj = serializedObject.targetObject as BuoyantObject; - } - public override void OnInspectorGUI() { - _generalSettingsBool = EditorGUILayout.Foldout(_generalSettingsBool, "General Settings"); + if (!EditorApplication.isPlaying) + { + base.OnInspectorGUI(); + return; + } + + _generalSettingsBool = EditorGUILayout.BeginFoldoutHeaderGroup(_generalSettingsBool, "General Settings"); + EditorGUILayout.EndFoldoutHeaderGroup(); if (_generalSettingsBool) { base.OnInspectorGUI(); } - if (EditorGUILayout.BeginFoldoutHeaderGroup(_heightsDebugBool, "Height Debug Values")) + _heightsDebugBool = EditorGUILayout.BeginFoldoutHeaderGroup(_heightsDebugBool, "Height Debug Values"); + EditorGUILayout.EndFoldoutHeaderGroup(); + if (_heightsDebugBool) { - if (obj.Heights != null) + if (Obj.Heights != null) { - for (var i = 0; i < obj.Heights.Length; i++) + for (var i = 0; i < Obj.Heights.Length; i++) { - var h = obj.Heights[i]; + var h = Obj.Heights[i]; EditorGUILayout.LabelField($"{i})Wave(heights):", $"X:{h.x:00.00} Y:{h.y:00.00} Z:{h.z:00.00}"); } } @@ -41,7 +47,6 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("Height debug info only available in playmode.", MessageType.Info); } } - EditorGUILayout.EndFoldoutHeaderGroup(); } } } diff --git a/Runtime/Materials/UnlitDebug.mat b/Runtime/Materials/UnlitDebug.mat index 002c3af..bf5a310 100644 --- a/Runtime/Materials/UnlitDebug.mat +++ b/Runtime/Materials/UnlitDebug.mat @@ -46,7 +46,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _Depth: - m_Texture: {fileID: 2800000, guid: 37a375190af9a41f1b65c35d5829ad23, type: 3} + m_Texture: {fileID: 2800000, guid: 472408d18cae6ba43b335a55a1dcd445, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _DetailAlbedoMap: diff --git a/Runtime/Physics/BuoyantObject.cs b/Runtime/Physics/BuoyantObject.cs index aa989ae..3ab48cd 100644 --- a/Runtime/Physics/BuoyantObject.cs +++ b/Runtime/Physics/BuoyantObject.cs @@ -121,37 +121,37 @@ private void SetupColliders() private void Update() { + switch (_buoyancyType) + { + case BuoyancyType.Physical: + case BuoyancyType.PhysicalVoxel: + return; + } + #if STATIC_EVERYTHING var dt = 0.0f; #else var dt = Time.deltaTime; #endif + switch (_buoyancyType) { case BuoyancyType.NonPhysical: - { - _samplePoints[0] = transform.position; - var t = transform; - var vec = t.position; - vec.y = Heights[0].y + waterLevelOffset; - t.position = vec; - var up = t.up; - t.up = Vector3.Slerp(up, _normals[0], dt); - break; - } + { + _samplePoints[0] = transform.position; + var t = transform; + var vec = t.position; + vec.y = Heights[0].y + waterLevelOffset; + t.position = vec; + var up = t.up; + t.up = Vector3.Slerp(up, _normals[0], dt); + break; + } case BuoyancyType.NonPhysicalVoxel: // do the voxel non-physical break; - case BuoyancyType.Physical: - LocalToWorldJob.CompleteJob(_guid); - GetVelocityPoints(); - break; - case BuoyancyType.PhysicalVoxel: - LocalToWorldJob.CompleteJob(_guid); - GetVelocityPoints(); - break; default: - throw new ArgumentOutOfRangeException(); + return; } GerstnerWavesJobs.UpdateSamplePoints(ref _samplePoints, _guid); @@ -161,33 +161,44 @@ private void Update() private void FixedUpdate() { var submergedAmount = 0f; - + + switch (_buoyancyType) + { + case BuoyancyType.NonPhysical: + case BuoyancyType.NonPhysicalVoxel: + return; + } + + LocalToWorldJob.CompleteJob(_guid); + GetVelocityPoints(); + GerstnerWavesJobs.UpdateSamplePoints(ref _samplePoints, _guid); + GerstnerWavesJobs.GetData(_guid, ref Heights, ref _normals); + switch (_buoyancyType) { case BuoyancyType.PhysicalVoxel: - { - LocalToWorldJob.CompleteJob(_guid); - //Debug.Log("new pass: " + gameObject.name); - UnityPhysics.autoSyncTransforms = false; - - for (var i = 0; i < _voxels.Length; i++) - BuoyancyForce(_samplePoints[i], _velocity[i], Heights[i].y + waterLevelOffset, ref submergedAmount, ref _debugInfo[i]); - UnityPhysics.SyncTransforms(); - UnityPhysics.autoSyncTransforms = true; - UpdateDrag(submergedAmount); - break; - } + { + LocalToWorldJob.CompleteJob(_guid); + + var autoSyncTransforms = UnityPhysics.autoSyncTransforms; + UnityPhysics.autoSyncTransforms = false; + + for (var i = 0; i < _voxels.Length; i++) + BuoyancyForce(_samplePoints[i], _velocity[i], Heights[i].y + waterLevelOffset, ref submergedAmount, ref _debugInfo[i]); + + UnityPhysics.SyncTransforms(); + UnityPhysics.autoSyncTransforms = autoSyncTransforms; + + UpdateDrag(submergedAmount); + break; + } case BuoyancyType.Physical: - //LocalToWorldJob.CompleteJob(_guid); + LocalToWorldJob.CompleteJob(_guid); BuoyancyForce(Vector3.zero, _velocity[0], Heights[0].y + waterLevelOffset, ref submergedAmount, ref _debugInfo[0]); //UpdateDrag(submergedAmount); break; - case BuoyancyType.NonPhysical: - break; - case BuoyancyType.NonPhysicalVoxel: - break; default: - throw new ArgumentOutOfRangeException(); + return; } } From a5b7e57d8f179015249b4b92e640ddd78b8ebc00 Mon Sep 17 00:00:00 2001 From: Danny Whittaker Date: Wed, 14 Dec 2022 10:04:19 +0000 Subject: [PATCH 2/5] Update BuoyantObject.cs to sync transforms during voxel slice. Fixes an issue where the array sizes don't match after a hot reload. --- Runtime/Physics/BuoyantObject.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Runtime/Physics/BuoyantObject.cs b/Runtime/Physics/BuoyantObject.cs index 3ab48cd..d3d9549 100644 --- a/Runtime/Physics/BuoyantObject.cs +++ b/Runtime/Physics/BuoyantObject.cs @@ -269,6 +269,7 @@ private void SliceIntoVoxels() var size = t.localScale; t.SetPositionAndRotation(Vector3.zero, Quaternion.identity); t.localScale = Vector3.one; + UnityPhysics.SyncTransforms(); _voxels = null; var points = new List(); @@ -305,6 +306,8 @@ private void SliceIntoVoxels() _voxels = points.ToArray(); t.SetPositionAndRotation(pos, rot); t.localScale = size; + UnityPhysics.SyncTransforms(); + var voxelVolume = Mathf.Pow(voxelResolution, 3f) * _voxels.Length; var rawVolume = rawBounds.size.x * rawBounds.size.y * rawBounds.size.z; volume = Mathf.Min(rawVolume, voxelVolume); From a51859b2004c62d07f70c901f6de9833496c1ca7 Mon Sep 17 00:00:00 2001 From: Danny Whittaker Date: Wed, 14 Dec 2022 10:23:04 +0000 Subject: [PATCH 3/5] Revert unintended material update --- Runtime/Materials/UnlitDebug.mat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Runtime/Materials/UnlitDebug.mat b/Runtime/Materials/UnlitDebug.mat index bf5a310..002c3af 100644 --- a/Runtime/Materials/UnlitDebug.mat +++ b/Runtime/Materials/UnlitDebug.mat @@ -46,7 +46,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _Depth: - m_Texture: {fileID: 2800000, guid: 472408d18cae6ba43b335a55a1dcd445, type: 3} + m_Texture: {fileID: 2800000, guid: 37a375190af9a41f1b65c35d5829ad23, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _DetailAlbedoMap: From 114465acd6a1f717815a406a31008b60ce013b87 Mon Sep 17 00:00:00 2001 From: Danny Whittaker Date: Wed, 14 Dec 2022 11:02:05 +0000 Subject: [PATCH 4/5] GerstnerWavesJobs didn't clear out Registry on cleanup, so Init never worked as expected if resolutions changed. Changed BuoyantObject to use a LateFixedUpdate to setup its next Gerstner jobs, since they're only needed for Physics based interactions. Also updated to explicitly reference IsPhysicsBased and IsVoxelBased for code sanity. --- Runtime/GerstnerWavesJobs.cs | 4 ++- Runtime/Physics/BuoyantObject.cs | 57 +++++++++++++++++--------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Runtime/GerstnerWavesJobs.cs b/Runtime/GerstnerWavesJobs.cs index 71e9e83..873e199 100644 --- a/Runtime/GerstnerWavesJobs.cs +++ b/Runtime/GerstnerWavesJobs.cs @@ -78,7 +78,9 @@ public static void Cleanup() _waterHeightHandle.Complete(); DepthGenerator.CleanUp(); - + + Registry.Clear(); + //Cleanup native arrays _waveData.Dispose(); _positions.Dispose(); diff --git a/Runtime/Physics/BuoyantObject.cs b/Runtime/Physics/BuoyantObject.cs index d3d9549..aa65f76 100644 --- a/Runtime/Physics/BuoyantObject.cs +++ b/Runtime/Physics/BuoyantObject.cs @@ -48,6 +48,9 @@ public class BuoyantObject : MonoBehaviour private DebugDrawing[] _debugInfo; // For drawing force gizmos [NonSerialized] public float PercentSubmerged; + private bool IsPhysicsBased => _buoyancyType == BuoyancyType.Physical || _buoyancyType == BuoyancyType.PhysicalVoxel; + private bool IsVoxelBased => _buoyancyType == BuoyancyType.NonPhysicalVoxel || _buoyancyType == BuoyancyType.PhysicalVoxel; + [ContextMenu("Initialize")] private void Init() { @@ -82,7 +85,7 @@ private void Init() private void SetupVoxels() { - if (_buoyancyType == BuoyancyType.NonPhysicalVoxel || _buoyancyType == BuoyancyType.PhysicalVoxel) + if (IsVoxelBased) { SliceIntoVoxels(); } @@ -106,6 +109,8 @@ private void OnEnable() _guid = gameObject.GetInstanceID(); Init(); LocalToWorldConversion(); + + StartCoroutine(LateFixedUpdate()); } private void SetupColliders() @@ -121,12 +126,8 @@ private void SetupColliders() private void Update() { - switch (_buoyancyType) - { - case BuoyancyType.Physical: - case BuoyancyType.PhysicalVoxel: - return; - } + if (IsPhysicsBased) + return; #if STATIC_EVERYTHING var dt = 0.0f; @@ -151,7 +152,7 @@ private void Update() // do the voxel non-physical break; default: - return; + throw new ArgumentOutOfRangeException(); } GerstnerWavesJobs.UpdateSamplePoints(ref _samplePoints, _guid); @@ -160,14 +161,10 @@ private void Update() private void FixedUpdate() { - var submergedAmount = 0f; + if (!IsPhysicsBased) + return; - switch (_buoyancyType) - { - case BuoyancyType.NonPhysical: - case BuoyancyType.NonPhysicalVoxel: - return; - } + var submergedAmount = 0f; LocalToWorldJob.CompleteJob(_guid); GetVelocityPoints(); @@ -178,8 +175,6 @@ private void FixedUpdate() { case BuoyancyType.PhysicalVoxel: { - LocalToWorldJob.CompleteJob(_guid); - var autoSyncTransforms = UnityPhysics.autoSyncTransforms; UnityPhysics.autoSyncTransforms = false; @@ -193,16 +188,24 @@ private void FixedUpdate() break; } case BuoyancyType.Physical: - LocalToWorldJob.CompleteJob(_guid); BuoyancyForce(Vector3.zero, _velocity[0], Heights[0].y + waterLevelOffset, ref submergedAmount, ref _debugInfo[0]); //UpdateDrag(submergedAmount); break; default: - return; + throw new ArgumentOutOfRangeException(); } } - private void LateUpdate() { LocalToWorldConversion(); } + private static readonly WaitForFixedUpdate YieldLateFixedUpdate = new WaitForFixedUpdate(); + private System.Collections.IEnumerator LateFixedUpdate() + { + while (true) + { + yield return YieldLateFixedUpdate; + + LocalToWorldConversion(); + } + } private void OnDestroy() { @@ -211,19 +214,19 @@ private void OnDestroy() void CleanUp() { - if (_buoyancyType == BuoyancyType.Physical || _buoyancyType == BuoyancyType.PhysicalVoxel) + StopAllCoroutines(); + + if (IsPhysicsBased) { LocalToWorldJob.Cleanup(_guid); } - else - { - _samplePoints.Dispose(); - } + + _samplePoints.Dispose(); } private void LocalToWorldConversion() { - if (_buoyancyType != BuoyancyType.Physical && _buoyancyType != BuoyancyType.PhysicalVoxel) return; + if (!IsPhysicsBased) return; var transformMatrix = transform.localToWorldMatrix; LocalToWorldJob.ScheduleJob(_guid, transformMatrix); @@ -401,7 +404,7 @@ private void OnDrawGizmosSelected() water.y = debug.WaterHeight; Gizmos.DrawLine(debug.Position, water); // draw the water line Gizmos.DrawSphere(water, gizmoSize * 4f); - if(_buoyancyType == BuoyancyType.Physical || _buoyancyType == BuoyancyType.PhysicalVoxel) + if(IsPhysicsBased) { Gizmos.color = Color.red; Gizmos.DrawRay(debug.Position, debug.Force / _rb.mass); // draw force From 04cfefad1d37b00479cc7e4bda908b3ff52504eb Mon Sep 17 00:00:00 2001 From: Danny Whittaker Date: Wed, 14 Dec 2022 11:15:19 +0000 Subject: [PATCH 5/5] Revert samplePoints.Dispose() change since it's done by the LocalToWorldJob.Cleanup() --- Runtime/Physics/BuoyantObject.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Runtime/Physics/BuoyantObject.cs b/Runtime/Physics/BuoyantObject.cs index aa65f76..4d0a13b 100644 --- a/Runtime/Physics/BuoyantObject.cs +++ b/Runtime/Physics/BuoyantObject.cs @@ -220,8 +220,10 @@ void CleanUp() { LocalToWorldJob.Cleanup(_guid); } - - _samplePoints.Dispose(); + else + { + _samplePoints.Dispose(); + } } private void LocalToWorldConversion()