【问题标题】:Simplify collision mesh of road-like system?简化道路系统的碰撞网格?
【发布时间】:2020-05-04 15:08:59
【问题描述】:

鉴于 Unity 中基于图块的道路或人行道系统(如图所示),我得到了刚体在其接缝上移动的小凹凸(即使对于相同的垂直位置和比例,并且在为每个图块使用盒子碰撞器时)。有没有好的方法,例如将碰撞网格组合成一个超级简化的全平面网格?我没有运气,例如导出为对象(不使用我的网格简化器),因为在重新导入和摆脱单个盒子碰撞器时,明显的小凹凸仍然存在。我的要求不是它必须是实时的(尽管如果没有缺点的话,那将是一个优点)。谢谢!

【问题讨论】:

  • 您提到了您的“网格简化器”?它是如何工作的?我可以想象当同一位置的顶点没有合并时,可能会发生小凹凸。我认为如果您在生成简化网格时删除重复的顶点可能会有所帮助,如果我正确假设您的网格简化器是如何工作的..
  • 我已经尝试过 Lightwave 3D 以及 Blender 的各种 Poly-etc-reduce 功能。 (我也玩过 MeshLab,但它有许多不同的选项。)与此同时,我通过简单的重叠长四边形手动重新创建了碰撞网格,并且碰撞消失了。能够自动化这个过程(这将允许更容易添加或编辑图块)仍然很好......

标签: c# unity3d


【解决方案1】:

您可以尝试Mesh.CombineMeshes 将所有小对撞机组合成一个大对撞机。

[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;
    }
}

需要注意的一点:生成的组合网格位于世界空间坐标中,因此如果附加到的游戏对象有任何变换更改,它们也将被应用。

如果您启用了 MeshCollider -> Cooking Options -> Weld Colocated Vertices,这可能就足够了,它应该组合具有相同位置的顶点。

如果没有,您可以自己尝试weld 顶点,看看是否能解决问题。

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;                
}


这是一个示例(之前和之后):6 个以上有明显间隙的碰撞器,1 个以下没有间隙的碰撞器。

【讨论】:

  • 谢谢!我现在已经授予你赏金,并且一旦我有机会实施它并检查它是否适用于我的刚体颠簸,也会标记为答案。
【解决方案2】:

也许,你不需要改变电路,而是改变汽车碰撞系统:

  • 使用真正的碰撞器和输入反馈制作“隐形假车”,然后制作真正的汽车(可能只有模型,或者使用额外的碰撞器进行其他类型的碰撞检测(¿ 加电?)但是我认为在虚拟汽车中安装一个对撞机就足够了)
  • 使模型遵循虚拟位置,但插入垂直故障(例如,每帧更新您的真实模型位置是当前位置 + 1/10 的“y”差异(可能仅当它太大时)或其他东西像这样,夹紧位置的变化时间或百分比需要手动测试以获得良好的感觉)
  • 如果您使用两个碰撞器,请使用它们的层和碰撞系统来完善系统(真实模型仅与环境或汽车碰撞),而假碰撞器会忽略环境。

【讨论】:

    【解决方案3】:

    您正在寻找称为Composite Collider 的东西。 2D Tilemaps 甚至有一个“由合成使用”复选框。如果您将 Composite Collider 2D 组件附加到您的 tilemap 对象并勾选“由复合材料使用”,它会将所有对撞机组合成一个大型对撞机。

    话虽如此,看起来您是在使用预制件将道路生成到网格上,而不是使用 tilemap 构建地图。您仍然可以通过在碰撞器上勾选“由复合材料使用”来为一堆不同的游戏对象使用复合碰撞器,但它比简单地在一个组件上勾选一个按钮更复杂,因为您必须配置所有游戏对象.如果您可以简化为在道路上使用瓦片地图,那应该会简单得多。

    【讨论】:

    • 谢谢。我应该提到,但我的应用程序是一个完全 3d 的世界,而不是 2d。一个人甚至可以上下,驾驶直升机等等。不过,为了这些道路,我们可以假设它们都在同一个垂直位置。
    • 不幸的是,运行时不存在用于 3D 对象的复合碰撞器选项。您可以考虑构建自定义网格,但我在 3D 开发方面经验不足,无法帮助您,抱歉@PhilippLenssen
    猜你喜欢
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    • 2014-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多