using Unity.Burst; using Unity.Collections; using Unity.Jobs; using Unity.Mathematics; using UnityEngine; namespace Unity.Physics.Authoring { static partial class PhysicsShapeExtensions { #region Box [BurstCompile] internal struct BakeBoxJob : IJob { public NativeArray Box; public float4x4 LocalToWorld; public float4x4 ShapeToWorld; public EulerAngles Orientation; public bool BakeUniformScale; public void Execute() { var center = Box[0].Center; var size = Box[0].Size; var bevelRadius = Box[0].BevelRadius; quaternion orientation = Orientation; var bakeToShape = Math.GetBakeToShape(LocalToWorld, ShapeToWorld, ref center, ref orientation, BakeUniformScale); bakeToShape = math.mul(bakeToShape, float4x4.Scale(size)); var scale = bakeToShape.DecomposeScale(); size = scale; Box[0] = new BoxGeometry { Center = center, Orientation = orientation, Size = size, BevelRadius = math.clamp(bevelRadius, 0f, 0.5f * math.cmin(size)), }; } } #endregion #region Capsule [BurstCompile] internal struct BakeCapsuleJob : IJob { public NativeArray Capsule; public float4x4 LocalToWorld; public float4x4 ShapeToWorld; public bool BakeUniformScale; public void Execute() { var radius = Capsule[0].Radius; var center = Capsule[0].Center; var height = Capsule[0].Height; quaternion orientation = Capsule[0].OrientationEuler; var bakeToShape = Math.GetBakeToShape(LocalToWorld, ShapeToWorld, ref center, ref orientation, BakeUniformScale, makeZAxisPrimaryBasis: true); var scale = bakeToShape.DecomposeScale(); radius *= math.cmax(scale.xy); height = math.max(0, height * scale.z); Capsule[0] = new CapsuleGeometryAuthoring { OrientationEuler = orientation, Center = center, Height = height, Radius = radius }; } } #endregion #region Cylinder [BurstCompile] internal struct BakeCylinderJob : IJob { public NativeArray Cylinder; public float4x4 LocalToWorld; public float4x4 ShapeToWorld; public EulerAngles Orientation; public bool BakeUniformScale; public void Execute() { var center = Cylinder[0].Center; var height = Cylinder[0].Height; var radius = Cylinder[0].Radius; var bevelRadius = Cylinder[0].BevelRadius; quaternion orientation = Orientation; var bakeToShape = Math.GetBakeToShape(LocalToWorld, ShapeToWorld, ref center, ref orientation, BakeUniformScale, makeZAxisPrimaryBasis: true); var scale = bakeToShape.DecomposeScale(); height *= scale.z; radius *= math.cmax(scale.xy); Cylinder[0] = new CylinderGeometry { Center = center, Orientation = orientation, Height = height, Radius = radius, BevelRadius = math.min(bevelRadius, math.min(height * 0.5f, radius)), SideCount = Cylinder[0].SideCount }; } } internal static CylinderGeometry BakeToBodySpace( this CylinderGeometry cylinder, float4x4 localToWorld, float4x4 shapeToWorld, EulerAngles orientation, bool bakeUniformScale = true ) { using (var geometry = new NativeArray(1, Allocator.TempJob) { [0] = cylinder }) { var job = new BakeCylinderJob { Cylinder = geometry, LocalToWorld = localToWorld, ShapeToWorld = shapeToWorld, Orientation = orientation, BakeUniformScale = bakeUniformScale }; job.Run(); return geometry[0]; } } #endregion #region Sphere [BurstCompile] struct BakeSphereJob : IJob { public NativeArray Sphere; public NativeArray Orientation; public float4x4 LocalToWorld; public float4x4 ShapeToWorld; public bool BakeUniformScale; public void Execute() { var center = Sphere[0].Center; var radius = Sphere[0].Radius; quaternion orientation = Orientation[0]; var basisToWorld = Math.GetBasisToWorldMatrix(LocalToWorld, center, orientation, 1f); var basisPriority = basisToWorld.HasShear() ? Math.GetBasisAxisPriority(basisToWorld) : Math.Constants.DefaultAxisPriority; var bakeToShape = Math.GetPrimitiveBakeToShapeMatrix(LocalToWorld, ShapeToWorld, ref center, ref orientation, basisPriority, BakeUniformScale); radius *= math.cmax(bakeToShape.DecomposeScale()); Sphere[0] = new SphereGeometry { Center = center, Radius = radius }; Orientation[0] = orientation; } } internal static SphereGeometry BakeToBodySpace( this SphereGeometry sphere, float4x4 localToWorld, float4x4 shapeToWorld, ref EulerAngles orientation, bool bakeUniformScale = true ) { using (var geometry = new NativeArray(1, Allocator.TempJob) { [0] = sphere }) using (var outOrientation = new NativeArray(1, Allocator.TempJob) { [0] = orientation }) { var job = new BakeSphereJob { Sphere = geometry, Orientation = outOrientation, LocalToWorld = localToWorld, ShapeToWorld = shapeToWorld, BakeUniformScale = bakeUniformScale }; job.Run(); orientation = outOrientation[0]; return geometry[0]; } } #endregion #region Plane [BurstCompile] struct BakePlaneJob : IJob { public NativeArray Vertices; public float3 Center; public float2 Size; public EulerAngles Orientation; public float4x4 BakeFromShape; public void Execute() { var v = Vertices[0]; GetPlanePoints(Center, Size, Orientation, out v.c0, out v.c1, out v.c2, out v.c3); v.c0 = math.mul(BakeFromShape, new float4(v.c0, 1f)).xyz; v.c1 = math.mul(BakeFromShape, new float4(v.c1, 1f)).xyz; v.c2 = math.mul(BakeFromShape, new float4(v.c2, 1f)).xyz; v.c3 = math.mul(BakeFromShape, new float4(v.c3, 1f)).xyz; Vertices[0] = v; } } internal static void BakeToBodySpace( float3 center, float2 size, EulerAngles orientation, float4x4 bakeFromShape, out float3 vertex0, out float3 vertex1, out float3 vertex2, out float3 vertex3 ) { using (var geometry = new NativeArray(1, Allocator.TempJob)) { var job = new BakePlaneJob { Vertices = geometry, Center = center, Size = size, Orientation = orientation, BakeFromShape = bakeFromShape }; job.Run(); vertex0 = geometry[0].c0; vertex1 = geometry[0].c1; vertex2 = geometry[0].c2; vertex3 = geometry[0].c3; } } internal static void GetPlanePoints( float3 center, float2 size, EulerAngles orientation, out float3 vertex0, out float3 vertex1, out float3 vertex2, out float3 vertex3 ) { var sizeYUp = math.float3(size.x, 0, size.y); vertex0 = center + math.mul(orientation, sizeYUp * math.float3(-0.5f, 0, 0.5f)); vertex1 = center + math.mul(orientation, sizeYUp * math.float3(0.5f, 0, 0.5f)); vertex2 = center + math.mul(orientation, sizeYUp * math.float3(0.5f, 0, -0.5f)); vertex3 = center + math.mul(orientation, sizeYUp * math.float3(-0.5f, 0, -0.5f)); } #endregion #region ShapeInputHash #if !(UNITY_ANDROID && !UNITY_64) // !Android32 // Getting memory alignment errors from HashUtility.Hash128 on Android32 [BurstCompile] #endif internal struct GetShapeInputsHashJob : IJob { public NativeArray Result; public uint ForceUniqueIdentifier; public ConvexHullGenerationParameters GenerationParameters; public Material Material; public CollisionFilter CollisionFilter; public float4x4 BakeFromShape; [ReadOnly] public NativeArray Inputs; [ReadOnly] public NativeArray AllSkinIndices; [ReadOnly] public NativeArray AllBlendShapeWeights; public void Execute() { Result[0] = HashableShapeInputs.GetHash128( ForceUniqueIdentifier, GenerationParameters, Material, CollisionFilter, BakeFromShape, Inputs, AllSkinIndices, AllBlendShapeWeights ); } } #endregion } }