コード例 #1
0
        public void WorldTest()
        {
            var world = new Physics.PhysicsWorld(10, 5, 10);

            Assert.IsTrue((world.NumDynamicBodies == 5) && (world.NumStaticBodies == 10) && (world.NumBodies == 15) && (world.NumJoints == 10));

            world.Reset(0, 0, 0);
            Assert.IsTrue((world.NumDynamicBodies == 0) && (world.NumStaticBodies == 0) && (world.NumBodies == 0) && (world.NumJoints == 0));

            world.Reset(5, 1, 7);
            Assert.IsTrue((world.NumDynamicBodies == 1) && (world.NumStaticBodies == 5) && (world.NumBodies == 6) && (world.NumJoints == 7));

            // clone world
            var worldClone = new Physics.PhysicsWorld(0, 0, 0);

            Assert.IsTrue((worldClone.NumDynamicBodies == 0) && (worldClone.NumStaticBodies == 0) && (worldClone.NumBodies == 0) && (worldClone.NumJoints == 0));

            worldClone.Dispose();
            worldClone = (Physics.PhysicsWorld)world.Clone();
            Assert.IsTrue((worldClone.NumDynamicBodies == 1) && (worldClone.NumStaticBodies == 5) && (worldClone.NumBodies == 6) && (worldClone.NumJoints == 7));

            // dispose cloned world
            worldClone.Dispose();
            world.Dispose();
        }
コード例 #2
0
 public void BuildBPEmptyWorldTest()
 {
     Physics.PhysicsWorld world = createTestWorld();
     world.CollisionWorld.Broadphase.Build(world.StaticBodies, world.DynamicBodies, world.MotionVelocities,
                                           world.CollisionWorld.CollisionTolerance, 1 / 60, -9.81f * math.up());
     world.Dispose();
 }
コード例 #3
0
 public void UpdateWorldOneDynamicBoxTest()
 {
     Physics.PhysicsWorld world = BroadPhaseTests.createTestWorld(0, 1);
     BroadPhaseTests.addDynamicBoxToWorld(world, 0, Vector3.zero, quaternion.identity, new Vector3(10, .1f, 10));
     world.CollisionWorld.UpdateDynamicTree(ref world, 1 / 60, -9.81f * math.up());
     world.Dispose();
 }
コード例 #4
0
 public void BuildBPOneDynamicBoxTest()
 {
     Physics.PhysicsWorld world = createTestWorld(0, 1);
     addDynamicBoxToWorld(world, 0, new Vector3(0, 0, 0), Quaternion.identity, new Vector3(10, 10, 10));
     world.CollisionWorld.Broadphase.Build(world.StaticBodies, world.DynamicBodies, world.MotionVelocities,
                                           world.CollisionWorld.CollisionTolerance, 1 / 60, -9.81f * math.up());
     world.Dispose();
 }
コード例 #5
0
        public void WorldTest()
        {
            var world = new Physics.PhysicsWorld(1, 1, 0);

            Assert.IsTrue((world.NumStaticBodies == 1) && (world.NumDynamicBodies == 1) && (world.NumBodies == 2));

            // TODO: add test for dynamics

            world.Dispose();
        }
コード例 #6
0
 public void ScheduleBuildJobsOneStaticBoxTest()
 {
     Physics.PhysicsWorld world = createTestWorld(1);
     addStaticBoxToWorld(world, 0, new Vector3(0, 0, 0), Quaternion.identity, new Vector3(10, 0.1f, 10));
     Unity.Jobs.JobHandle handle = new Unity.Jobs.JobHandle();
     Unity.Jobs.JobHandle result = world.CollisionWorld.Broadphase.ScheduleBuildJobs(ref world, 1 / 60, 1, true, handle);
     result.Complete();
     Assert.IsTrue(result.IsCompleted);
     world.Dispose();
 }
コード例 #7
0
 public void UpdateWorldOneHundredDynamicBoxesTest()
 {
     Physics.PhysicsWorld world = BroadPhaseTests.createTestWorld(0, 100);
     for (int i = 0; i < 100; ++i)
     {
         BroadPhaseTests.addDynamicBoxToWorld(world, i, new Vector3(11 * i, 0, 0), quaternion.identity, new Vector3(10, .1f, 10));
     }
     world.CollisionWorld.UpdateDynamicTree(ref world, 1 / 60, -9.81f * math.up());
     world.Dispose();
 }
コード例 #8
0
 public void BuildBPOneHundredDynamicBoxesTest()
 {
     Physics.PhysicsWorld world = createTestWorld(0, 100);
     for (int i = 0; i < 100; ++i)
     {
         addDynamicBoxToWorld(world, i, new Vector3(i * 11, 0, 0), Quaternion.identity, new Vector3(10, 10, 10));
     }
     world.CollisionWorld.Broadphase.Build(world.StaticBodies, world.DynamicBodies, world.MotionVelocities,
                                           world.CollisionWorld.CollisionTolerance, 1 / 60, -9.81f * math.up());
     world.Dispose();
 }
コード例 #9
0
 public void SheduleUpdateJobsEmptyWorldTest()
 {
     for (int numThreads = 0; numThreads <= 8; numThreads++)
     {
         Physics.PhysicsWorld world          = BroadPhaseTests.createTestWorld();
         Unity.Jobs.JobHandle handle         = new Unity.Jobs.JobHandle();
         Unity.Jobs.JobHandle worldJobHandle = world.CollisionWorld.ScheduleUpdateDynamicTree(ref world, 1 / 60, -9.81f * math.up(), handle, numThreads);
         worldJobHandle.Complete();
         Assert.IsTrue(worldJobHandle.IsCompleted);
         world.Dispose();
     }
 }
コード例 #10
0
 public void SheduleUpdateJobsOneHundredStaticBoxesTest()
 {
     Physics.PhysicsWorld world = BroadPhaseTests.createTestWorld(100);
     for (int i = 0; i < 100; ++i)
     {
         BroadPhaseTests.addStaticBoxToWorld(world, i, new Vector3(11 * i, 0, 0), quaternion.identity, new Vector3(10, .1f, 10));
     }
     Unity.Jobs.JobHandle handle         = new Unity.Jobs.JobHandle();
     Unity.Jobs.JobHandle worldJobHandle = world.CollisionWorld.ScheduleUpdateDynamicLayer(ref world, 1 / 60, 1, handle);
     worldJobHandle.Complete();
     Assert.IsTrue(worldJobHandle.IsCompleted);
     world.Dispose();
 }
コード例 #11
0
 public void SheduleUpdateJobsOneDynamicBoxTest()
 {
     for (int numThreads = 0; numThreads <= 8; numThreads++)
     {
         Physics.PhysicsWorld world = BroadPhaseTests.createTestWorld(0, 1);
         BroadPhaseTests.addDynamicBoxToWorld(world, 0, Vector3.zero, quaternion.identity, new Vector3(10, .1f, 10));
         Unity.Jobs.JobHandle handle         = new Unity.Jobs.JobHandle();
         Unity.Jobs.JobHandle worldJobHandle = world.CollisionWorld.ScheduleUpdateDynamicTree(ref world, 1 / 60, -9.81f * math.up(), handle, numThreads);
         worldJobHandle.Complete();
         Assert.IsTrue(worldJobHandle.IsCompleted);
         world.Dispose();
     }
 }
コード例 #12
0
 public void ScheduleBuildJobsEmptyWorldTest()
 {
     for (int numThreads = 0; numThreads <= 8; numThreads++)
     {
         Physics.PhysicsWorld world = createTestWorld();
         var handle          = new JobHandle();
         var buildStaticTree = new NativeArray <int>(1, Allocator.TempJob);
         buildStaticTree[0] = 1;
         JobHandle result = world.CollisionWorld.Broadphase.ScheduleBuildJobs(ref world, 1 / 60, -9.81f * math.up(), buildStaticTree, handle, numThreads);
         result.Complete();
         world.Dispose();
         buildStaticTree.Dispose();
     }
 }
コード例 #13
0
 public void ScheduleBuildJobsOneStaticBoxTest()
 {
     for (int numThreads = 0; numThreads <= 8; numThreads++)
     {
         Physics.PhysicsWorld world = createTestWorld(1);
         addStaticBoxToWorld(world, 0, new Vector3(0, 0, 0), Quaternion.identity, new Vector3(10, 0.1f, 10));
         var handle          = new JobHandle();
         var buildStaticTree = new NativeArray <int>(1, Allocator.TempJob);
         buildStaticTree[0] = 1;
         JobHandle result = world.CollisionWorld.Broadphase.ScheduleBuildJobs(ref world, 1 / 60, -9.81f * math.up(), buildStaticTree, handle, numThreads);
         result.Complete();
         Assert.IsTrue(result.IsCompleted);
         world.Dispose();
         buildStaticTree.Dispose();
     }
 }
コード例 #14
0
 public void SheduleUpdateJobsTenStaticBoxesTest()
 {
     for (int numThreads = 0; numThreads <= 1; numThreads++)
     {
         Physics.PhysicsWorld world = BroadPhaseTests.createTestWorld(10);
         for (int i = 0; i < 10; ++i)
         {
             BroadPhaseTests.addStaticBoxToWorld(world, i, new Vector3(11 * i, 0, 0), quaternion.identity, new Vector3(10, .1f, 10));
         }
         Unity.Jobs.JobHandle handle         = new Unity.Jobs.JobHandle();
         Unity.Jobs.JobHandle worldJobHandle = world.CollisionWorld.ScheduleUpdateDynamicTree(ref world, 1 / 60, -9.81f * math.up(), handle, numThreads == 1);
         worldJobHandle.Complete();
         Assert.IsTrue(worldJobHandle.IsCompleted);
         world.Dispose();
     }
 }
コード例 #15
0
        public void ScheduleBuildJobsOneStaticBoxTest()
        {
            Physics.PhysicsWorld world = createTestWorld(1);
            addStaticBoxToWorld(world, 0, new Vector3(0, 0, 0), Quaternion.identity, new Vector3(10, 0.1f, 10));
            JobHandle             handle = new JobHandle();
            StaticLayerChangeInfo staticLayerChangeInfo = new StaticLayerChangeInfo();

            staticLayerChangeInfo.Init(Allocator.TempJob);
            staticLayerChangeInfo.NumStaticBodies         = 1;
            staticLayerChangeInfo.HaveStaticBodiesChanged = 1;
            JobHandle result = world.CollisionWorld.Broadphase.ScheduleBuildJobs(ref world, 1 / 60, -9.81f * math.up(), 1, ref staticLayerChangeInfo, handle);

            result.Complete();
            Assert.IsTrue(result.IsCompleted);
            world.Dispose();
            staticLayerChangeInfo.Deallocate();
        }
コード例 #16
0
 public void UpdateEmptyWorldTest()
 {
     Physics.PhysicsWorld world = BroadPhaseTests.createTestWorld();
     world.CollisionWorld.UpdateDynamicTree(ref world, 1 / 60, -9.81f * math.up());
     world.Dispose();
 }
コード例 #17
0
        public void CalculateDetailsTest()
        {
            // Simple collision event with straight normal and 3 contact points
            LowLevel.CollisionEvent lowLevelEvent = new LowLevel.CollisionEvent();
            lowLevelEvent.BodyIndices.BodyAIndex    = 0;
            lowLevelEvent.BodyIndices.BodyBIndex    = 1;
            lowLevelEvent.ColliderKeys.ColliderKeyA = ColliderKey.Empty;
            lowLevelEvent.ColliderKeys.ColliderKeyB = ColliderKey.Empty;
            lowLevelEvent.Normal = new float3(0.0f, -1.00000f, 0.0f);
            lowLevelEvent.NumNarrowPhaseContactPoints = 3;
            lowLevelEvent.SolverImpulse = 1.0f;

            // Wrapping collision event
            CollisionEvent collisionEvent = new CollisionEvent();

            collisionEvent.EventData = lowLevelEvent;
            collisionEvent.TimeStep  = 1.0f / 60.0f;

            // Input velocity is obviously separating, but high angular velocity still caused an event
            collisionEvent.InputVelocityA = new Velocity
            {
                Angular = new float3(-0.00064f, 11.17604f, 0.02133f),
                Linear  = new float3(-3.81205f, -0.56607f, 9.14945f)
            };
            collisionEvent.InputVelocityB = new Velocity
            {
                Angular = new float3(0.00000f, 0.00000f, 0.00000f),
                Linear  = new float3(0.00000f, 0.00000f, 0.00000f)
            };

            // Initialize 3 contact points
            collisionEvent.NarrowPhaseContactPoints = new NativeArray <ContactPoint>(3, Allocator.Temp)
            {
                [0] = new ContactPoint
                {
                    Distance = 0.177905f,
                    Position = new float3(-22.744950f, 2.585318f, -50.108990f)
                },
                [1] = new ContactPoint
                {
                    Distance = 0.276652f,
                    Position = new float3(-20.731140f, 2.486506f, -50.322240f)
                },
                [2] = new ContactPoint
                {
                    Distance = 0.278534f,
                    Position = new float3(-20.766140f, 2.484623f, -50.652630f)
                }
            };

            // Allocate a simple world of 1 dynamic and 1 static body
            var simpleWorld      = new Physics.PhysicsWorld(1, 1, 0);
            var motionVelocities = simpleWorld.MotionVelocities;
            var motionDatas      = simpleWorld.MotionDatas;

            motionDatas[0] = new MotionData
            {
                LinearDamping   = 0.0f,
                AngularDamping  = 0.0f,
                GravityFactor   = 1.0f,
                BodyFromMotion  = new RigidTransform(new quaternion(0.0f, 0.0f, 0.0f, 1.0f), new float3(0.0f, 0.0f, 0.0f)),
                WorldFromMotion = new RigidTransform(new quaternion(0.09212853f, 0.1400256f, -0.006776567f, -0.9858292f), new float3(-22.17587f, 0.5172966f, -52.24425f))
            };
            motionVelocities[0] = new MotionVelocity
            {
                LinearVelocity         = new float3(-3.81221f, -1.37538f, -15.41893f),
                AngularVelocity        = new float3(-7.30913f, -4.78899f, 1.14168f),
                InverseInertiaAndMass  = new float4(0.00045f, 0.00045f, 0.00045f, 0.00018f),
                AngularExpansionFactor = 2.05061f
            };

            // Calculate the collision event details and make sure 1 contact point is returned
            var details = collisionEvent.CalculateDetails(ref simpleWorld);

            Assert.AreEqual(details.EstimatedContactPointPositions.Length, 1);

            // Dispose the world data
            simpleWorld.Dispose();
        }
コード例 #18
0
        public unsafe void ManifoldQueryTest()
        {
            const uint seed      = 0x98765432;
            Random     rnd       = new Random(seed);
            int        numWorlds = 1000;

            uint dbgWorld = 0;

            if (dbgWorld > 0)
            {
                numWorlds = 1;
            }

            for (int iWorld = 0; iWorld < numWorlds; iWorld++)
            {
                // Save state to repro this query without doing everything that came before it
                if (dbgWorld > 0)
                {
                    rnd.state = dbgWorld;
                }
                uint worldState            = rnd.state;
                Physics.PhysicsWorld world = TestUtils.GenerateRandomWorld(ref rnd, rnd.NextInt(1, 20), 3.0f);

                // Manifold test
                // TODO would be nice if we could change the world collision tolerance
                for (int iBodyA = 0; iBodyA < world.NumBodies; iBodyA++)
                {
                    for (int iBodyB = iBodyA + 1; iBodyB < world.NumBodies; iBodyB++)
                    {
                        Physics.RigidBody bodyA = world.Bodies[iBodyA];
                        Physics.RigidBody bodyB = world.Bodies[iBodyB];
                        if (bodyA.Collider->Type == ColliderType.Mesh && bodyB.Collider->Type == ColliderType.Mesh)
                        {
                            continue; // TODO - no mesh-mesh manifold support yet
                        }

                        // Build manifolds
                        BlockStream        contacts      = new BlockStream(1, 0, Allocator.Temp);
                        BlockStream.Writer contactWriter = contacts;
                        contactWriter.BeginForEachIndex(0);
                        ManifoldQueries.BodyBody(ref world, new BodyIndexPair {
                            BodyAIndex = iBodyA, BodyBIndex = iBodyB
                        }, 1.0f, ref contactWriter);
                        contactWriter.EndForEachIndex();

                        // Read each manifold
                        BlockStream.Reader contactReader = contacts;
                        contactReader.BeginForEachIndex(0);
                        int manifoldIndex = 0;
                        while (contactReader.RemainingItemCount > 0)
                        {
                            string failureMessage = iWorld + " (" + worldState + ") " + iBodyA + " vs " + iBodyB + " #" + manifoldIndex;
                            manifoldIndex++;

                            // Read the manifold header
                            ContactHeader header = contactReader.Read <ContactHeader>();
                            ConvexConvexManifoldQueries.Manifold manifold = new ConvexConvexManifoldQueries.Manifold();
                            manifold.NumContacts = header.NumContacts;
                            manifold.Normal      = header.Normal;

                            // Get the leaf shapes
                            ChildCollider leafA, leafB;
                            {
                                Collider.GetLeafCollider(bodyA.Collider, bodyA.WorldFromBody, header.ColliderKeys.ColliderKeyA, out leafA);
                                Collider.GetLeafCollider(bodyB.Collider, bodyB.WorldFromBody, header.ColliderKeys.ColliderKeyB, out leafB);
                            }

                            // Read each contact point
                            int minIndex = 0;
                            for (int iContact = 0; iContact < header.NumContacts; iContact++)
                            {
                                // Read the contact and find the closest
                                ContactPoint contact = contactReader.Read <ContactPoint>();
                                manifold[iContact] = contact;
                                if (contact.Distance < manifold[minIndex].Distance)
                                {
                                    minIndex = iContact;
                                }

                                // Check that the contact point is on or inside the shape
                                CheckPointOnSurface(ref leafA, contact.Position + manifold.Normal * contact.Distance, failureMessage + " contact " + iContact + " leaf A");
                                CheckPointOnSurface(ref leafB, contact.Position, failureMessage + " contact " + iContact + " leaf B");
                            }

                            // Check the closest point
                            {
                                ContactPoint           closestPoint = manifold[minIndex];
                                RigidTransform         aFromWorld   = math.inverse(leafA.TransformFromChild);
                                DistanceQueries.Result result       = new DistanceQueries.Result
                                {
                                    PositionOnAinA = math.transform(aFromWorld, closestPoint.Position + manifold.Normal * closestPoint.Distance),
                                    NormalInA      = math.mul(aFromWorld.rot, manifold.Normal),
                                    Distance       = closestPoint.Distance
                                };

                                MTransform aFromB            = new MTransform(math.mul(aFromWorld, leafB.TransformFromChild));
                                float      referenceDistance = DistanceQueries.ConvexConvex(leafA.Collider, leafB.Collider, aFromB).Distance;
                                ValidateDistanceResult(result, ref ((ConvexCollider *)leafA.Collider)->ConvexHull, ref ((ConvexCollider *)leafB.Collider)->ConvexHull, aFromB, referenceDistance, failureMessage + " closest point");
                            }

                            // Check that the manifold is flat
                            CheckManifoldFlat(ref manifold, manifold.Normal, failureMessage + ": non-flat A");
                            CheckManifoldFlat(ref manifold, float3.zero, failureMessage + ": non-flat B");
                        }

                        contacts.Dispose();
                    }
                }

                world.Dispose(); // TODO leaking memory if the test fails
            }
        }
コード例 #19
0
        public unsafe void WorldQueryTest()
        {
            const uint seed     = 0x12345678;
            uint       dbgWorld = 0; // set dbgWorld, dbgTest to the seed reported from a failure message to repeat the failing case alone
            uint       dbgTest  = 0;

            int numWorlds = 200;
            int numTests  = 5000;

            if (dbgWorld > 0)
            {
                numWorlds = 1;
                numTests  = 1;
            }

            Random rnd = new Random(seed);
            NativeList <DistanceHit>     distanceHits     = new NativeList <DistanceHit>(Allocator.Temp);
            NativeList <ColliderCastHit> colliderCastHits = new NativeList <ColliderCastHit>(Allocator.Temp);
            NativeList <RaycastHit>      raycastHits      = new NativeList <RaycastHit>(Allocator.Temp);

            for (int iWorld = 0; iWorld < numWorlds; iWorld++)
            {
                // Save state to repro this query without doing everything that came before it
                if (dbgWorld > 0)
                {
                    rnd.state = dbgWorld;
                }
                uint worldState            = rnd.state;
                Physics.PhysicsWorld world = TestUtils.GenerateRandomWorld(ref rnd, rnd.NextInt(1, 20), 10.0f);

                for (int iTest = 0; iTest < (numTests / numWorlds); iTest++)
                {
                    if (dbgTest > 0)
                    {
                        rnd.state = dbgTest;
                    }
                    uint   testState      = rnd.state;
                    string failureMessage = iWorld + ", " + iTest + " (" + worldState.ToString() + ", " + testState.ToString() + ")";

                    // Generate common random query inputs
                    Collider *     collider  = (Collider *)TestUtils.GenerateRandomConvex(ref rnd).GetUnsafePtr();
                    RigidTransform transform = new RigidTransform
                    {
                        pos = rnd.NextFloat3(-10.0f, 10.0f),
                        rot = (rnd.NextInt(10) > 0) ? rnd.NextQuaternionRotation() : quaternion.identity,
                    };
                    Ray ray = new Ray(transform.pos, rnd.NextFloat3(-5.0f, 5.0f));

                    // Distance test
                    {
                        ColliderDistanceInput input = new ColliderDistanceInput
                        {
                            Collider    = collider,
                            Transform   = transform,
                            MaxDistance = (rnd.NextInt(4) > 0) ? rnd.NextFloat(5.0f) : 0.0f
                        };
                        WorldCalculateDistanceTest(ref world, input, ref distanceHits, "WorldQueryTest failed CalculateDistance " + failureMessage);
                    }

                    // Collider cast test
                    {
                        ColliderCastInput input = new ColliderCastInput
                        {
                            Collider    = collider,
                            Position    = transform.pos,
                            Orientation = transform.rot,
                            Direction   = ray.Direction
                        };
                        WorldColliderCastTest(ref world, input, ref colliderCastHits, "WorldQueryTest failed ColliderCast " + failureMessage);
                    }

                    // Ray cast test
                    {
                        RaycastInput input = new RaycastInput
                        {
                            Ray    = ray,
                            Filter = CollisionFilter.Default
                        };
                        WorldRaycastTest(ref world, input, ref raycastHits, "WorldQueryTest failed Raycast " + failureMessage);
                    }
                }

                world.Dispose(); // TODO leaking memory if the test fails
            }

            distanceHits.Dispose(); // TODO leaking memory if the test fails
            colliderCastHits.Dispose();
            raycastHits.Dispose();
        }