Example #1
0
        // Schedules a set of jobs to iterate the provided dispatch pairs and create contacts based on them.
        internal static SimulationJobHandles ScheduleCreateContactsJobs(ref PhysicsWorld world, float timeStep,
                                                                        ref NativeStream contacts, ref NativeStream jacobians, ref NativeList <DispatchPairSequencer.DispatchPair> dispatchPairs,
                                                                        JobHandle inputDeps, ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                contacts  = new NativeStream(1, Allocator.TempJob);
                jacobians = new NativeStream(1, Allocator.TempJob);
                returnHandles.FinalExecutionHandle = new CreateContactsJob
                {
                    World               = world,
                    TimeStep            = timeStep,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo,
                    ContactsWriter      = contacts.AsWriter()
                }.Schedule(inputDeps);
            }
            else
            {
                var numWorkItems    = solverSchedulerInfo.NumWorkItems;
                var contactsHandle  = NativeStream.ScheduleConstruct(out contacts, numWorkItems, inputDeps, Allocator.TempJob);
                var jacobiansHandle = NativeStream.ScheduleConstruct(out jacobians, numWorkItems, inputDeps, Allocator.TempJob);

                var processHandle = new CreateContactsJob
                {
                    World               = world,
                    TimeStep            = timeStep,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo,
                    ContactsWriter      = contacts.AsWriter()
                }.ScheduleUnsafeIndex0(numWorkItems, 1, JobHandle.CombineDependencies(contactsHandle, jacobiansHandle));


                returnHandles.FinalExecutionHandle = processHandle;
            }

            return(returnHandles);
        }
Example #2
0
        /// <summary>
        /// Schedule a set of jobs to build the broadphase based on the given world.
        /// </summary>       
        public JobHandle ScheduleBuildJobs(ref PhysicsWorld world, float timeStep, float3 gravity, int numThreadsHint, ref StaticLayerChangeInfo staticLayerChangeInfo, JobHandle inputDeps)
        {
            var previousFrameBodyFilters = new NativeArray<CollisionFilter>(m_BodyFilters, Allocator.TempJob);

            if (world.NumBodies > m_BodyFilters.Length)
            {
                m_BodyFilters.Dispose();
                m_BodyFilters = new NativeArray<CollisionFilter>(world.NumBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            }

            m_StaticTree.BodyCount = world.NumStaticBodies;
            JobHandle staticTree = ScheduleStaticTreeBuildJobs(ref world, numThreadsHint, ref staticLayerChangeInfo, previousFrameBodyFilters, inputDeps);

            m_DynamicTree.BodyCount = world.NumDynamicBodies;
            JobHandle dynamicTree = inputDeps;
            if (world.NumDynamicBodies > 0)
            {
                dynamicTree = ScheduleDynamicTreeBuildJobs(ref world, timeStep, gravity, numThreadsHint, inputDeps);
            }

            return JobHandle.CombineDependencies(staticTree, dynamicTree);
        }
Example #3
0
        internal static JobHandle ScheduleProcessBodyPairsJobs(ref PhysicsWorld world, float timeStep, int numIterations, ref Simulation.Context context, JobHandle inputDeps)
        {
            var numWorkItems         = context.SolverSchedulerInfo.NumWorkItems;
            var contactsHandle       = NativeStream.ScheduleConstruct(out context.Contacts, numWorkItems, inputDeps, Allocator.TempJob);
            var jointJacobiansHandle = NativeStream.ScheduleConstruct(out context.JointJacobians, numWorkItems, inputDeps, Allocator.TempJob);
            var jacobiansHandle      = NativeStream.ScheduleConstruct(out context.Jacobians, numWorkItems, inputDeps, Allocator.TempJob);

            var processHandle = new ProcessBodyPairsJob
            {
                World               = world,
                TimeStep            = timeStep,
                NumIterations       = numIterations,
                PhasedDispatchPairs = context.PhasedDispatchPairs.AsDeferredJobArray(),
                SolverSchedulerInfo = context.SolverSchedulerInfo,
                ContactWriter       = context.Contacts.AsWriter(),
                JointJacobianWriter = context.JointJacobians.AsWriter(),
            }.ScheduleUnsafeIndex0(numWorkItems, 1, JobHandle.CombineDependencies(contactsHandle, jointJacobiansHandle, jacobiansHandle));


            context.DisposeProcessBodyPairs = NativeListUtilityTemp.DisposeHotFix(ref context.PhasedDispatchPairs, processHandle);

            return(processHandle);
        }
Example #4
0
        private JobHandle ScheduleDynamicTreeBuildJobs(ref PhysicsWorld world, float timeStep, int numThreadsHint, JobHandle inputDeps)
        {
            JobHandle handle = inputDeps;
            var       aabbs  = new NativeArray <Aabb>(world.NumBodies, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var       lookup = new NativeArray <BoundingVolumeHierarchy.PointAndIndex>(world.NumDynamicBodies, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            handle = new BuildDynamicBodyDataJob
            {
                RigidBodies      = world.DynamicBodies,
                MotionVelocities = world.MotionVelocities,
                Aabbs            = aabbs,
                FiltersOut       = new NativeSlice <CollisionFilter>(m_BodyFilters, 0, world.NumDynamicBodies),
                Lookup           = lookup,
                AabbMargin       = world.CollisionTolerance / 2.0f, // each body contributes half
                TimeStep         = timeStep
            }.Schedule(world.NumDynamicBodies, 32, handle);

            m_DynamicTree.NodeCount = world.NumDynamicBodies + BoundingVolumeHierarchy.Constants.MaxNumTreeBranches;

            return(m_DynamicTree.BoundingVolumeHierarchy.ScheduleBuildJobs(
                       lookup, aabbs, m_BodyFilters, numThreadsHint, handle,
                       m_DynamicTree.NodeCount, m_DynamicTree.Ranges, m_DynamicTree.m_BranchCount));
        }
Example #5
0
 /// <summary>
 /// Schedule a set of jobs to build the broadphase based on the given world.
 /// </summary>
 public JobHandle ScheduleBuildJobs(ref PhysicsWorld world, float timeStep, float3 gravity, NativeArray <int> buildStaticTree, JobHandle inputDeps, int threadCountHint = 0)
 {
     if (threadCountHint <= 0)
     {
         return(new BuildBroadphaseJob
         {
             StaticBodies = world.StaticBodies,
             DynamicBodies = world.DynamicBodies,
             MotionVelocities = world.MotionVelocities,
             CollisionTolerance = world.CollisionWorld.CollisionTolerance,
             TimeStep = timeStep,
             Gravity = gravity,
             BuildStaticTree = buildStaticTree,
             Broadphase = this
         }.Schedule(inputDeps));
     }
     else
     {
         return(JobHandle.CombineDependencies(
                    ScheduleStaticTreeBuildJobs(ref world, threadCountHint, buildStaticTree, inputDeps),
                    ScheduleDynamicTreeBuildJobs(ref world, timeStep, gravity, threadCountHint, inputDeps)));
     }
 }
Example #6
0
        public static unsafe void Solve(PhysicsWorld world, float deltaTime, float3 up, int numConstraints,
                                        ref NativeArray <SurfaceConstraintInfo> constraints, ref float3 position, ref float3 velocity, out float integratedTime, bool respectMinDeltaTime = true)
        {
            float minDeltaTime = 0.0f;

            if (math.lengthsq(velocity) > k_Epsilon)
            {
                if (respectMinDeltaTime)
                {
                    // Min delta time to travel at least 1cm
                    minDeltaTime = 0.01f / math.length(velocity);
                }
                else
                {
                    minDeltaTime = deltaTime;
                }
            }

            // If velocity is exactly -up, it means we are checking for support.
            bool useConstraintVelocities = !(velocity.Equals(-up));

            Solve(world, deltaTime, minDeltaTime, up, numConstraints, ref constraints, ref position, ref velocity, out integratedTime, useConstraintVelocities);
        }
Example #7
0
        // TODO: We need to make a public version of ScheduleReset for use with
        // local simulation calling StepImmediate and chaining jobs over a number
        // of steps. This becomes a problem if new bodies are added to the world
        // between simulation steps.
        // A public version could take the form:
        //         public JobHandle ScheduleReset(ref PhysicsWorld world, JobHandle inputDeps = default)
        //         {
        //             return ScheduleReset(ref world, inputDeps, true);
        //         }
        // However, to make that possible we need a why to allocate InputVelocities within a job.
        // The core simulation does not chain jobs across multiple simulation steps and so
        // will not hit this issue.
        internal JobHandle ScheduleReset(ref PhysicsWorld world, JobHandle inputDeps, bool allocateEventDataStreams)
        {
            m_Bodies = world.Bodies;

            int numDynamicBodies = world.NumDynamicBodies;

            if (InputVelocities.Length < numDynamicBodies)
            {
                // TODO: can we find a way to setup InputVelocities within a job?
                if (InputVelocities.IsCreated)
                {
                    InputVelocities.Dispose();
                }
                InputVelocities = new NativeArray <Velocity>(numDynamicBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            }

            var handle = inputDeps;

            if (CollisionEventDataStream.IsCreated)
            {
                handle = CollisionEventDataStream.Dispose(handle);
            }
            if (TriggerEventDataStream.IsCreated)
            {
                handle = TriggerEventDataStream.Dispose(handle);
            }
            if (allocateEventDataStreams)
            {
                if (!WorkItemCount.IsCreated)
                {
                    WorkItemCount = new NativeArray <int>(new int[] { 1 }, Allocator.Persistent);
                }
                handle = NativeStream.ScheduleConstruct(out CollisionEventDataStream, WorkItemCount, handle, Allocator.Persistent);
                handle = NativeStream.ScheduleConstruct(out TriggerEventDataStream, WorkItemCount, handle, Allocator.Persistent);
            }
            return(handle);
        }
Example #8
0
        // Schedule a set of jobs to synchronize the collision world with the dynamics world.
        public JobHandle ScheduleUpdateDynamicTree(ref PhysicsWorld world, float timeStep, float3 gravity, JobHandle inputDeps, int threadCountHint = 0)
        {
            if (threadCountHint <= 0)
            {
                return(new UpdateDynamicLayerJob
                {
                    World = world,
                    TimeStep = timeStep,
                    Gravity = gravity
                }.Schedule(inputDeps));
            }
            else
            {
                // Synchronize transforms
                JobHandle handle = new UpdateRigidBodyTransformsJob
                {
                    MotionDatas = world.MotionDatas,
                    RigidBodies = m_Bodies
                }.Schedule(world.MotionDatas.Length, 32, inputDeps);

                // Update broadphase
                return(Broadphase.ScheduleDynamicTreeBuildJobs(ref world, timeStep, gravity, threadCountHint, handle));
            }
        }
Example #9
0
        /// <summary>
        /// Schedule a set of jobs to build the static tree of the broadphase based on the given world.
        /// </summary>
        public JobHandle ScheduleStaticTreeBuildJobs(
            ref PhysicsWorld world, int numThreadsHint, NativeArray <int> shouldDoWork, JobHandle inputDeps)
        {
            Assert.AreEqual(world.NumStaticBodies, m_StaticTree.NumBodies);
            if (world.NumStaticBodies == 0)
            {
                return(inputDeps);
            }

            var aabbs  = new NativeArray <Aabb>(world.NumStaticBodies, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
            var points = new NativeArray <PointAndIndex>(world.NumStaticBodies, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);

            var       numStaticBodiesArray = new NativeArray <int>(1, Allocator.TempJob);
            JobHandle handle = new PrepareNumStaticBodiesJob
            {
                NumStaticBodies      = world.NumStaticBodies,
                BuildStaticTree      = shouldDoWork,
                NumStaticBodiesArray = numStaticBodiesArray
            }.Schedule(inputDeps);

            handle = new PrepareStaticBodyDataJob
            {
                RigidBodies            = world.StaticBodies,
                Aabbs                  = aabbs,
                Points                 = points,
                FiltersOut             = m_StaticTree.BodyFilters,
                RespondsToCollisionOut = m_StaticTree.RespondsToCollision,
                AabbMargin             = world.CollisionWorld.CollisionTolerance * 0.5f, // each body contributes half
            }.ScheduleUnsafeIndex0(numStaticBodiesArray, 32, handle);

            var buildHandle = m_StaticTree.BoundingVolumeHierarchy.ScheduleBuildJobs(
                points, aabbs, m_StaticTree.BodyFilters, shouldDoWork, numThreadsHint, handle,
                m_StaticTree.Nodes.Length, m_StaticTree.Ranges, m_StaticTree.BranchCount);

            return(JobHandle.CombineDependencies(buildHandle, numStaticBodiesArray.Dispose(handle)));
        }
Example #10
0
 public JobHandle ScheduleUpdateDynamicLayer(
     ref PhysicsWorld world, float timeStep, float3 gravity, int numThreadsHint, JobHandle inputDeps)
 {
     return(ScheduleUpdateDynamicTree(ref world, timeStep, gravity, inputDeps, numThreadsHint));
 }
Example #11
0
        // Write a set of contact manifolds for a pair of bodies to the given stream.
        public static unsafe void BodyBody(ref PhysicsWorld world, BodyIndexPair pair, float timeStep, ref BlockStream.Writer contactWriter)
        {
            RigidBody rigidBodyA = world.Bodies[pair.BodyAIndex];
            RigidBody rigidBodyB = world.Bodies[pair.BodyBIndex];

            Collider *colliderA = rigidBodyA.Collider;
            Collider *colliderB = rigidBodyB.Collider;

            if (colliderA == null || colliderB == null || !CollisionFilter.IsCollisionEnabled(colliderA->Filter, colliderB->Filter))
            {
                return;
            }

            // Build combined motion expansion
            MotionExpansion expansion;
            {
                MotionExpansion GetBodyExpansion(int bodyIndex, NativeSlice <MotionVelocity> mvs)
                {
                    return(bodyIndex < mvs.Length ? mvs[bodyIndex].CalculateExpansion(timeStep) : MotionExpansion.Zero);
                }

                MotionExpansion expansionA = GetBodyExpansion(pair.BodyAIndex, world.MotionVelocities);
                MotionExpansion expansionB = GetBodyExpansion(pair.BodyBIndex, world.MotionVelocities);
                expansion = new MotionExpansion
                {
                    Linear  = expansionA.Linear - expansionB.Linear,
                    Uniform = expansionA.Uniform + expansionB.Uniform + world.CollisionTolerance
                };
            }

            var context = new Context
            {
                BodyIndices     = pair,
                BodyCustomDatas = new CustomDataPair {
                    CustomDataA = rigidBodyA.CustomData, CustomDataB = rigidBodyB.CustomData
                }
            };

            var worldFromA = new MTransform(rigidBodyA.WorldFromBody);
            var worldFromB = new MTransform(rigidBodyB.WorldFromBody);

            // Dispatch to appropriate manifold generator
            switch (colliderA->CollisionType)
            {
            case CollisionType.Convex:
                switch (colliderB->CollisionType)
                {
                case CollisionType.Convex:
                    ConvexConvex(context, ColliderKeyPair.Empty, colliderA, colliderB, worldFromA, worldFromB, expansion.MaxDistance, false, ref contactWriter);
                    break;

                case CollisionType.Composite:
                    ConvexComposite(context, ColliderKey.Empty, colliderA, colliderB, worldFromA, worldFromB, expansion, false, ref contactWriter);
                    break;
                }
                break;

            case CollisionType.Composite:
                switch (colliderB->CollisionType)
                {
                case CollisionType.Convex:
                    CompositeConvex(context, colliderA, colliderB, worldFromA, worldFromB, expansion, false, ref contactWriter);
                    break;

                case CollisionType.Composite:
                    CompositeComposite(context, colliderA, colliderB, worldFromA, worldFromB, expansion, false, ref contactWriter);
                    break;
                }
                break;
            }
        }
Example #12
0
 public JobHandle ScheduleUpdateDynamicTree(ref PhysicsWorld world, float timeStep, float3 gravity, JobHandle inputDeps, int threadCountHint = 0)
 {
     return(ScheduleUpdateDynamicTree(ref world, timeStep, gravity, inputDeps, threadCountHint > 0));
 }
Example #13
0
 // Schedule a set of jobs to build the broadphase based on the given world.
 public JobHandle ScheduleBuildBroadphaseJobs(ref PhysicsWorld world, float timeStep, float3 gravity, NativeArray <int> buildStaticTree, JobHandle inputDeps, bool multiThreaded = true)
 {
     return(Broadphase.ScheduleBuildJobs(ref world, timeStep, gravity, buildStaticTree, inputDeps, multiThreaded));
 }
Example #14
0
        // Schedules a collision events job only for UnityPhysics simulation
        internal static unsafe JobHandle ScheduleUnityPhysicsCollisionEventsJob <T>(T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, ICollisionEventsJobBase
        {
            SafetyChecks.CheckAreEqualAndThrow(SimulationType.UnityPhysics, simulation.Type);

            var data = new CollisionEventJobData <T>
            {
                UserJobData = jobData,
                EventReader = ((Simulation)simulation).CollisionEvents
            };

            // Ensure the input dependencies include the end-of-simulation job, so events will have been generated
            inputDeps = JobHandle.CombineDependencies(inputDeps, simulation.FinalSimulationJobHandle);
#if UNITY_2020_2_OR_NEWER
            var parameters = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref data), CollisionEventJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Single);
#else
            var parameters = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref data), CollisionEventJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Batched);
#endif
            return(JobsUtility.Schedule(ref parameters));
        }
 internal JobHandle Execute(Phase phase, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
 {
     ref List <CallbackAndDependency> cbs = ref m_Callbacks[(int)phase];
        // Schedule() implementation for IContactsJob when Havok Physics is available
        public static unsafe JobHandle Schedule <T>(this T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, IContactsJobBase
        {
            switch (simulation.Type)
            {
            case SimulationType.UnityPhysics:
                // Call the scheduling method for Unity.Physics
                return(IContactsJobExtensions.ScheduleUnityPhysicsContactsJob(jobData, simulation, ref world, inputDeps));

            case SimulationType.HavokPhysics:
            {
                var data = new ContactsJobData <T>
                {
                    UserJobData        = jobData,
                    ManifoldStream     = ((Havok.Physics.HavokSimulation)simulation).ManifoldStream,
                    PluginIndexToLocal = ((Havok.Physics.HavokSimulation)simulation).PluginIndexToLocal,
                    Bodies             = world.Bodies
                };
                var parameters = new JobsUtility.JobScheduleParameters(
                    UnsafeUtility.AddressOf(ref data),
                    ContactsJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Batched);
                return(JobsUtility.Schedule(ref parameters));
            }

            default:
                return(inputDeps);
            }
        }
Example #17
0
 public static unsafe JobHandle Schedule <T>(this T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps,
                                             HAVOK_PHYSICS_MISSING_FROM_ASMDEF _causeCompileError = HAVOK_PHYSICS_MISSING_FROM_ASMDEF.HAVOK_PHYSICS_MISSING_FROM_ASMDEF)
     where T : struct, ICollisionEventsJobBase
 {
     return(new JobHandle());
 }
Example #18
0
        internal static unsafe JobHandle ScheduleUnityPhysicsBodyPairsJob <T>(T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, IBodyPairsJobBase
        {
            SafetyChecks.CheckAreEqualAndThrow(SimulationType.UnityPhysics, simulation.Type);

            var data = new BodyPairsJobData <T>
            {
                UserJobData         = jobData,
                PhasedDispatchPairs = ((Simulation)simulation).StepContext.PhasedDispatchPairs.AsDeferredJobArray(),
                Bodies = world.Bodies
            };
            var parameters = new JobsUtility.JobScheduleParameters(
                UnsafeUtility.AddressOf(ref data),
                BodyPairsJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Batched);

            return(JobsUtility.Schedule(ref parameters));
        }
Example #19
0
        internal static unsafe JobHandle ScheduleUnityPhysicsBodyPairsJob <T>(T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, IBodyPairsJobBase
        {
            if (simulation.Type != SimulationType.UnityPhysics)
            {
                throw new ArgumentException($"Simulation type {simulation.Type} is not supported! Should be called only for SimulationType.UnityPhysics.");
            }

            var data = new BodyPairsJobData <T>
            {
                UserJobData         = jobData,
                PhasedDispatchPairs = ((Simulation)simulation).StepContext.PhasedDispatchPairs.AsDeferredJobArray(),
                Bodies = world.Bodies
            };
            var parameters = new JobsUtility.JobScheduleParameters(
                UnsafeUtility.AddressOf(ref data),
                BodyPairsJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Batched);

            return(JobsUtility.Schedule(ref parameters));
        }
Example #20
0
        internal static unsafe JobHandle ScheduleImpl <T>(this T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, ITriggerEventsJob
        {
            if (simulation.Type == SimulationType.UnityPhysics)
            {
                var data = new TriggerEventJobData <T>
                {
                    UserJobData = jobData,
                    EventReader = ((Simulation)simulation).TriggerEvents,
                    Bodies      = world.Bodies
                };

                // Ensure the input dependencies include the end-of-simulation job, so events will have been generated
                inputDeps = JobHandle.CombineDependencies(inputDeps, simulation.FinalSimulationJobHandle);

                var parameters = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref data), TriggerEventJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Batched);
                return(JobsUtility.Schedule(ref parameters));
            }
            return(inputDeps);
        }
Example #21
0
 // Build the broadphase based on the given world.
 public void BuildBroadphase(ref PhysicsWorld world, float timeStep, float3 gravity, bool buildStaticTree = true)
 {
     Broadphase.Build(world.StaticBodies, world.DynamicBodies, world.MotionDatas, world.MotionVelocities,
                      world.CollisionWorld.CollisionTolerance, timeStep, gravity, buildStaticTree);
 }
Example #22
0
 // Default ITriggerEventsJob.Schedule() implementation.
 public static unsafe JobHandle Schedule <T>(this T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
     where T : struct, ITriggerEventsJob
 {
     return(ScheduleImpl(jobData, simulation, ref world, inputDeps));
 }
Example #23
0
 // Schedule a set of jobs to build the broadphase based on the given world.
 public JobHandle ScheduleBuildBroadphaseJobs(ref PhysicsWorld world, float timeStep, float3 gravity, NativeArray <int> buildStaticTree, JobHandle inputDeps, int threadCountHint = 0)
 {
     return(Broadphase.ScheduleBuildJobs(ref world, timeStep, gravity, buildStaticTree, inputDeps, threadCountHint));
 }
Example #24
0
 public static void Solve(
     PhysicsWorld world, float deltaTime, float minDeltaTime, float3 up, float maxVelocity,
     NativeList <SurfaceConstraintInfo> constraints, ref float3 position, ref float3 velocity, out float integratedTime, bool useConstraintVelocities = true
     ) =>
 Solve(deltaTime, minDeltaTime, up, maxVelocity, constraints, ref position, ref velocity, out integratedTime, useConstraintVelocities);
Example #25
0
        // Default Schedule() implementation for ICollisionEventsJob.
        public static unsafe JobHandle Schedule <T>(this T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, ICollisionEventsJobBase
        {
            // Should work only for UnityPhysics
            if (simulation.Type != SimulationType.UnityPhysics)
            {
                return(inputDeps);
            }

            return(ScheduleUnityPhysicsCollisionEventsJob(jobData, simulation, ref world, inputDeps));
        }
        // Schedule() implementation for ITriggerEventsJob when Havok Physics is available
        public static unsafe JobHandle Schedule <T>(this T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, ITriggerEventsJob
        {
            switch (simulation.Type)
            {
            case SimulationType.UnityPhysics:
                // Call the scheduling method for Unity.Physics
                return(ITriggerEventJobExtensions.ScheduleUnityPhysicsTriggerEventsJob(jobData, simulation, ref world, inputDeps));

            case SimulationType.HavokPhysics:
            {
                var data = new TriggerEventJobData <T>
                {
                    UserJobData = jobData,
                    EventReader = ((Havok.Physics.HavokSimulation)simulation).TriggerEvents
                };

                // Ensure the input dependencies include the end-of-simulation job, so events will have been generated
                inputDeps = JobHandle.CombineDependencies(inputDeps, simulation.FinalSimulationJobHandle);

                var parameters = new JobsUtility.JobScheduleParameters(
                    UnsafeUtility.AddressOf(ref data),
                    TriggerEventJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Batched);
                return(JobsUtility.Schedule(ref parameters));
            }

            default:
                return(inputDeps);
            }
        }
Example #27
0
        // Schedules a collision events job only for UnityPhysics simulation
        internal static unsafe JobHandle ScheduleUnityPhysicsCollisionEventsJob <T>(T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
            where T : struct, ICollisionEventsJobBase
        {
            if (simulation.Type != SimulationType.UnityPhysics)
            {
                throw new ArgumentException($"Simulation type {simulation.Type} is not supported! Should be called only for SimulationType.UnityPhysics.");
            }

            var data = new CollisionEventJobData <T>
            {
                UserJobData = jobData,
                EventReader = ((Simulation)simulation).CollisionEvents
            };

            // Ensure the input dependencies include the end-of-simulation job, so events will have been generated
            inputDeps = JobHandle.CombineDependencies(inputDeps, simulation.FinalSimulationJobHandle);

            var parameters = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref data), CollisionEventJobProcess <T> .Initialize(), inputDeps, ScheduleMode.Batched);

            return(JobsUtility.Schedule(ref parameters));
        }
Example #28
0
        public static unsafe void Solve(PhysicsWorld world, float deltaTime, float minDeltaTime, float3 up, int numConstraints,
                                        ref NativeArray <SurfaceConstraintInfo> constraints, ref float3 position, ref float3 velocity, out float integratedTime, bool useConstraintVelocities = true)
        {
            // List of planes to solve against (up to 4)
            SurfaceConstraintInfo *supportPlanes = stackalloc SurfaceConstraintInfo[4];
            int numSupportPlanes = 0;

            float remainingTime = deltaTime;
            float currentTime   = 0.0f;

            while (remainingTime > 0.0f)
            {
                int   hitIndex         = -1;
                float minCollisionTime = remainingTime;

                // Iterate over constraints and solve them
                for (int i = 0; i < numConstraints; i++)
                {
                    if (constraints[i].Touched)
                    {
                        continue;
                    }

                    SurfaceConstraintInfo constraint = constraints[i];

                    float3 relVel     = velocity - (useConstraintVelocities ? constraint.Velocity : float3.zero);
                    float  relProjVel = -math.dot(relVel, constraint.Plane.Normal);
                    if (relProjVel < k_Epsilon)
                    {
                        continue;
                    }

                    // Clamp distance to 0, since penetration is handled by constraint.Velocity already
                    float distance = math.max(constraint.Plane.Distance, 0.0f);
                    if (distance < minCollisionTime * relProjVel)
                    {
                        minCollisionTime = distance / relProjVel;
                        hitIndex         = i;
                    }
                }

                // Integrate if at least 100 microseconds to hit
                if (minCollisionTime > 1e-4f)
                {
                    currentTime   += minCollisionTime;
                    remainingTime -= minCollisionTime;
                    position      += minCollisionTime * velocity;
                }

                if (hitIndex < 0 || currentTime > minDeltaTime)
                {
                    break;
                }

                // Mark constraint as touched
                {
                    var constraint = constraints[hitIndex];
                    constraint.Touched    = true;
                    constraints[hitIndex] = constraint;
                }

                // Add the hit to the current list of active planes
                supportPlanes[numSupportPlanes] = constraints[hitIndex];
                if (!useConstraintVelocities)
                {
                    supportPlanes[numSupportPlanes].Velocity = float3.zero;
                }
                numSupportPlanes++;

                // Solve support planes
                ExamineActivePlanes(up, supportPlanes, ref numSupportPlanes, ref velocity);

                // Can't handle more than 4 support planes
                if (numSupportPlanes == 4)
                {
                    break;
                }
            }

            integratedTime = currentTime;
        }
Example #29
0
        public JobHandle ScheduleBuildJobs(ref PhysicsWorld world, float timeStep, int numThreadsHint, ref StaticLayerChangeInfo staticLayerChangeInfo, JobHandle inputDeps)
        {
            PhysicsStep stepComponent = PhysicsStep.Default;

            return(ScheduleBuildJobs(ref world, timeStep, stepComponent.Gravity, numThreadsHint, ref staticLayerChangeInfo, inputDeps));
        }
Example #30
0
 internal static unsafe JobHandle ScheduleImpl<T>(this T jobData, ISimulation simulation, ref PhysicsWorld world, JobHandle inputDeps)
     where T : struct, IBodyPairsJob
 {
     if (simulation.Type == SimulationType.UnityPhysics)
     {
         var data = new BodyPairsJobData<T>
         {
             UserJobData = jobData,
             PhasedDispatchPairs = ((Simulation)simulation).m_Context.PhasedDispatchPairs.AsDeferredJobArray(),
             Bodies = world.Bodies
         };
         var parameters = new JobsUtility.JobScheduleParameters(
             UnsafeUtility.AddressOf(ref data),
             BodyPairsJobProcess<T>.Initialize(), inputDeps, ScheduleMode.Batched);
         return JobsUtility.Schedule(ref parameters);
     }
     return inputDeps;
 }