static Hash128 GetHash128_FromMesh( UnityMesh mesh, float4x4 leafToBody, ConvexHullGenerationParameters convexHullGenerationParameters = default, Material material = default, CollisionFilter filter = default, float4x4 shapeFromBody = default, uint uniqueIdentifier = default, int[] includedIndices = default, float[] blendShapeWeights = default ) { // BUG: use TempJob to avoid InvalidOperationException triggered by NativeList.AddRange() inside SpookyHashBuilder using (var allIncludedIndices = new NativeList <int>(0, Allocator.TempJob)) using (var allBlendShapeWeights = new NativeList <float>(0, Allocator.TempJob)) using (var indices = new NativeArray <int>(includedIndices ?? Array.Empty <int>(), Allocator.TempJob)) using (var blendWeights = new NativeArray <float>(blendShapeWeights ?? Array.Empty <float>(), Allocator.TempJob)) return(HashableShapeInputs.GetHash128( uniqueIdentifier, convexHullGenerationParameters, material, filter, shapeFromBody, new NativeArray <HashableShapeInputs>(1, Allocator.Temp) { [0] = HashableShapeInputs.FromSkinnedMesh( mesh, leafToBody, indices, allIncludedIndices, blendWeights, allBlendShapeWeights ) }, allIncludedIndices, allBlendShapeWeights )); }
internal static void GetBakedConvexProperties( this PhysicsShapeAuthoring shape, NativeList <float3> pointCloud, out ConvexHullGenerationParameters generationParameters, out Hash128 hashedInputs ) { using (var inputs = new NativeList <HashableShapeInputs>(8, Allocator.TempJob)) using (var allSkinIndices = new NativeList <int>(4096, Allocator.TempJob)) using (var allBlendShapeWeights = new NativeList <float>(64, Allocator.TempJob)) { shape.GetConvexHullProperties(pointCloud, true, inputs, allSkinIndices, allBlendShapeWeights); shape.BakePoints(pointCloud); // compute convex radius var center = float3.zero; var orientation = EulerAngles.Default; var localToWorld = shape.transform.localToWorldMatrix; var shapeToWorld = shape.GetShapeToWorldMatrix(); var bakeToShape = GetPrimitiveBakeToShapeMatrix(localToWorld, shapeToWorld, ref center, ref orientation, 1f, k_DefaultAxisPriority); using (var aabb = new NativeArray <Aabb>(1, Allocator.TempJob)) { new GetAabbJob { Points = pointCloud, Aabb = aabb }.Run(); HashableShapeInputs.GetQuantizedTransformations(bakeToShape, aabb[0], out bakeToShape); } var s = new float3(math.length(bakeToShape[0]), math.length(bakeToShape[1]), math.length(bakeToShape[2])); generationParameters = shape.ConvexHullGenerationParameters; generationParameters.SimplificationTolerance = math.max( ConvexHullGenerationParametersExtensions.k_MinRecommendedSimplificationTolerance, math.cmax(s) * generationParameters.SimplificationTolerance ); generationParameters.BevelRadius *= math.cmin(s); using (var hash = new NativeArray <Hash128>(1, Allocator.TempJob)) { var job = new GetShapeInputsHashJob { Result = hash, ForceUniqueIdentifier = (uint)(shape.ForceUnique ? shape.GetInstanceID() : 0), GenerationParameters = generationParameters, Material = shape.GetMaterial(), CollisionFilter = shape.GetFilter(), BakeFromShape = shape.GetLocalToShapeMatrix(), Inputs = inputs, AllSkinIndices = allSkinIndices, AllBlendShapeWeights = allBlendShapeWeights }; job.Run(); hashedInputs = hash[0]; } } }
// used to hash convex hull generation properties in a way that is robust to imprecision internal static uint GetStableHash( this ConvexHullGenerationParameters generationParameters, ConvexHullGenerationParameters hashedParameters, float tolerance = k_HashFloatTolerance ) { var differences = new float3( generationParameters.BevelRadius - hashedParameters.BevelRadius, generationParameters.MinimumAngle - hashedParameters.MinimumAngle, generationParameters.SimplificationTolerance - hashedParameters.SimplificationTolerance ); return(math.cmax(math.abs(differences)) < tolerance ? unchecked ((uint)hashedParameters.GetHashCode()) : unchecked ((uint)generationParameters.GetHashCode())); }
public void SchedulePreviewIfChanged(PhysicsShapeAuthoring shape) { using (var currentPoints = new NativeList <float3>(65535, Allocator.Temp)) { var hash = GetInputHash( shape, currentPoints, m_HashedPoints, m_HashedConvexParameters, out var currentConvexParameters ); if (m_InputHash == hash) { return; } m_InputHash = hash; m_HashedConvexParameters = currentConvexParameters; m_HashedPoints.Dispose(); m_HashedPoints = new NativeArray <float3>(currentPoints.Length, Allocator.Persistent); m_HashedPoints.CopyFrom(currentPoints); } if (shape.ShapeType != ShapeType.ConvexHull && shape.ShapeType != ShapeType.Mesh) { return; } // TODO: cache results per input data hash, and simply use existing data (e.g., to make undo/redo faster) var output = new NativeArray <BlobAssetReference <Collider> >(1, Allocator.Persistent); m_MostRecentlyScheduledJob = shape.ShapeType == ShapeType.Mesh ? ScheduleMeshPreview(shape, output) : ScheduleConvexHullPreview(shape, output); m_PreviewJobsOutput.Add(m_MostRecentlyScheduledJob, output); if (m_PreviewJobsOutput.Count == 1) { CheckPreviewJobsForCompletion(); EditorApplication.update += CheckPreviewJobsForCompletion; EditorApplication.delayCall += () => { SceneViewUtility.DisplayProgressNotification( Styles.PreviewGenerationNotification, () => float.PositiveInfinity ); }; } }
public static unsafe Hash128 GetHash128( uint uniqueIdentifier, ConvexHullGenerationParameters hullGenerationParameters, Material material, CollisionFilter filter, float4x4 bakeFromShape, NativeArray <HashableShapeInputs> inputs, NativeArray <int> allIncludedIndices, NativeArray <float> allBlendShapeWeights, float linearPrecision = k_DefaultLinearPrecision ) { var numInputs = inputs.IsCreated ? inputs.Length : 0; // quantize shape-level transforms var bounds = new Aabb { Min = float.MaxValue, Max = float.MinValue }; for (int i = 0; i < numInputs; i++) { var d = inputs[i]; bounds.Include(math.mul(d.BodyFromShape, new float4(d.Bounds.Min, 1f)).xyz); bounds.Include(math.mul(d.BodyFromShape, new float4(d.Bounds.Max, 1f)).xyz); } GetQuantizedTransformations(bakeFromShape, bounds, out var bakeMatrix, linearPrecision); // bakeFromShape only contains scale/shear information, so only the inner 3x3 needs to contribute to the hash var scaleShear = new float3x3(bakeMatrix.c0.xyz, bakeMatrix.c1.xyz, bakeMatrix.c2.xyz); var bytes = new NativeList <byte>(Allocator.Temp); bytes.Append(ref uniqueIdentifier); bytes.Append(ref hullGenerationParameters); bytes.Append(ref material); bytes.Append(ref filter); bytes.Append(ref scaleShear); bytes.Append(inputs); bytes.Append(allIncludedIndices); bytes.Append(allBlendShapeWeights); return(HashUtility.Hash128(bytes.GetUnsafeReadOnlyPtr(), bytes.Length)); }
internal void RegisterConvexColliderDeferred( T shape, NativeArray <float3> points, ConvexHullGenerationParameters generationParameters, CollisionFilter filter, Material material ) { m_ConvexShapes.Add(shape); m_ConvexColliderJobs.Add(new ConvertConvexColliderInput { BodyEntity = GetPrimaryEntity(GetPrimaryBody(shape)), LeafEntity = GetPrimaryEntity(shape), CompoundFromChild = GetCompoundFromChild(shape), GenerationParameters = generationParameters, PointsStart = m_ConvexColliderPoints.Length, PointCount = points.Length, Filter = filter, Material = material }); m_ConvexColliderPoints.AddRange(points); }
internal static void GetBakedConvexProperties( this PhysicsShapeAuthoring shape, NativeList <float3> pointCloud, out ConvexHullGenerationParameters generationParameters ) { shape.GetConvexHullProperties(pointCloud); shape.BakePoints(pointCloud); // compute convex radius var center = float3.zero; var orientation = EulerAngles.Default; var bakeToShape = GetPrimitiveBakeToShapeMatrix(shape, ref center, ref orientation, 1f, k_DefaultAxisPriority); var s = new float3(math.length(bakeToShape[0]), math.length(bakeToShape[1]), math.length(bakeToShape[2])); generationParameters = shape.ConvexHullGenerationParameters; generationParameters.SimplificationTolerance = math.max( ConvexHullGenerationParametersExtensions.k_MinRecommendedSimplificationTolerance, math.cmax(s) * generationParameters.SimplificationTolerance ); generationParameters.BevelRadius *= math.cmin(s); }
unsafe uint GetInputHash( PhysicsShapeAuthoring shape, NativeList <float3> currentPoints, NativeArray <float3> hashedPoints, ConvexHullGenerationParameters hashedConvexParameters, out ConvexHullGenerationParameters currentConvexProperties ) { currentConvexProperties = default; switch (shape.ShapeType) { case ShapeType.ConvexHull: shape.GetBakedConvexProperties(currentPoints, out currentConvexProperties); return(math.hash( new uint3( (uint)shape.ShapeType, currentConvexProperties.GetStableHash(hashedConvexParameters), currentPoints.GetStableHash(hashedPoints) ) )); case ShapeType.Mesh: var indices = new NativeList <int>(65535, Allocator.Temp); shape.GetBakedMeshProperties(currentPoints, indices); return(math.hash( new uint3( (uint)shape.ShapeType, currentPoints.GetStableHash(hashedPoints), math.hash(indices.GetUnsafePtr(), UnsafeUtility.SizeOf <int>() * indices.Length) ) )); default: return((uint)shape.ShapeType); } }
public static BodyInfo CreateBody(GameObject gameObject) { var bounds = gameObject.GetComponent <MeshRenderer>().bounds; var basicBodyInfo = gameObject.GetComponent <BasicBodyInfo>(); BlobAssetReference <Unity.Physics.Collider> collider = default; switch (basicBodyInfo.Type) { case BodyType.Sphere: float radius = math.cmax(bounds.extents); collider = Unity.Physics.SphereCollider.Create( new SphereGeometry { Center = float3.zero, Radius = radius }); break; case BodyType.Box: collider = Unity.Physics.BoxCollider.Create( new BoxGeometry { Center = float3.zero, Orientation = quaternion.identity, Size = bounds.size, BevelRadius = 0.0f }); break; case BodyType.ConvexHull: var mesh = gameObject.GetComponent <MeshFilter>().mesh; var scale = gameObject.transform.lossyScale; NativeArray <float3> points = new NativeArray <float3>(mesh.vertexCount, Allocator.Temp); for (int i = 0; i < mesh.vertexCount; i++) { points[i] = mesh.vertices[i]; points[i] *= scale; } ConvexHullGenerationParameters def = ConvexHullGenerationParameters.Default; def.BevelRadius = 0.0f; collider = Unity.Physics.ConvexCollider.Create( points, def, CollisionFilter.Default); break; case BodyType.Capsule: var capsuleRadius = math.cmin(bounds.extents); var capsuleLength = math.cmax(bounds.extents); var capsuleGeometry = new CapsuleGeometry { Radius = capsuleRadius, Vertex0 = new float3(0, capsuleLength - capsuleRadius, 0f), Vertex1 = new float3(0, -1.0f * (capsuleLength - capsuleRadius), 0f) }; collider = Unity.Physics.CapsuleCollider.Create(capsuleGeometry); break; default: Assert.IsTrue(false, "Invalid body type"); break; } bool isDynamic = !gameObject.GetComponent <BasicBodyInfo>().IsStatic; return(new BodyInfo { Mass = isDynamic ? basicBodyInfo.Mass : 0f, Collider = collider, AngularVelocity = float3.zero, LinearVelocity = float3.zero, Orientation = gameObject.transform.rotation, Position = gameObject.transform.position, IsDynamic = isDynamic }); }
public void TestConvexColliderCreateInvalid() { // Invalid points { var validBevelRadius = new ConvexHullGenerationParameters { BevelRadius = 0.15f }; // invalid point, +inf { var invalidPoints = new NativeArray <float3>(6, Allocator.TempJob) { [0] = new float3(1.45f, 8.67f, 3.45f), [1] = new float3(8.75f, 1.23f, 6.44f), [2] = new float3(float.PositiveInfinity, 5.33f, -2.55f), [3] = new float3(8.76f, 4.56f, -4.54f), [4] = new float3(9.75f, -0.45f, -8.99f), [5] = new float3(7.66f, 3.44f, 0.0f) }; TestUtils.ThrowsException <ArgumentException>( () => ConvexCollider.Create(invalidPoints, validBevelRadius, CollisionFilter.Default) ); invalidPoints.Dispose(); } // invalid point, -inf { var invalidPoints = new NativeArray <float3>(6, Allocator.TempJob) { [0] = new float3(1.45f, 8.67f, 3.45f), [1] = new float3(8.75f, 1.23f, 6.44f), [2] = new float3(float.NegativeInfinity, 5.33f, -2.55f), [3] = new float3(8.76f, 4.56f, -4.54f), [4] = new float3(9.75f, -0.45f, -8.99f), [5] = new float3(7.66f, 3.44f, 0.0f) }; TestUtils.ThrowsException <ArgumentException>( () => ConvexCollider.Create(invalidPoints, validBevelRadius, CollisionFilter.Default) ); invalidPoints.Dispose(); } // invalid point, NaN { var invalidPoints = new NativeArray <float3>(6, Allocator.TempJob) { [0] = new float3(1.45f, 8.67f, 3.45f), [1] = new float3(8.75f, 1.23f, 6.44f), [2] = new float3(float.NaN, 5.33f, -2.55f), [3] = new float3(8.76f, 4.56f, -4.54f), [4] = new float3(9.75f, -0.45f, -8.99f), [5] = new float3(7.66f, 3.44f, 0.0f) }; TestUtils.ThrowsException <ArgumentException>( () => ConvexCollider.Create(invalidPoints, validBevelRadius, CollisionFilter.Default) ); invalidPoints.Dispose(); } } // invalid convex radius { var points = new NativeArray <float3>(6, Allocator.TempJob) { [0] = new float3(1.45f, 8.67f, 3.45f), [1] = new float3(8.75f, 1.23f, 6.44f), [2] = new float3(7.54f, 5.33f, -2.55f), [3] = new float3(8.76f, 4.56f, -4.54f), [4] = new float3(9.75f, -0.45f, -8.99f), [5] = new float3(7.66f, 3.44f, 0.0f) }; float3 scale = new float3(1.0f, 1.0f, 1.0f); var invalidBevelRadius = new ConvexHullGenerationParameters(); // negative convex radius { invalidBevelRadius.BevelRadius = -0.30f; TestUtils.ThrowsException <ArgumentException>( () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default) ); } // +inf convex radius { invalidBevelRadius.BevelRadius = float.PositiveInfinity; TestUtils.ThrowsException <ArgumentException>( () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default) ); } // -inf convex radius { invalidBevelRadius.BevelRadius = float.NegativeInfinity; TestUtils.ThrowsException <ArgumentException>( () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default) ); } // nan convex radius { invalidBevelRadius.BevelRadius = float.NaN; TestUtils.ThrowsException <ArgumentException>( () => ConvexCollider.Create(points, invalidBevelRadius, CollisionFilter.Default) ); } points.Dispose(); } }