Skip to content

Instantly share code, notes, and snippets.

@pbhogan
Created May 23, 2023 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pbhogan/d9170ff611eff23229274bec9207a633 to your computer and use it in GitHub Desktop.
Save pbhogan/d9170ff611eff23229274bec9207a633 to your computer and use it in GitHub Desktop.
Unity Physics creating collider from mesh
using System;
using System.Runtime.CompilerServices;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Physics;
using UnityEngine;
using UnityEngine.Rendering;
using Collider = Unity.Physics.Collider;
using Material = Unity.Physics.Material;
namespace GallantGames
{
public struct ConvertMeshToNativeBuffersJob : IJob
{
[ReadOnly] public Mesh.MeshData MeshData;
[WriteOnly] public NativeArray<float3> MeshVertices;
[WriteOnly] public NativeArray<int3> MeshTriangles;
public void Execute()
{
MeshData.GetVertices( MeshVertices.Reinterpret<Vector3>() );
if (MeshData.indexFormat == IndexFormat.UInt16)
{
var indexData16 = MeshData.GetIndexData<ushort>();
var index16 = 0;
for (var sm = 0; sm < MeshData.subMeshCount; ++sm)
{
var subMesh = MeshData.GetSubMesh( sm );
for (int i = subMesh.indexStart, count = 0; count < subMesh.indexCount; i += 3, count += 3)
{
MeshTriangles[index16++] = (int3) new uint3( indexData16[i], indexData16[i + 1], indexData16[i + 2] );
}
}
}
else
{
var indexData32 = MeshData.GetIndexData<uint>();
var index32 = 0;
for (var sm = 0; sm < MeshData.subMeshCount; ++sm)
{
var subMesh = MeshData.GetSubMesh( sm );
for (int i = subMesh.indexStart, count = 0; count < subMesh.indexCount; i += 3, count += 3)
{
MeshTriangles[index32++] = (int3) new uint3( indexData32[i], indexData32[i + 1], indexData32[i + 2] );
}
}
}
}
}
public struct CreatePhysicsMeshColliderJob : IJob
{
[ReadOnly] public NativeArray<float3> MeshVertices;
[ReadOnly] public NativeArray<int3> MeshTriangles;
[ReadOnly] public CollisionFilter CollisionFilter;
[ReadOnly] public Material Material;
[WriteOnly] public NativeReference<BlobAssetReference<Collider>> Collider;
public void Execute()
{
Collider.Value = Unity.Physics.MeshCollider.Create( MeshVertices, MeshTriangles, CollisionFilter, Material );
}
}
public static class PhysicsUtility
{
public static BlobAssetReference<Collider> CreateColliderForMesh( Mesh mesh, CollisionFilter collisionFilter )
{
var material = new Material
{
FrictionCombinePolicy = Material.CombinePolicy.Maximum,
RestitutionCombinePolicy = Material.CombinePolicy.Maximum,
Friction = 0.5f,
Restitution = 0.5f
};
using var meshDataArray = Mesh.AcquireReadOnlyMeshData( mesh );
var meshData = meshDataArray[0];
var vertices = new NativeArray<float3>( meshData.vertexCount, Allocator.TempJob );
var triangles = new NativeArray<int3>( meshData.GetTriangleCount(), Allocator.TempJob );
var convertMeshToNativeBuffersJob = new ConvertMeshToNativeBuffersJob
{
MeshData = meshData,
MeshVertices = vertices,
MeshTriangles = triangles
};
convertMeshToNativeBuffersJob.Run();
var createPhysicsMeshColliderJob = new CreatePhysicsMeshColliderJob
{
MeshVertices = vertices,
MeshTriangles = triangles,
CollisionFilter = collisionFilter,
Material = material,
Collider = new NativeReference<BlobAssetReference<Collider>>( Allocator.TempJob )
};
createPhysicsMeshColliderJob.Run();
var collider = createPhysicsMeshColliderJob.Collider.Value;
createPhysicsMeshColliderJob.MeshVertices.Dispose();
createPhysicsMeshColliderJob.MeshTriangles.Dispose();
createPhysicsMeshColliderJob.Collider.Dispose();
return collider;
}
public static void AddComponentsForMesh( Entity entity, EntityManager entityManager, BlobAssetReference<Collider> collider, PhysicsBodyMotionType bodyMotionType = PhysicsBodyMotionType.Static )
{
entityManager.AddComponentData( entity, new PhysicsCollider { Value = collider } );
switch (bodyMotionType)
{
case PhysicsBodyMotionType.Dynamic:
entityManager.AddComponentData( entity, new PhysicsVelocity() );
entityManager.AddComponentData( entity, PhysicsMass.CreateDynamic( collider.Value.MassProperties, 1.0f ) );
break;
case PhysicsBodyMotionType.Kinematic:
entityManager.AddComponentData( entity, new PhysicsVelocity() );
entityManager.AddComponentData( entity, PhysicsMass.CreateKinematic( collider.Value.MassProperties ) );
break;
case PhysicsBodyMotionType.Static:
break;
default:
throw new ArgumentOutOfRangeException( nameof(bodyMotionType), bodyMotionType, null );
}
entityManager.AddSharedComponentManaged( entity, new PhysicsWorldIndex { Value = 0 } );
}
public static void AddComponentsForMesh( Entity entity, EntityManager entityManager, Mesh mesh, CollisionFilter collisionFilter, PhysicsBodyMotionType bodyMotionType = PhysicsBodyMotionType.Static )
{
var collider = CreateColliderForMesh( mesh, collisionFilter );
AddComponentsForMesh( entity, entityManager, collider, bodyMotionType );
}
public static void AddComponentsForMesh( Entity entity, EntityCommandBuffer entityCommandBuffer, BlobAssetReference<Collider> collider, PhysicsBodyMotionType bodyMotionType = PhysicsBodyMotionType.Static )
{
entityCommandBuffer.AddComponent( entity, new PhysicsCollider { Value = collider } );
switch (bodyMotionType)
{
case PhysicsBodyMotionType.Dynamic:
entityCommandBuffer.AddComponent( entity, new PhysicsVelocity() );
entityCommandBuffer.AddComponent( entity, PhysicsMass.CreateDynamic( collider.Value.MassProperties, 1.0f ) );
break;
case PhysicsBodyMotionType.Kinematic:
entityCommandBuffer.AddComponent( entity, new PhysicsVelocity() );
entityCommandBuffer.AddComponent( entity, PhysicsMass.CreateKinematic( collider.Value.MassProperties ) );
break;
case PhysicsBodyMotionType.Static:
break;
default:
throw new ArgumentOutOfRangeException( nameof(bodyMotionType), bodyMotionType, null );
}
entityCommandBuffer.AddSharedComponent( entity, new PhysicsWorldIndex { Value = 0 } );
}
public static void AddComponentsForMesh( Entity entity, EntityCommandBuffer entityCommandBuffer, Mesh mesh, CollisionFilter collisionFilter, PhysicsBodyMotionType bodyMotionType = PhysicsBodyMotionType.Static )
{
var collider = CreateColliderForMesh( mesh, collisionFilter );
AddComponentsForMesh( entity, entityCommandBuffer, collider, bodyMotionType );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment