using UnityEngine; using Unity.Profiling; using System.Collections; using System.Collections.Generic; using System; using Unity.Jobs; using Unity.Collections; namespace Obi { /// /// Base class for updating multiple solvers in parallel. /// Derive from this class to write your onw updater. This grants you precise control over execution order, /// as you can choose to update solvers at any point during Unity's update cycle. /// [ExecuteInEditMode] public abstract class ObiUpdater : MonoBehaviour { static ProfilerMarker m_BeginStepPerfMarker = new ProfilerMarker("BeginStep"); static ProfilerMarker m_SubstepPerfMarker = new ProfilerMarker("Substep"); static ProfilerMarker m_EndStepPerfMarker = new ProfilerMarker("EndStep"); static ProfilerMarker m_InterpolatePerfMarker = new ProfilerMarker("Interpolate"); /// /// List of solvers updated by this updater. /// public List solvers = new List(); private List handles = new List(); /// /// Prepares all solvers to begin simulating a new frame. This should be called as soon as possible in the frame, /// and guaranteed to be called every frame that will step physics. /// protected void PrepareFrame() { foreach (ObiSolver solver in solvers) if (solver != null) solver.PrepareFrame(); } /// /// Prepares all solvers to begin simulating a new physics step. This involves /// caching some particle data for interpolation, performing collision detection, among other things. /// /// Duration (in seconds) of the next step. protected void BeginStep(float stepDeltaTime) { using (m_BeginStepPerfMarker.Auto()) { // Update colliders right before collision detection: ObiColliderWorld.GetInstance().UpdateColliders(); ObiColliderWorld.GetInstance().UpdateRigidbodies(solvers,stepDeltaTime); ObiColliderWorld.GetInstance().UpdateWorld(stepDeltaTime); handles.Clear(); // Kick off all solver jobs: foreach (ObiSolver solver in solvers) if (solver != null) handles.Add(solver.BeginStep(stepDeltaTime)); // wait for all solver jobs to complete: foreach (IObiJobHandle handle in handles) if (handle != null) handle.Complete(); foreach (ObiSolver solver in solvers) if (solver != null) solver.ReleaseJobHandles(); } } /// /// Advances the simulation a given amount of time. Note that once BeginStep has been called, /// Substep can be called multiple times. /// /// Duration (in seconds) of the substep. protected void Substep(float stepDeltaTime, float substepDeltaTime, int index) { using (m_SubstepPerfMarker.Auto()) { handles.Clear(); // Kick off all solver jobs: foreach (ObiSolver solver in solvers) if (solver != null) handles.Add(solver.Substep(stepDeltaTime, substepDeltaTime, index)); // wait for all solver jobs to complete: foreach (IObiJobHandle handle in handles) if (handle != null) handle.Complete(); foreach (ObiSolver solver in solvers) if (solver != null) solver.ReleaseJobHandles(); } } /// /// Wraps up the current simulation step. This will trigger contact callbacks. /// protected void EndStep(float substepDeltaTime) { using (m_EndStepPerfMarker.Auto()) { // End step: Invokes collision callbacks and notifies actors that the solver step has ended. foreach (ObiSolver solver in solvers) if (solver != null) solver.EndStep(substepDeltaTime); } // Write back rigidbody velocity deltas: ObiColliderWorld.GetInstance().UpdateRigidbodyVelocities(solvers); } /// /// Interpolates the previous and current physics states. Should be called right before rendering the current frame. /// /// Duration (in seconds) of the last step taken. /// Amount of accumulated (not yet simulated) time. protected void Interpolate(float stepDeltaTime, float accumulatedTime) { using (m_InterpolatePerfMarker.Auto()) { foreach (ObiSolver solver in solvers) if (solver != null) solver.Interpolate(stepDeltaTime, accumulatedTime); } } } }