[FREE] Better Convex Mesh Collider Generator: CoACD!

Are you tired of wrestling with complex mesh decomposition for your dynamic rigid bodies in Unity? Look no further! We’re thrilled to introduce CoACD (Collision-Aware Convex Decomposition), a free and fully open-source package that takes your mesh decomposition to the next level, ensuring precision and accuracy in collision simulations.

Why Convex Mesh Decomposition Matters

In Unity, dynamic rigid bodies require convex meshes to function properly. While enabling the convex setting and generating a convex hull of your mesh can be sufficient for some cases, many scenarios demand a more meticulous approach. Splitting your mesh into smaller, convex parts and computing their convex hulls individually is often the key to achieving realistic collision simulations.

Previously, the go-to solution for this task was the V-HACD algorithm. While V-HACD works well for simpler cases, it falls short when dealing with complex geometries, such as bowls or vases. It tends to fill the interior of these shapes, leading to unsatisfactory results.

CoACD is here to address these challenges head-on. This package is fully open-source, released under the Apache v2 license, and is designed to outperform V-HACD in precision and reliability. Take a look at the image above, and you’ll see how CoACD excels in mesh splitting, particularly in collision-aware scenarios. It’s tailored to solve complicated cases like bowls and vases, ensuring accurate and realistic results.

Key Features of CoACD

  • Collision-Aware Decomposition: CoACD splits your mesh with collision simulations in mind, providing results that are true to real-world physics.

  • Open Source: We believe in the power of the community. CoACD is free and open source, enabling collaboration and innovation.

  • Precise Results: Say goodbye to interior fillings and glitches. CoACD guarantees precision even in complex cases.

  • Easy Integration: CoACD seamlessly integrates into your Unity project, making the setup process a breeze. CoACD supports Windows, Linux and MacOS.

Get Started with CoACD Today!

If you have any questions or need assistance, feel free to ask in this thread. We’re here to support you on your journey to better mesh decomposition and collision simulations in Unity.

Github: https://github.com/SarahWeiii/CoACD

To install CoACD into your unity project:

  • Open the Package Manager from Window → Package Manager.
  • Find and click the + button in the upper lefthand corner of the window. Select Add package from git URL (see the screenshot).
  • Enter the following URL: https://github.com/SarahWeiii/CoACD.git?path=/Packages/info.flandre.coacd#unity
  • Click “Add”.

To use CoACD:

  • Add a CoACD component to your object. You can tweak the parameters in the editor.
  • Right click the component header lane. Then select Generate Collision Meshes or Generate Collision Meshes for Hierarchy to generate collision for the current object or all children of the current object that contains a MeshFilter, respectively. You usually want **Generate Collision Meshes for Hierarchy**.
  • Unity mesh colliders will be created in the scene under Collision as a child of each object.



Check here for an example project leveraging CoACD for articulation simulation.

8 Likes

Looks great, but seems there is no way to save the generated collider meshes in the prefab. Each time I do it by any of 2 scenarios in Editor (not runtime):

  1. generating in prefab view
  2. generating in scene view selecting particular prefab
    I see meshed in Collisions parent, but when I open prefab after applying changes or exit from prefab view meshes are destroyed.

If I generate colliders for any other not prefab object seems meshes don’t disappear.

Am I doing something wrong?

This is due to unity’s logic of referencing mesh data in scene. You can use the following script to save meshes to a separate asset, which should allow you to reference in a prefab.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[ExecuteInEditMode]
public class SaveHierarchyMeshes : MonoBehaviour
{
    public bool justDoIt = false;
    public string assetPath = "Assets/untitled.asset";
    // Update is called once per frame
    void Update()
    {
        if (justDoIt)
        {
            justDoIt = false;
            AssetDatabase.CreateAsset(new TextAsset(gameObject.name), assetPath);
            foreach (var mesh in GetComponentsInChildren<MeshFilter>())
            {
                AssetDatabase.AddObjectToAsset(mesh.sharedMesh, assetPath);
            }
        }
    }
}

This looks better

public class SaveMeshToAsset : MonoBehaviour
    {
        private enum Method
        {
            Single,
            Hierarchy
        }

        [SerializeField]
        private GameObject _parent;

        [SerializeField]
        private Method _method;

        [SerializeField]
        private bool _saveAsTextAsset;

        [SerializeField]
        private string _saveDirectoryPath = "Assets/";

        //[Button("Save")]
        [ContextMenu("Save", false, 10000002)]
        private void Save()
        {
            if (string.IsNullOrEmpty(_saveDirectoryPath)) return;

            if (_method == Method.Single)
            {
                SaveSingle();
            }
            else if (_method == Method.Hierarchy)
            {
                SaveInHierarchy();
            }
        }

        private void SaveSingle()
        {
            var meshFilter = _parent.GetComponentInChildren<MeshFilter>();
            if (meshFilter == null) return;

            var assetPath = new StringBuilder(_saveDirectoryPath).Append(gameObject.name).Append("_CoACD").Append(".asset").ToString();
            Debug.Log($"mesh asset path: {assetPath}");

            if (_saveAsTextAsset)
            {
                AssetDatabase.CreateAsset(new TextAsset(gameObject.name), assetPath);
                AssetDatabase.AddObjectToAsset(meshFilter.sharedMesh, assetPath);
            }
            else
            {
                AssetDatabase.CreateAsset(meshFilter.sharedMesh, assetPath);
            }

            Debug.Log($"Single mesh filter is saved. To test asset? {_saveAsTextAsset}");
        }

        private void SaveInHierarchy()
        {
            if (_saveAsTextAsset)
            {
                var assetPath = new StringBuilder(_saveDirectoryPath).Append(gameObject.name).Append("_CoACD").Append(".asset").ToString();

                AssetDatabase.CreateAsset(new TextAsset(gameObject.name), assetPath);
                foreach (var mesh in _parent.GetComponentsInChildren<MeshFilter>())
                {
                    if (mesh != null && mesh.sharedMesh != null)
                    {
                        AssetDatabase.AddObjectToAsset(mesh.sharedMesh, assetPath);
                    }
                }
            }
            else
            {
                foreach (var mesh in _parent.GetComponentsInChildren<MeshFilter>())
                {
                    var assetPath = new StringBuilder(_saveDirectoryPath).Append("/").Append(gameObject.name).Append("/").Append(mesh.gameObject.name).Append("_CoACD").Append(".asset").ToString();
                    AssetDatabase.CreateAsset(mesh.sharedMesh, assetPath);
                }
            }

            Debug.Log($"Hierarchy meshes are saved. To test asset? {_saveAsTextAsset}");
        }
    }

However, it works only if you do it in prefab mode. In case if you apply changes and save test asset in scene view and apply prefab changes, meshes will miss reference

1 Like

Sorry, can’t understand what to do with it. Newby here. could you give a step by step on how to implment this?

the first script succesfully creates an asset. but then what? should script something when spawning the prefab and associate it with the collision asset?

Finally something that works well! Thanks!
I added persistence a-la Unity V-HACD with all decomposed meshes neatly stored in a scriptable objects and stored where the source mesh is.
https://github.com/laurentopia/CoACD/tree/unity/Packages/info.flandre.coacd/Runtime

2 Likes

This looks tremendous, thanks for making this work in unity.

I’d be looking for a way to convert those mesh into 2D polygon colliders (hence with ordered vertice boundaries)

I have an issue where the created Collider Data asset loses it’s script after building. It still works as it should and the colliders get created, but it’s annoying seeing “The referenced script on this Behavious is missing” every time i run the game. Is there any way to fix this?

Is this supported on android/ios ?