首页 > 解决方案 > Unity3d中的圆锥截头体

问题描述

我正在帮助我的朋友制作他的研究项目,为此我们需要一个 3d 平截头体,并且能够在运行时设置上圆形表面和底部圆形表面的直径,您能否建议如何完成?我正在考虑获取边缘/顶点数组,它们与顶部和底部的中心连接,并更改它们的坐标,也许有更简单的方法可以做到这一点?

标签: c#unity3druntimefrustum

解决方案


要创建具有动态大小的圆锥截头体,您可以使用http://wiki.unity3d.com/index.php/ProceduralPrimitives#C.23_-_Cone中的脚本

由于您稍后开始创建网格,因此您确切知道哪些顶点是顶部和底部平面的顶点,因此您可以在之后轻松地动态更改它们。

有点像例如

public class DynamicConicalFrustum : MonoBehaviour
{
    [SerializeField] private MeshFilter meshFilter;
    [SerializeField] private MeshCollider meshCollider;

    [Header("Settings")]
    [SerializeField] private float _height = 1f;
    [SerializeField] private float _bottomRadius = .25f;
    [SerializeField] private float _topRadius = .05f;
    [SerializeField] private int nbSides = 18;

    private Mesh mesh;
    const float _2pi = Mathf.PI * 2f;
    private Vector3[] vertices;

    private void Awake()
    {
        if (!meshFilter && !TryGetComponent<MeshFilter>(out meshFilter))
        {
            meshFilter = gameObject.AddComponent<MeshFilter>();
        }

        if(!GetComponent<MeshRenderer>())
        {
            var mr = gameObject.AddComponent<MeshRenderer>();
            mr.material = new Material(Shader.Find("Standard"));
        }

        if (!meshCollider)
            meshCollider = GetComponent<MeshCollider>();

        mesh = meshFilter.mesh;

        if (!mesh)
        {
            mesh = new Mesh();
        }

        meshFilter.mesh = mesh;
        if (meshCollider)
            meshCollider.sharedMesh = mesh;

        RecreateFrustum(_height,_bottomRadius,_topRadius);
    }

#if UNITY_EDITOR
    private void OnValidate()
    {
        if (Application.isPlaying)
        {
            Awake();
        }
    }
#endif

    public void RecreateFrustum(float height, float bottomRadius, float topRadius)
    {
        mesh.Clear();

        int nbVerticesCap = nbSides + 1;
        #region Vertices

        // bottom + top + sides
        vertices = new Vector3[nbVerticesCap + nbVerticesCap + nbSides  * 2 + 2];

        // Bottom cap
        vertices[0] = new Vector3(0f, 0f, 0f);
        for(var idx = 1; idx <= nbSides; idx++)
        {
            float rad = (float)(idx ) / nbSides * _2pi;
            vertices[idx ] = new Vector3(Mathf.Cos(rad) * bottomRadius, 0f, Mathf.Sin(rad) * bottomRadius);
        }

        // Top cap
        vertices[nbSides + 1] = new Vector3(0f, height, 0f);
        for(var idx = nbSides + 2; idx <= nbSides * 2 + 1; idx++)
        { 
            float rad = (float)(idx - nbSides - 1) / nbSides * _2pi;
            vertices[idx] = new Vector3(Mathf.Cos(rad) * topRadius, height, Mathf.Sin(rad) * topRadius);
        }

        // Sides
        int v = 0;
        for(var idx = nbSides * 2 + 2; idx <= vertices.Length - 4; idx+=2)
        { 
            float rad = (float)v / nbSides * _2pi;
            vertices[idx] = new Vector3(Mathf.Cos(rad) * topRadius, height, Mathf.Sin(rad) * topRadius);
            vertices[idx + 1] = new Vector3(Mathf.Cos(rad) * bottomRadius, 0, Mathf.Sin(rad) * bottomRadius);
            v++;
        }
        vertices[vertices.Length - 2] = vertices[nbSides * 2 + 2];
        vertices[vertices.Length - 1] = vertices[nbSides * 2 + 3];
        #endregion

        #region Triangles
        int nbTriangles = nbSides + nbSides + nbSides * 2;
        int[] triangles = new int[nbTriangles * 3 + 3];

        // Bottom cap
        int tri = 0;
        int i = 0;
        while (tri < nbSides - 1)
        {
            triangles[i] = 0;
            triangles[i + 1] = tri + 1;
            triangles[i + 2] = tri + 2;
            tri++;
            i += 3;
        }
        triangles[i] = 0;
        triangles[i + 1] = tri + 1;
        triangles[i + 2] = 1;
        tri++;
        i += 3;

        // Top cap
        //tri++;
        while (tri < nbSides * 2)
        {
            triangles[i] = tri + 2;
            triangles[i + 1] = tri + 1;
            triangles[i + 2] = nbVerticesCap;
            tri++;
            i += 3;
        }

        triangles[i] = nbVerticesCap + 1;
        triangles[i + 1] = tri + 1;
        triangles[i + 2] = nbVerticesCap;
        tri++;
        i += 3;
        tri++;

        // Sides
        while (tri <= nbTriangles)
        {
            triangles[i] = tri + 2;
            triangles[i + 1] = tri + 1;
            triangles[i + 2] = tri + 0;
            tri++;
            i += 3;

            triangles[i] = tri + 1;
            triangles[i + 1] = tri + 2;
            triangles[i + 2] = tri + 0;
            tri++;
            i += 3;
        }
        #endregion

        mesh.vertices = vertices;
        mesh.triangles = triangles;

        mesh.RecalculateBounds();
        mesh.RecalculateNormals();
        mesh.RecalculateTangents();
        mesh.Optimize();
    }
}

在此处输入图像描述

当然,目前还没有真正优化,但我希望你能从那里继续前进;)例如,该方法为侧面创建额外的顶点..人们可以重新使用顶部和底部的顶点,因为它们无论如何都匹配位置。此外,您当然也可以在高度和半径变化时更新相应的顶点,您不需要每次都重新创建整个网格,因为三角形保持不变,只有顶点改变位置。


推荐阅读