简体   繁体   中英

Simplify collision mesh of road-like system?

Given a tile-based road or sidewalk system in Unity in 3d like shown, I'm getting mini-bumps of rigidbodies moving over their seams (even for same vertical position & scale and when using box colliders for each tile). Is there a good way to eg combine the collision mesh into one super-simplified & all-flat mesh? I've had no luck with eg exporting as Object (neither with my mesh simplifier), as the apparent mini-bumps persist when re-importing and getting rid of the individual box colliders. My requirement isn't that it has to be real-time (though that would be a bit of a plus, if no downsides). Thanks!

道路系统

You can try Mesh.CombineMeshes to make a big collider out of all the small ones.

[RequireComponent(typeof(MeshCollider))]
public class MeshCompositeCollider : MonoBehaviour
{
    void Start()
    {
        var meshColliders = GetComponentsInChildren<MeshCollider>();
        var combine = new CombineInstance[meshColliders.Length];

        for (int i = 0; i < meshColliders.Length; i++)
        {
            combine[i].mesh = meshColliders[i].sharedMesh;
            combine[i].transform = meshColliders[i].transform.localToWorldMatrix;
            meshColliders[i].enabled = false;
        }

        var compositeMesh = new Mesh();
        compositeMesh.CombineMeshes(combine);
        //WeldVertices(compositeMesh);
        GetComponent<MeshCollider>().sharedMesh = compositeMesh;
        GetComponent<MeshCollider>().enabled = true;
    }
}

One thing to note: the resulting combined mesh is in world space coordinates, so if the gameObject this gets attached to has any transform changes they will be applied too.

This might be enough if you have the MeshCollider -> Cooking Options -> Weld Colocated Vertices enabled which should combine the vertices that have the same position.

If not, you can try to weld the vertices yourself to see if that fixes the problem.

public static void WeldVertices(Mesh aMesh, float aMaxDistDelta = 0.01f)
{
    var aMaxDelta = aMaxDistDelta * aMaxDistDelta;
    var verts = aMesh.vertices;    
    List<int> newVerts = new List<int>();
    int[] map = new int[verts.Length];
    // create mapping and filter duplicates.
    for (int i = 0; i < verts.Length; i++)
    {
        var p = verts[i];

        bool duplicate = false;
        for (int i2 = 0; i2 < newVerts.Count; i2++)
        {
            int a = newVerts[i2];
            if ((verts[a] - p).sqrMagnitude <= aMaxDelta)
            {
                map[i] = i2;
                duplicate = true;
                break;
            }
        }
        if (!duplicate)
        {
            map[i] = newVerts.Count;
            newVerts.Add(i);
        }
    }
    // create new vertices
    var verts2 = new Vector3[newVerts.Count];    
    for (int i = 0; i < newVerts.Count; i++)
    {
        int a = newVerts[i];
        verts2[i] = verts[a];        
    }
    // map the triangle to the new vertices
    var tris = aMesh.triangles;
    for (int i = 0; i < tris.Length; i++)
    {
        tris[i] = map[tris[i]];
    }

    aMesh.Clear();       
    aMesh.vertices = verts2;
    aMesh.triangles = tris;                
}


Here is an example (before and after): Above 6 colliders with clear gaps, below 1 collider with no gaps.

在此处输入图片说明

You are looking for something called a Composite Collider . 2D Tilemaps even have a checkbox for "Used by Composite". if you attached a Composite Collider 2D component to your tilemap object and tick "used by composite", it will combine all of the colliders into one large collider.

That being said, it looks like you're spawning pieces of road onto the grid using prefabs, and not building your map using the tilemap. You can still use a composite collider for a bunch of different GameObjects by ticking "Used by composite" on the collider, but it is a bit more involved than simply ticking a button on one component, as you will have to configure all of your gameobjects. If you can simplify down to using a tilemap for your roads, it should be much simpler.

Maybe, you don't need to change the circuit, change the car collision system instead:

  • Make a "invisible dummy car" with the real collider and input feedback and then make the real car (only the model, maybe, or with an extra collider for other kind of collisions detection (¿with power-ups?) but i think that with one collider in the dummy car will be enough)
  • Make the model follow the dummy position but interpolating the vertical glitch (ex. every frame update your real model position is the current position + 1/10 of the "y" difference (maybe only if it is too big) or something like that, the time or percentage of the change for clamping the position will need to be manually tested to get a good feeling)
  • If you use two colliders, play with they layers and collision system to perfect the system (real model only collides with the environment or car) and the fake collider ignores environment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM