/// <summary> /// Performs a collision correction at the specified position. /// </summary> /// <param name="entity"></param> /// <param name="currPos"></param> /// <param name="currRot"></param> /// <param name="controller"></param> /// <param name="collider"></param> /// <param name="collisionWorld"></param> private void CorrectForCollision(ref Entity entity, ref float3 currPos, ref quaternion currRot, ref CharacterControllerData controller, ref PhysicsCollider collider, ref CollisionWorld collisionWorld) { RigidTransform transform = new RigidTransform() { pos = currPos, rot = currRot }; // Use a subset sphere within our collider to test against. // We do not use the collider itself as some intersection (such as on ramps) is ok. var offset = -math.normalize(controller.gravity) * 0.1f; var sampleCollider = new PhysicsCollider() { Value = SphereCollider.Create(new SphereGeometry() { Center = currPos + offset, Radius = 0.1f }) }; if (PhysicsUtils.ColliderDistance(out DistanceHit smallestHit, sampleCollider, 0.1f, transform, ref collisionWorld, entity, PhysicsCollisionFilters.DynamicWithPhysical, null, ColliderData, Allocator.Temp)) { if (smallestHit.Distance < 0.0f) { currPos += math.abs(smallestHit.Distance) * smallestHit.SurfaceNormal; } } }
public void TestDistanceTwoSpheres() { // Insertion var tree = new NativeBVHTree(64, Allocator.Persistent); int expectedIndex = tree.InsertLeaf(SphereCollider.Create(new float3(0, 2, 0), 2)); tree.InsertLeaf(SphereCollider.Create(new float3(0, 5, 0), 2)); // Distance query var rayResult = new NativeList <int>(64, Allocator.Temp); var query = new NativeBVHTree.DistanceQueryInput { origin = new float3(0, -1, 0), maxDistance = 3f }; tree.DistanceQuery(query, rayResult); // Debug NativeBVHDebugDrawer.LastTree = tree; NativeBVHDebugDrawer.LastTreeHits = rayResult.ToArray(); // Assert Assert.AreEqual(1, rayResult.Length, "Expected only one hit"); Assert.AreEqual(expectedIndex, rayResult[0], "Expected nearer sphere to be the result"); }
public void TestSphereColliderCreateInvalid() { var sphere = new SphereGeometry { Center = new float3(-10.34f, 0.0f, -1.54f), Radius = 1.25f }; // positive inf center { var invalidSphere = sphere; invalidSphere.Center = new float3(float.PositiveInfinity, 0.0f, 0.0f); TestUtils.ThrowsException <System.ArgumentException>(() => SphereCollider.Create(invalidSphere)); } // negative inf center { var invalidSphere = sphere; invalidSphere.Center = new float3(float.NegativeInfinity, 0.0f, 0.0f); TestUtils.ThrowsException <System.ArgumentException>(() => SphereCollider.Create(invalidSphere)); } // nan center { var invalidSphere = sphere; invalidSphere.Center = new float3(float.NaN, 0.0f, 0.0f); TestUtils.ThrowsException <System.ArgumentException>(() => SphereCollider.Create(invalidSphere)); } // negative radius { var invalidSphere = sphere; invalidSphere.Radius = -0.5f; TestUtils.ThrowsException <System.ArgumentException>(() => SphereCollider.Create(invalidSphere)); } // positive inf radius { var invalidSphere = sphere; invalidSphere.Radius = float.PositiveInfinity; TestUtils.ThrowsException <System.ArgumentException>(() => SphereCollider.Create(invalidSphere)); } // negative inf radius { var invalidSphere = sphere; invalidSphere.Radius = float.NegativeInfinity; TestUtils.ThrowsException <System.ArgumentException>(() => SphereCollider.Create(invalidSphere)); } // nan radius { var invalidSphere = sphere; invalidSphere.Radius = float.NaN; TestUtils.ThrowsException <System.ArgumentException>(() => SphereCollider.Create(invalidSphere)); } }
protected override BlobAssetReference <Collider> ProduceColliderBlob(LegacySphere shape) { var scale = (float3)shape.transform.lossyScale; return(SphereCollider.Create( shape.center * scale, shape.radius * math.cmax(math.abs(scale)), ProduceCollisionFilter(shape), ProduceMaterial(shape) )); }
public void SphereCollider_Create_WhenRadiusInvalid_Throws( [Values(float.PositiveInfinity, float.NegativeInfinity, float.NaN, -1f)] float value ) { var geometry = new SphereGeometry { Radius = value }; var ex = Assert.Throws <ArgumentException>(() => SphereCollider.Create(geometry)); Assert.That(ex.Message, Does.Match(nameof(SphereGeometry.Radius))); }
unsafe public void TestSphereColliderCreate() { float3 center = new float3(-8.45f, 9.65f, -0.10f); float radius = 0.98f; var collider = SphereCollider.Create(center, radius); var sphereCollider = UnsafeUtilityEx.AsRef <SphereCollider>(collider.GetUnsafePtr()); TestUtils.AreEqual(center, sphereCollider.Center, 1e-3f); TestUtils.AreEqual(radius, sphereCollider.Radius, 1e-3f); Assert.AreEqual(ColliderType.Sphere, sphereCollider.Type); Assert.AreEqual(CollisionType.Convex, sphereCollider.CollisionType); }
public unsafe void RigidBodyCalculateAabb_SphereColliderTest() { Physics.RigidBody rigidbodySphere = Unity.Physics.RigidBody.Zero; const float convexRadius = 1.0f; rigidbodySphere.Collider = (Collider *)SphereCollider.Create(float3.zero, convexRadius).GetUnsafePtr(); var sphereAabb = rigidbodySphere.CalculateAabb(); var sphere = (Collider *)SphereCollider.Create(float3.zero, convexRadius).GetUnsafePtr(); Assert.IsTrue(sphereAabb.Equals(sphere->CalculateAabb())); }
public void Execute(int i) { var shapeData = ComputeData[ToComputeTable[i]]; switch (shapeData.ShapeType) { case ShapeType.Box: { BlobAssets[i] = BoxCollider.Create( shapeData.BoxProperties, shapeData.CollisionFilter, shapeData.Material ); return; } case ShapeType.Capsule: { BlobAssets[i] = CapsuleCollider.Create( shapeData.CapsuleProperties, shapeData.CollisionFilter, shapeData.Material ); return; } case ShapeType.Cylinder: { BlobAssets[i] = CylinderCollider.Create( shapeData.CylinderProperties, shapeData.CollisionFilter, shapeData.Material ); return; } case ShapeType.Plane: { var v = shapeData.PlaneVertices; BlobAssets[i] = PolygonCollider.CreateQuad( v.c0, v.c1, v.c2, v.c3, shapeData.CollisionFilter, shapeData.Material ); return; } case ShapeType.Sphere: { BlobAssets[i] = SphereCollider.Create( shapeData.SphereProperties, shapeData.CollisionFilter, shapeData.Material ); return; } // Note : Mesh and Hull are not computed here as they are in a separated set of jobs default: return; } }
public void TestSphereColliderMassProperties() { float3 center = new float3(-8.4f, 5.63f, 77.2f); float radius = 2.3f; var sphereCollider = SphereCollider.Create(center, radius); float inertia = 2.0f / 5.0f * radius * radius; float3 expectedInertiaTensor = new float3(inertia, inertia, inertia); float3 inertiaTensor = sphereCollider.Value.MassProperties.MassDistribution.InertiaTensor; Debug.Log($"Expected inertia tensor: {expectedInertiaTensor}, was: {inertiaTensor}"); TestUtils.AreEqual(expectedInertiaTensor, inertiaTensor, 1e-3f); }
public unsafe void RigidBodyCalculateDistanceTest() { const float size = 1.0f; const float convexRadius = 0.0f; const float sphereRadius = 1.0f; var queryPos = new float3(-10, -10, -10); BlobAssetReference <Collider> boxCollider = BoxCollider.Create(new BoxGeometry { Center = float3.zero, Orientation = quaternion.identity, Size = size, BevelRadius = convexRadius }); BlobAssetReference <Collider> sphereCollider = SphereCollider.Create(new SphereGeometry { Center = float3.zero, Radius = sphereRadius }); var rigidBody = new Physics.RigidBody { WorldFromBody = RigidTransform.identity, Collider = boxCollider }; var colliderDistanceInput = new ColliderDistanceInput { Collider = (Collider *)sphereCollider.GetUnsafePtr(), Transform = new RigidTransform(quaternion.identity, queryPos) }; var closestHit = new DistanceHit(); var allHits = new NativeList <DistanceHit>(Allocator.Temp); // OK case : with enough max distance colliderDistanceInput.MaxDistance = 10000.0f; Assert.IsTrue(rigidBody.CalculateDistance(colliderDistanceInput)); Assert.IsTrue(rigidBody.CalculateDistance(colliderDistanceInput, out closestHit)); Assert.IsTrue(rigidBody.CalculateDistance(colliderDistanceInput, ref allHits)); // Fail case : not enough max distance colliderDistanceInput.MaxDistance = 1; Assert.IsFalse(rigidBody.CalculateDistance(colliderDistanceInput)); Assert.IsFalse(rigidBody.CalculateDistance(colliderDistanceInput, out closestHit)); Assert.IsFalse(rigidBody.CalculateDistance(colliderDistanceInput, ref allHits)); boxCollider.Dispose(); sphereCollider.Dispose(); }
public void TestSphereColliderMassProperties() { float3 center = new float3(-8.4f, 5.63f, 77.2f); float radius = 2.3f; var sphereCollider = SphereCollider.Create(new SphereGeometry { Center = center, Radius = radius }); float inertia = 2.0f / 5.0f * radius * radius; float3 expectedInertiaTensor = new float3(inertia, inertia, inertia); float3 inertiaTensor = sphereCollider.Value.MassProperties.MassDistribution.InertiaTensor; TestUtils.AreEqual(expectedInertiaTensor, inertiaTensor, 1e-3f); }
public unsafe void RigidBodyCalculateAabb_SphereColliderTest() { var geometry = new SphereGeometry { Center = float3.zero, Radius = 1.0f }; Physics.RigidBody rigidbodySphere = Unity.Physics.RigidBody.Zero; rigidbodySphere.Collider = (Collider *)SphereCollider.Create(geometry).GetUnsafePtr(); var sphereAabb = rigidbodySphere.CalculateAabb(); var sphere = (Collider *)SphereCollider.Create(geometry).GetUnsafePtr(); Assert.IsTrue(sphereAabb.Equals(sphere->CalculateAabb())); }
public unsafe void RigidBodyCastColliderTest() { Physics.RigidBody rigidbody = Unity.Physics.RigidBody.Zero; const float size = 1.0f; const float convexRadius = 0.0f; const float sphereRadius = 1.0f; var rayStartOK = new float3(-10, -10, -10); var rayEndOK = new float3(10, 10, 10); var rayStartFail = new float3(-10, 10, -10); var rayEndFail = new float3(10, 10, 10); rigidbody.Collider = (Collider *)BoxCollider.Create(new BoxGeometry { Center = float3.zero, Orientation = quaternion.identity, Size = size, BevelRadius = convexRadius }).GetUnsafePtr(); var colliderCastInput = new ColliderCastInput(); var closestHit = new ColliderCastHit(); var allHits = new NativeList <ColliderCastHit>(Allocator.Temp); // OK case : Sphere hits the box collider colliderCastInput.Start = rayStartOK; colliderCastInput.End = rayEndOK; colliderCastInput.Collider = (Collider *)SphereCollider.Create( new SphereGeometry { Center = float3.zero, Radius = sphereRadius } ).GetUnsafePtr(); Assert.IsTrue(rigidbody.CastCollider(colliderCastInput)); Assert.IsTrue(rigidbody.CastCollider(colliderCastInput, out closestHit)); Assert.IsTrue(rigidbody.CastCollider(colliderCastInput, ref allHits)); // Fail case : wrong direction colliderCastInput.Start = rayStartFail; colliderCastInput.End = rayEndFail; Assert.IsFalse(rigidbody.CastCollider(colliderCastInput)); Assert.IsFalse(rigidbody.CastCollider(colliderCastInput, out closestHit)); Assert.IsFalse(rigidbody.CastCollider(colliderCastInput, ref allHits)); }
public void TestSphereColliderCalculateAabbLocal() { float3 center = new float3(-8.4f, 5.63f, -7.2f); float radius = 2.3f; var sphereCollider = SphereCollider.Create(center, radius); Aabb expected = new Aabb(); expected.Min = center - new float3(radius, radius, radius); expected.Max = center + new float3(radius, radius, radius); Aabb actual = sphereCollider.Value.CalculateAabb(); Debug.Log($"Expected aabb: Min: {expected.Min} Max: {expected.Max}, was Min: {actual.Min} Max: {actual.Max}"); TestUtils.AreEqual(expected.Min, actual.Min, 1e-3f); TestUtils.AreEqual(expected.Max, actual.Max, 1e-3f); }
public void TestSphereColliderCalculateAabbLocal() { float3 center = new float3(-8.4f, 5.63f, -7.2f); float radius = 2.3f; var sphereCollider = SphereCollider.Create(new SphereGeometry { Center = center, Radius = radius }); Aabb expected = new Aabb(); expected.Min = center - new float3(radius, radius, radius); expected.Max = center + new float3(radius, radius, radius); Aabb actual = sphereCollider.Value.CalculateAabb(); TestUtils.AreEqual(expected.Min, actual.Min, 1e-3f); TestUtils.AreEqual(expected.Max, actual.Max, 1e-3f); }
unsafe public void TestSphereColliderCreate() { var sphere = new SphereGeometry { Center = new float3(-8.45f, 9.65f, -0.10f), Radius = 0.98f }; var collider = SphereCollider.Create(sphere); var sphereCollider = UnsafeUtilityEx.AsRef <SphereCollider>(collider.GetUnsafePtr()); TestUtils.AreEqual(sphere.Center, sphereCollider.Center, 1e-3f); TestUtils.AreEqual(sphere.Center, sphereCollider.Geometry.Center, 1e-3f); TestUtils.AreEqual(sphere.Radius, sphereCollider.Radius, 1e-3f); TestUtils.AreEqual(sphere.Radius, sphereCollider.Geometry.Radius, 1e-3f); Assert.AreEqual(ColliderType.Sphere, sphereCollider.Type); Assert.AreEqual(CollisionType.Convex, sphereCollider.CollisionType); }
protected override BlobAssetReference <Collider> ProduceColliderBlob(LegacySphere shape) { var worldCenter = math.mul(shape.transform.localToWorldMatrix, new float4(shape.center, 1f)); var shapeFromWorld = math.inverse( new float4x4(new RigidTransform(shape.transform.rotation, shape.transform.position)) ); var center = math.mul(shapeFromWorld, worldCenter).xyz; var linearScale = (float3)shape.transform.lossyScale; var radius = shape.radius * math.cmax(math.abs(linearScale)); return(SphereCollider.Create( new SphereGeometry { Center = center, Radius = radius }, ProduceCollisionFilter(shape), ProduceMaterial(shape) )); }
public void TestSphereColliderCalculateAabbTransformed() { float3 center = new float3(-3.4f, 0.63f, -17.2f); float radius = 5.3f; var sphereCollider = SphereCollider.Create(center, radius); float3 translation = new float3(8.3f, -0.5f, 170.0f); quaternion rotation = quaternion.AxisAngle(math.normalize(new float3(1.1f, 4.5f, 0.0f)), 146.0f); Aabb expected = new Aabb(); expected.Min = math.mul(rotation, center) + translation - new float3(radius, radius, radius); expected.Max = math.mul(rotation, center) + translation + new float3(radius, radius, radius); Aabb actual = sphereCollider.Value.CalculateAabb(new RigidTransform(rotation, translation)); Debug.Log($"Expected aabb: Min: {expected.Min} Max: {expected.Max}, was Min: {actual.Min} Max: {actual.Max}"); TestUtils.AreEqual(expected.Min, actual.Min, 1e-3f); TestUtils.AreEqual(expected.Max, actual.Max, 1e-3f); }
public static async void SpawnBall(float3 position, float radius) { Material whiteMaterial = await Addressables.LoadAssetAsync <Material>( PRC.Addressables.Materials.White ).Task; BlobAssetReference <Collider> collider = SphereCollider.Create(new SphereGeometry() { Radius = radius }); DOTools.Physics.CreateDynamicBody( position, quaternion.identity, collider, float3.zero, float3.zero, 1f, whiteMaterial ); }
public unsafe void RigidBodyCastColliderTest() { Physics.RigidBody rigidbody = Unity.Physics.RigidBody.Zero; const float size = 1.0f; const float convexRadius = 0.0f; const float sphereRadius = 1.0f; var rayStartOK = new float3(-10, -10, -10); var rayEndOK = new float3(10, 10, 10); var rayStartFail = new float3(-10, 10, -10); var rayEndFail = new float3(10, 10, 10); rigidbody.Collider = (Collider *)BoxCollider.Create(float3.zero, quaternion.identity, new float3(size), convexRadius).GetUnsafePtr(); var colliderCastInput = new ColliderCastInput(); var closestHit = new ColliderCastHit(); var allHits = new NativeList <ColliderCastHit>(Allocator.Temp); // OK case : Sphere hits the box collider float3 rayDir = rayEndOK - rayStartOK; colliderCastInput.Position = rayStartOK; colliderCastInput.Direction = rayDir; colliderCastInput.Collider = (Collider *)SphereCollider.Create(float3.zero, sphereRadius).GetUnsafePtr(); Assert.IsTrue(rigidbody.CastCollider(colliderCastInput)); Assert.IsTrue(rigidbody.CastCollider(colliderCastInput, out closestHit)); Assert.IsTrue(rigidbody.CastCollider(colliderCastInput, ref allHits)); // Fail case : wrong direction rayDir = rayEndFail - rayStartFail; colliderCastInput.Position = rayStartFail; colliderCastInput.Direction = rayDir; Assert.IsFalse(rigidbody.CastCollider(colliderCastInput)); Assert.IsFalse(rigidbody.CastCollider(colliderCastInput, out closestHit)); Assert.IsFalse(rigidbody.CastCollider(colliderCastInput, ref allHits)); }
public static unsafe BlobAssetReference <Collider> GenerateRandomConvex(ref Random rnd) { ColliderType colliderType = (ColliderType)rnd.NextInt((int)ColliderType.Box); float radius = (rnd.NextInt(4) > 0) ? rnd.NextFloat(0.5f) : 0.0f; switch (colliderType) { case ColliderType.Convex: { int numPoints = rnd.NextInt(1, 16); if (numPoints == 3) // TODO - hull builder doesn't build faces for flat shapes, work around it for now to run the test { numPoints++; } var points = new NativeArray <float3>(numPoints, Allocator.Temp); for (int i = 0; i < numPoints; i++) { points[i] = rnd.NextFloat3(-1.0f, 1.0f); } var collider = ConvexCollider.Create(points, radius); points.Dispose(); return(collider); } case ColliderType.Sphere: { float3 center = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f); return(SphereCollider.Create(center, rnd.NextFloat(0.01f, 0.5f))); } case ColliderType.Capsule: { float3 point0 = rnd.NextFloat3(0.0f, 1.0f); float3 point1 = (rnd.NextInt(4) > 0) ? -point0 : rnd.NextFloat3(-1.0f, 1.0f); return(CapsuleCollider.Create(point0, point1, rnd.NextFloat(0.01f, 0.5f))); } case ColliderType.Triangle: { return(PolygonCollider.CreateTriangle(rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f))); } case ColliderType.Quad: { // Pick 3 totally random points, then choose a fourth that makes a flat and convex quad float3 point0 = rnd.NextFloat3(-1.0f, 1.0f); float3 point1 = rnd.NextFloat3(-1.0f, 1.0f); float3 point3 = rnd.NextFloat3(-1.0f, 1.0f); float t0 = rnd.NextFloat(0.0f, 1.0f); float t1 = rnd.NextFloat(0.0f, 1.0f); float3 e = point1 + point1 - point0; float3 a = math.lerp(point1, e, t0); float3 b = math.lerp(point3, point3 + point3 - point0, t0); float3 point2 = math.lerp(a, b, t1); return(PolygonCollider.CreateQuad(point0, point1, point2, point3)); } case ColliderType.Box: { float3 center = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f); quaternion orientation = (rnd.NextInt(4) > 0) ? quaternion.identity : rnd.NextQuaternionRotation(); return(BoxCollider.Create(center, orientation, rnd.NextFloat3(0.01f, 1.0f), radius)); } default: throw new System.NotImplementedException(); } }
protected override BlobAssetReference <Collider> ProduceColliderBlob(PhysicsShape shape) { var material = ProduceMaterial(shape); var collisionFilter = ProduceCollisionFilter(shape); var blob = new BlobAssetReference <Collider>(); shape.GetBakeTransformation(out var linearScalar, out var radiusScalar); switch (shape.ShapeType) { case ShapeType.Box: shape.GetBoxProperties(out var center, out var size, out quaternion orientation); blob = BoxCollider.Create( center * linearScalar, orientation, math.abs(size * linearScalar), shape.ConvexRadius * radiusScalar, collisionFilter, material); break; case ShapeType.Capsule: shape.GetCapsuleProperties(out var v0, out var v1, out var radius); blob = CapsuleCollider.Create( v0 * linearScalar, v1 * linearScalar, radius * radiusScalar, collisionFilter, material); break; case ShapeType.Sphere: shape.GetSphereProperties(out center, out radius, out orientation); blob = SphereCollider.Create( center * linearScalar, radius * radiusScalar, collisionFilter, material); break; case ShapeType.Cylinder: shape.GetCylinderProperties(out center, out var height, out radius, out orientation); var s = math.abs(math.mul(math.inverse(orientation), linearScalar)); blob = CylinderCollider.Create( center * linearScalar, height * s.z, radius * math.cmax(s.xy), orientation, shape.ConvexRadius * radiusScalar, collisionFilter, material); break; case ShapeType.Plane: shape.GetPlaneProperties(out v0, out v1, out var v2, out var v3); blob = PolygonCollider.CreateQuad( v0 * linearScalar, v1 * linearScalar, v2 * linearScalar, v3 * linearScalar, collisionFilter, material); break; case ShapeType.ConvexHull: var pointCloud = new NativeList <float3>(65535, Allocator.Temp); shape.GetConvexHullProperties(pointCloud); if (pointCloud.Length == 0) { pointCloud.Dispose(); throw new InvalidOperationException( $"No vertices associated with {shape.name}. Add a {typeof(MeshFilter)} component or assign {nameof(PhysicsShape.CustomMesh)}." ); } blob = ConvexCollider.Create( pointCloud, shape.ConvexRadius * radiusScalar, linearScalar, collisionFilter, material); pointCloud.Dispose(); break; case ShapeType.Mesh: // TODO: no convex radius? var mesh = shape.GetMesh(); if (mesh == null) { throw new InvalidOperationException( $"No mesh associated with {shape.name}. Add a {typeof(MeshFilter)} component or assign {nameof(PhysicsShape.CustomMesh)}." ); } else { blob = MeshCollider.Create(mesh.GetScaledVertices(linearScalar), mesh.triangles, collisionFilter, material); } break; default: throw new UnimplementedShapeException(shape.ShapeType); } return(blob); }
private BlobAssetReference <Collider> CreateCollider(UnityEngine.Mesh mesh, ColliderType type) { switch (type) { case ColliderType.Sphere: { Bounds bounds = mesh.bounds; return(SphereCollider.Create(bounds.center, math.cmax(bounds.extents))); } case ColliderType.Triangle: { return(PolygonCollider.CreateTriangle(mesh.vertices[0], mesh.vertices[1], mesh.vertices[2])); } case ColliderType.Quad: { // We assume the first 2 triangles of the mesh are a quad with a shared edge // Work out a correct ordering for the triangle int[] orderedIndices = new int[4]; // Find the vertex in first triangle that is not on the shared edge for (int i = 0; i < 3; i++) { if ((mesh.triangles[i] != mesh.triangles[3]) && (mesh.triangles[i] != mesh.triangles[4]) && (mesh.triangles[i] != mesh.triangles[5])) { // Push in order or prev, unique, next orderedIndices[0] = mesh.triangles[(i - 1 + 3) % 3]; orderedIndices[1] = mesh.triangles[i]; orderedIndices[2] = mesh.triangles[(i + 1) % 3]; break; } } // Find the vertex in second triangle that is not on a shared edge for (int i = 3; i < 6; i++) { if ((mesh.triangles[i] != orderedIndices[0]) && (mesh.triangles[i] != orderedIndices[1]) && (mesh.triangles[i] != orderedIndices[2])) { orderedIndices[3] = mesh.triangles[i]; break; } } return(PolygonCollider.CreateQuad( mesh.vertices[orderedIndices[0]], mesh.vertices[orderedIndices[1]], mesh.vertices[orderedIndices[2]], mesh.vertices[orderedIndices[3]])); } case ColliderType.Box: { Bounds bounds = mesh.bounds; return(BoxCollider.Create(bounds.center, quaternion.identity, 2.0f * bounds.extents, 0.0f)); } case ColliderType.Capsule: { Bounds bounds = mesh.bounds; float min = math.cmin(bounds.extents); float max = math.cmax(bounds.extents); int x = math.select(math.select(2, 1, min == bounds.extents.y), 0, min == bounds.extents.x); int z = math.select(math.select(2, 1, max == bounds.extents.y), 0, max == bounds.extents.x); int y = math.select(math.select(2, 1, (1 != x) && (1 != z)), 0, (0 != x) && (0 != z)); float radius = bounds.extents[y]; float3 vertex0 = bounds.center; vertex0[z] = -(max - radius); float3 vertex1 = bounds.center; vertex1[z] = (max - radius); return(CapsuleCollider.Create(vertex0, vertex1, radius)); } case ColliderType.Cylinder: // TODO: need someone to add throw new NotImplementedException(); case ColliderType.Convex: { NativeArray <float3> points = new NativeArray <float3>(mesh.vertices.Length, Allocator.Temp); for (int i = 0; i < mesh.vertices.Length; i++) { points[i] = mesh.vertices[i]; } return(ConvexCollider.Create(points, 0.0f)); } default: throw new System.NotImplementedException(); } }
public unsafe void Execute(int index) { Results.BeginForEachIndex(index); int numRows = (Request.ImageResolution + Results.ForEachCount - 1) / Results.ForEachCount; const float sphereRadius = 0.005f; BlobAssetReference <Collider> sphere; if (Request.CastSphere) { sphere = SphereCollider.Create(float3.zero, sphereRadius, Request.CollisionFilter); } for (int yCoord = index * numRows; yCoord < math.min(Request.ImageResolution, (index + 1) * numRows); yCoord++) { for (int xCoord = 0; xCoord < Request.ImageResolution; xCoord++) { float xFrac = 2.0f * ((xCoord / (float)Request.ImageResolution) - 0.5f); float yFrac = 2.0f * ((yCoord / (float)Request.ImageResolution) - 0.5f); float3 targetImagePlane = Request.ImageCenter + Request.Up * Request.PlaneHalfExtents * yFrac + Request.Right * Request.PlaneHalfExtents * xFrac; float3 rayDir = Request.RayLength * (Request.PinHole - targetImagePlane); RaycastHit hit; bool hasHit; if (Request.CastSphere) { var input = new ColliderCastInput { Collider = (Collider *)sphere.GetUnsafePtr(), Orientation = quaternion.identity, Start = Request.PinHole, End = Request.PinHole + rayDir }; hasHit = World.CastCollider(input, out ColliderCastHit colliderHit); hit = new RaycastHit { Fraction = colliderHit.Fraction, Position = colliderHit.Position, SurfaceNormal = colliderHit.SurfaceNormal, RigidBodyIndex = colliderHit.RigidBodyIndex, ColliderKey = colliderHit.ColliderKey }; } else { var rayCastInput = new RaycastInput { Start = Request.PinHole, End = Request.PinHole + rayDir, Filter = Request.CollisionFilter }; hasHit = World.CastRay(rayCastInput, out hit); } Color hitColor = Color.black; if (hasHit) { if (hit.RigidBodyIndex < NumDynamicBodies) { hitColor = Color.yellow; } else { hitColor = Color.grey; } // Lighten alternate keys if (Request.AlternateKeys && !hit.ColliderKey.Equals(ColliderKey.Empty)) { Collider *collider = World.Bodies[hit.RigidBodyIndex].Collider; hit.ColliderKey.PopSubKey(collider->NumColliderKeyBits, out uint key); if (key % 2 == 0) { Color.RGBToHSV(hitColor, out float h, out float s, out float v); hitColor = Color.HSVToRGB(h, s, v + 0.25f); } } if (Request.Shadows) { float3 hitPos = Request.PinHole + rayDir * hit.Fraction + hit.SurfaceNormal * 0.001f; bool shadowHit = false; if (Request.CastSphere) { var start = hitPos + hit.SurfaceNormal * sphereRadius; var input = new ColliderCastInput { Collider = (Collider *)sphere.GetUnsafePtr(), Orientation = quaternion.identity, Start = start, End = start + (Request.LightDir * Request.RayLength), }; ColliderCastHit colliderHit; shadowHit = World.CastCollider(input, out colliderHit); } else { var rayCastInput = new RaycastInput { Start = hitPos, End = hitPos + (Request.LightDir * Request.RayLength), Filter = Request.CollisionFilter }; RaycastHit shadowOutput; shadowHit = World.CastRay(rayCastInput, out shadowOutput); } if (shadowHit) { hitColor *= 0.4f; } } } float lighting = math.min(1.0f, math.max(Request.AmbientLight, Vector3.Dot(hit.SurfaceNormal, Request.LightDir))); Results.Write(xCoord); Results.Write(yCoord); Results.Write(hitColor * lighting); } } Results.EndForEachIndex(); }
public static unsafe BlobAssetReference <Collider> GenerateRandomConvex(ref Random rnd) { ColliderType colliderType = (ColliderType)rnd.NextInt((int)ColliderType.Cylinder + 1); float convexRadius = (rnd.NextInt(4) > 0) ? rnd.NextFloat(0.5f) : 0.0f; switch (colliderType) { case ColliderType.Convex: { int numPoints = rnd.NextInt(1, 16); if (numPoints == 3) // TODO - hull builder doesn't build faces for flat shapes, work around it for now to run the test { numPoints++; } var points = new NativeArray <float3>(numPoints, Allocator.TempJob); for (int i = 0; i < numPoints; i++) { points[i] = rnd.NextFloat3(-1.0f, 1.0f); } var generationParameters = ConvexHullGenerationParameters.Default; generationParameters.BevelRadius = convexRadius; var collider = ConvexCollider.Create(points, generationParameters, CollisionFilter.Default); points.Dispose(); return(collider); } case ColliderType.Sphere: { return(SphereCollider.Create(new SphereGeometry { Center = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f), Radius = rnd.NextFloat(0.01f, 0.5f) })); } case ColliderType.Capsule: { float3 point0 = rnd.NextFloat3(0.0f, 1.0f); float3 point1 = (rnd.NextInt(4) > 0) ? -point0 : rnd.NextFloat3(-1.0f, 1.0f); return(CapsuleCollider.Create(new CapsuleGeometry { Vertex0 = point0, Vertex1 = point1, Radius = rnd.NextFloat(0.01f, 0.5f) })); } case ColliderType.Triangle: { return(PolygonCollider.CreateTriangle(rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f), rnd.NextFloat3(-1.0f, 1.0f))); } case ColliderType.Quad: { // Pick 3 totally random points, then choose a fourth that makes a flat and convex quad float3 point0 = rnd.NextFloat3(-1.0f, 1.0f); float3 point1 = rnd.NextFloat3(-1.0f, 1.0f); float3 point3 = rnd.NextFloat3(-1.0f, 1.0f); float t0 = rnd.NextFloat(0.0f, 1.0f); float t1 = rnd.NextFloat(0.0f, 1.0f); float3 e = point1 + point1 - point0; float3 a = math.lerp(point1, e, t0); float3 b = math.lerp(point3, point3 + point3 - point0, t0); float3 point2 = math.lerp(a, b, t1); return(PolygonCollider.CreateQuad(point0, point1, point2, point3)); } case ColliderType.Box: { float minSize = 0.05f; // TODO - work around hull builder problems with small faces, sometimes doesn't extend 1D->2D based on face area var boxGeometry = new BoxGeometry { Center = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f), Orientation = (rnd.NextInt(4) > 0) ? quaternion.identity : rnd.NextQuaternionRotation(), Size = rnd.NextFloat3(minSize, 1.0f) }; float maxBevelRadius = math.max(math.cmin((boxGeometry.Size - minSize) / (2.0f * (1.0f + float.Epsilon))), 0.0f); boxGeometry.BevelRadius = math.min(maxBevelRadius, convexRadius); return(BoxCollider.Create(boxGeometry)); } case ColliderType.Cylinder: { float minSize = 0.01f; // TODO - cylinder gets degenerate faces if radius-convexRadius=0 or height/2-convexRadius=0, decide how to handle this in CylinderCollider var cylinderGeometry = new CylinderGeometry { Center = (rnd.NextInt(4) > 0) ? float3.zero : rnd.NextFloat3(-0.5f, 0.5f), Orientation = (rnd.NextInt(4) > 0) ? quaternion.identity : rnd.NextQuaternionRotation(), Height = rnd.NextFloat(2.0f * minSize, 1f), Radius = rnd.NextFloat(minSize, 1.0f), SideCount = 20 }; var maxBevelRadius = math.max(math.min(cylinderGeometry.Height / 2, cylinderGeometry.Radius) - minSize, 0.0f); cylinderGeometry.BevelRadius = math.min(maxBevelRadius, convexRadius); return(CylinderCollider.Create(cylinderGeometry)); } default: throw new NotImplementedException(); } }
private BlobAssetReference <Collider> CreateCollider(ColliderType type) { int numMeshes = type == ColliderType.Compound ? 2 : 1; ColliderMeshes = new Mesh[numMeshes]; BlobAssetReference <Collider> collider = default; switch (type) { case ColliderType.Sphere: collider = SphereCollider.Create(new SphereGeometry { Center = float3.zero, Radius = 0.5f }); break; case ColliderType.Triangle: collider = PolygonCollider.CreateTriangle(k_TriangleVertices[0], k_TriangleVertices[1], k_TriangleVertices[2]); break; case ColliderType.Quad: collider = PolygonCollider.CreateQuad(k_QuadVertices[0], k_QuadVertices[1], k_QuadVertices[2], k_QuadVertices[3]); break; case ColliderType.Box: collider = BoxCollider.Create(new BoxGeometry { Center = float3.zero, Orientation = quaternion.identity, Size = new float3(1.0f), BevelRadius = 0.0f }); break; case ColliderType.Capsule: collider = CapsuleCollider.Create(new CapsuleGeometry { Vertex0 = new float3(0, -0.5f, 0), Vertex1 = new float3(0, 0.5f, 0), Radius = 0.5f }); break; case ColliderType.Cylinder: // TODO: need someone to add throw new NotImplementedException(); case ColliderType.Convex: // Tetrahedron NativeArray <float3> points = new NativeArray <float3>(k_TetraherdonVertices, Allocator.TempJob); collider = ConvexCollider.Create(points, ConvexHullGenerationParameters.Default, CollisionFilter.Default); points.Dispose(); break; case ColliderType.Compound: var child1 = SphereCollider.Create(new SphereGeometry { Center = float3.zero, Radius = 0.5f }); ChildrenColliders.Add(child1); var child2 = BoxCollider.Create(new BoxGeometry { Center = float3.zero, Orientation = quaternion.identity, Size = new float3(1.0f), BevelRadius = 0.0f }); ChildrenColliders.Add(child2); NativeArray <ColliderBlobInstance> childrenBlobs = new NativeArray <ColliderBlobInstance>(2, Allocator.TempJob); childrenBlobs[0] = new ColliderBlobInstance { Collider = child1, CompoundFromChild = new RigidTransform { pos = new float3(0.5f, 0, 0), rot = quaternion.identity } }; childrenBlobs[1] = new ColliderBlobInstance { Collider = child2, CompoundFromChild = new RigidTransform { pos = new float3(-0.5f, 0, 0), rot = quaternion.identity } }; ColliderMeshes[0] = SceneCreationUtilities.CreateMeshFromCollider(child1); ColliderMeshes[1] = SceneCreationUtilities.CreateMeshFromCollider(child2); collider = CompoundCollider.Create(childrenBlobs); childrenBlobs.Dispose(); break; case ColliderType.Mesh: // Tetrahedron mesh NativeArray <float3> meshVertices = new NativeArray <float3>(k_TetraherdonVertices, Allocator.TempJob); NativeArray <int3> meshTriangles = new NativeArray <int3>(k_TetrahedronMeshTriangles, Allocator.TempJob); collider = MeshCollider.Create(meshVertices, meshTriangles); meshVertices.Dispose(); meshTriangles.Dispose(); break; case ColliderType.Terrain: int2 size = 2; float3 scale = 1; Random rand = new Random(0x9739); int numSamples = size.x * size.y; var heights = new NativeArray <float>(numSamples, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); for (int i = 0; i < numSamples; i++) { heights[i] = rand.NextFloat(0, 1); } collider = TerrainCollider.Create(heights, size, scale, TerrainCollider.CollisionMethod.VertexSamples); heights.Dispose(); break; default: throw new System.NotImplementedException(); } if (ColliderType != ColliderType.Compound) { ColliderMeshes[0] = SceneCreationUtilities.CreateMeshFromCollider(collider); } return(collider); }
public unsafe void CreateCompound_WithRepeatedInputs_ChildrenAreInstances() { BlobAssetReference <Collider> boxBlob = default; BlobAssetReference <Collider> capsuleBlob = default; BlobAssetReference <Collider> sphereBlob = default; BlobAssetReference <Collider> compoundBlob = default; try { // 3 unique instance inputs boxBlob = BoxCollider.Create(new BoxGeometry { Orientation = quaternion.identity, Size = new float3(1) }); capsuleBlob = CapsuleCollider.Create(new CapsuleGeometry { Radius = 0.5f, Vertex0 = new float3(1f), Vertex1 = new float3(-1f) }); sphereBlob = SphereCollider.Create(new SphereGeometry { Radius = 0.5f }); var children = new NativeArray <CompoundCollider.ColliderBlobInstance>(8, Allocator.Temp) { [0] = new CompoundCollider.ColliderBlobInstance { Collider = boxBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(0f)) }, [1] = new CompoundCollider.ColliderBlobInstance { Collider = capsuleBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(1f)) }, [2] = new CompoundCollider.ColliderBlobInstance { Collider = boxBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(2f)) }, [3] = new CompoundCollider.ColliderBlobInstance { Collider = sphereBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(3f)) }, [4] = new CompoundCollider.ColliderBlobInstance { Collider = boxBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(4f)) }, [5] = new CompoundCollider.ColliderBlobInstance { Collider = capsuleBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(5f)) }, [6] = new CompoundCollider.ColliderBlobInstance { Collider = boxBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(6f)) }, [7] = new CompoundCollider.ColliderBlobInstance { Collider = sphereBlob, CompoundFromChild = new RigidTransform(quaternion.identity, new float3(7f)) } }; compoundBlob = CompoundCollider.Create(children); var compound = (CompoundCollider *)compoundBlob.GetUnsafePtr(); var uniqueChildren = new HashSet <long>(); for (var i = 0; i < compound->Children.Length; i++) { uniqueChildren.Add((long)compound->Children[i].Collider); } Assert.That(uniqueChildren.Count, Is.EqualTo(3)); } finally { boxBlob.Dispose(); capsuleBlob.Dispose(); sphereBlob.Dispose(); if (compoundBlob.IsCreated) { compoundBlob.Dispose(); } } }
public void Execute() => SphereCollider.Create(new SphereGeometry { Radius = 1f }).Release();
protected override BlobAssetReference <Collider> ProduceColliderBlob(PhysicsShapeAuthoring shape) { var material = ProduceMaterial(shape); var collisionFilter = ProduceCollisionFilter(shape); BlobAssetReference <Collider> blob = default; switch (shape.ShapeType) { case ShapeType.Box: blob = BoxCollider.Create( shape.GetBakedBoxProperties(), collisionFilter, material); break; case ShapeType.Capsule: blob = CapsuleCollider.Create( shape.GetBakedCapsuleProperties(out var center, out var height, out var orientation), collisionFilter, material); break; case ShapeType.Sphere: blob = SphereCollider.Create( shape.GetBakedSphereProperties(out orientation), collisionFilter, material); break; case ShapeType.Cylinder: blob = CylinderCollider.Create( shape.GetBakedCylinderProperties(), collisionFilter, material); break; case ShapeType.Plane: shape.GetBakedPlaneProperties(out var v0, out var v1, out var v2, out var v3); blob = PolygonCollider.CreateQuad( v0, v1, v2, v3, collisionFilter, material); break; case ShapeType.ConvexHull: var pointCloud = new NativeList <float3>(65535, Allocator.Temp); shape.GetConvexHullProperties(pointCloud); if (pointCloud.Length == 0) { throw new InvalidOperationException( $"No vertices associated with {shape.name}. Add a {typeof(MeshFilter)} component or assign a readable {nameof(PhysicsShapeAuthoring.CustomMesh)}." ); } shape.GetBakedConvexProperties(pointCloud, out var hullGenerationParameters); RegisterConvexColliderDeferred( shape, pointCloud, hullGenerationParameters.ToRunTime(), collisionFilter, material ); pointCloud.Dispose(); break; case ShapeType.Mesh: const int defaultVertexCount = 2048; pointCloud = new NativeList <float3>(defaultVertexCount, Allocator.Temp); var triangles = new NativeList <int>((defaultVertexCount - 2) * 3, Allocator.Temp); shape.GetBakedMeshProperties(pointCloud, triangles); if (pointCloud.Length == 0 || triangles.Length == 0) { triangles.Dispose(); pointCloud.Dispose(); throw new InvalidOperationException( $"Invalid mesh data associated with {shape.name}. " + $"Add a {typeof(MeshFilter)} component or assign a {nameof(PhysicsShapeAuthoring.CustomMesh)}. " + "Ensure that you have enabled Read/Write on the mesh's import settings." ); } RegisterMeshColliderDeferred(shape, pointCloud, triangles, collisionFilter, material); triangles.Dispose(); pointCloud.Dispose(); break; default: throw new UnimplementedShapeException(shape.ShapeType); } return(blob); }
protected unsafe override void OnUpdate() { PhysicsWorld physicsWorld = _worldBuildSystem.PhysicsWorld; NativeMultiHashMap <Entity, HitboxCollision> collisions = _collisions; collisions.Clear(); var collisionWriter = collisions.AsParallelWriter(); Entities .WithName("QueryHitboxCollisons") .WithReadOnly(physicsWorld) .ForEach((Entity entity, ref Hitbox hitbox, ref HitboxState state, in LocalToWorld transform) => { if (!state.Enabled) { return; } BlobAssetReference <Collider> collider = SphereCollider.Create(new SphereGeometry { Center = float3.zero, Radius = hitbox.Radius }, new CollisionFilter { BelongsTo = (uint)PhysicsLayers.HITBOX, CollidesWith = (uint)PhysicsLayers.HITBOX, }); float3 position = math.transform(transform.Value, float3.zero); var hits = new NativeList <ColliderCastHit>(Allocator.Temp); physicsWorld.CastCollider(new ColliderCastInput { Collider = (Collider *)collider.GetUnsafePtr(), Start = state.PreviousPosition ?? position, End = position, Orientation = float4.zero }, ref hits); collider.Dispose(); state.PreviousPosition = position; for (var i = 0; i < hits.Length; i++) { var hit = hits[i]; if (!HasComponent <Hurtbox>(hit.Entity)) { continue; } var hurtbox = GetComponent <Hurtbox>(hit.Entity); if (!hurtbox.Enabled || hurtbox.Player == Entity.Null || hurtbox.Player == state.Player) { continue; } collisionWriter.Add(hurtbox.Player, new HitboxCollision { OriginPlayer = entity, Hitbox = hitbox, Hurtbox = hurtbox, }); } }).ScheduleParallel(); Entities .WithName("ApplyCollisions") .WithReadOnly(collisions) .ForEach((Entity entity, ref PlayerComponent player, in PlayerConfig config, in CharacterFrame frame) => { NativeArray <HitboxCollision>?playerCollisions = collisions.CopyValuesForKey(entity); if (playerCollisions == null) { return; } // Sort collisions playerCollisions.Value.Sort(); }).Schedule();