Created
September 13, 2024 13:46
-
-
Save Andicraft/ec28b8690c7d6cbb13bb4fe29e7a7645 to your computer and use it in GitHub Desktop.
CoaCD collision generation for Godot 4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.InteropServices; | |
using Godot; | |
using Godot.Collections; | |
namespace CoACD_Godot; | |
/* Generates colliders using CoaCD - https://github.com/SarahWeiii/CoACD | |
* This is NOT a drag and drop file, but it should give you the framework you need to get started. | |
* | |
* Requires you to build the CoaCD library yourself to get the latest version. | |
* Put the lib_coacd.dll/so/dylib next to your Godot executable. | |
* | |
* Because this is unsafe code that interfaces with an unmanaged library, | |
* you might have to put this into a separate C# project from your main Godot project. | |
*/ | |
public unsafe class CoACD | |
{ | |
[Serializable] | |
public struct MeshInterface | |
{ | |
public double* vertices_ptr; | |
public ulong vertices_count; | |
public int* triangles_ptr; | |
public ulong triangles_count; | |
} | |
[Serializable] | |
public struct MeshArrayInterface : IDisposable | |
{ | |
public MeshInterface* meshes_ptr; | |
public ulong meshes_count; | |
public void Dispose() | |
{ | |
if (meshes_ptr != null) { | |
Free(this); | |
meshes_ptr = null; | |
} | |
} | |
} | |
[DllImport("lib_coacd", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CoACD_setLogLevel")] | |
static extern void SetLogLevel([MarshalAs(UnmanagedType.LPStr)] string level); | |
[DllImport("lib_coacd", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CoACD_freeMeshArray")] | |
static extern void Free(MeshArrayInterface array); | |
[DllImport("lib_coacd", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CoACD_run")] | |
static extern MeshArrayInterface Run(ref MeshInterface mesh, | |
double threshold, | |
int max_convex_hull, | |
int preprocess_mode, | |
int prep_resolution, | |
int sample_resolution, | |
int mcts_nodes, | |
int mcts_iteration, | |
int mcts_max_depth, | |
bool pca, | |
bool merge, | |
bool decimate, | |
int max_ch_vertex, | |
bool extrude, | |
double extrude_margin, | |
int apx_mode, | |
uint seed); | |
public enum PreprocessMode { Auto = 0, On = 1, Off = 2 } | |
public enum LogLevel { Off, Info, Warn, Error, Critical } | |
[Serializable] | |
public unsafe struct CoaCDParams | |
{ | |
public static CoaCDParams Init() => new CoaCDParams | |
{ | |
threshold = 0.05, | |
preprocessMode = PreprocessMode.Auto, | |
preprocessResolution = 50, | |
sampleResolution = 2000, | |
mctsNodes = 20, | |
mctsIteration = 150, | |
mctsMaxDepth = 3, | |
pca = false, | |
merge = true, | |
maxConvexHull = -1, | |
decimate = true, | |
max_ch_vertex = 65, | |
extrude = false, | |
extrude_margin = 0.01, | |
apx_mode = 0, | |
seed = 0 | |
}; | |
//[Range(0.01f, 1f)] | |
// Concavity threshold for terminating the decomposition | |
public double threshold; | |
// Choose manifold preprocessing mode ('auto': automatically check input mesh manifoldness; 'on': force turn on the pre-processing; 'off': force turn off the pre-processing) | |
public PreprocessMode preprocessMode; | |
//[Range(20, 100)] | |
// Resolution for manifold preprocess | |
public int preprocessResolution; | |
//[Range(1000, 10000)] | |
// Sampling resolution for Hausdorff distance calculation | |
public int sampleResolution; | |
//[Range(10, 40)] | |
// Max number of child nodes in MCTS | |
public int mctsNodes; | |
//[Range(60, 2000)] | |
// Number of search iterations in MCTS | |
public int mctsIteration; | |
//[Range(2, 7)] | |
// Max search depth in MCTS | |
public int mctsMaxDepth; | |
// Flag to enable PCA pre-processing | |
public bool pca; | |
public bool merge; | |
// Max number of convex hulls generated, -1 for no limit | |
public int maxConvexHull; | |
// Max # convex hulls in the result, -1 for no maximum limitation, works only when merge is enabled, default = -1 (may introduce convex hull with a concavity larger than the threshold | |
public bool decimate; // enable max vertex constraint per convex hull, default = false. | |
public int max_ch_vertex; // max vertex value for each convex hull, only when decimate is enabled, default = 256. | |
public bool extrude; // extrude neighboring convex hulls along the overlapping faces (other faces unchanged), default = false. | |
public double extrude_margin; // extrude margin, only when extrude is enabled, default = 0.01. | |
public int apx_mode; // approximation shape type ("ch" for convex hulls, "box" for cubes), default = "ch". | |
public uint seed; | |
} | |
public static Array<ConvexPolygonShape3D> RunACD(ArrayMesh mesh, CoaCDParams parameters) | |
{ | |
int vcount = mesh.GetFaces().Length; | |
var unityV = mesh.GetFaces(); | |
var unityF = new int[vcount]; | |
var v = new double[vcount * 3]; | |
for (var i = 0; i < vcount; i++) { | |
v[3 * i + 0] = unityV[i].X; | |
v[3 * i + 1] = unityV[i].Y; | |
v[3 * i + 2] = unityV[i].Z; | |
unityF[i] = i; | |
} | |
fixed (double* vptr = v) { | |
fixed (int* fptr = unityF) { | |
var mi = new MeshInterface() {vertices_ptr = vptr, vertices_count = (ulong) vcount, triangles_ptr = fptr, triangles_count = (ulong) (unityF.LongLength / 3)}; | |
using var res = Run(ref mi, parameters.threshold, parameters.maxConvexHull, (int) parameters.preprocessMode, parameters.preprocessResolution, parameters.sampleResolution, | |
parameters.mctsNodes, parameters.mctsIteration, parameters.mctsMaxDepth, parameters.pca, parameters.merge, parameters.decimate, parameters.max_ch_vertex, parameters.extrude, parameters.extrude_margin, parameters.apx_mode, parameters.seed); | |
var shapes = new Array<ConvexPolygonShape3D>(); | |
for (ulong i = 0; i < res.meshes_count; i++) { | |
var shape = new ConvexPolygonShape3D(); | |
var verts = new Vector3[res.meshes_ptr[i].vertices_count]; | |
for (ulong j = 0; j < res.meshes_ptr[i].vertices_count; j++) { | |
verts[j] = new Vector3((float) res.meshes_ptr[i].vertices_ptr[j * 3 + 0], (float) res.meshes_ptr[i].vertices_ptr[j * 3 + 1], | |
(float) res.meshes_ptr[i].vertices_ptr[j * 3 + 2]); | |
} | |
shape.Points = verts; | |
shapes.Add(shape); | |
} | |
return shapes; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment