使用方向创建程序网格

时间:2015-04-02 22:21:47

标签: c# graphics unity3d 3d procedural-generation

我正在使用Unity C#创建一个程序圆柱网格。我有一切正常工作,但我想在现有代码中实现的一件事是定义一个vector3 halfAxis,它决定了圆柱体的高度和方向。因此,如果halfAxis为(0,1,0),则圆柱的中心与y轴重合,如果圆柱位于世界空间的原点,则长度为2,因为它是半轴。

目前我的所有代码都是基于仅在y方向上的高度因子生成圆柱体。有capResolution决定圆柱的平滑度和半径来定义圆柱半径

以下是我的代码。如何修改它以添加halfAxis向量并确定其方向

public Vector3 halfAxis = Vector3.up;
public float radius = 3f;
public int capResolution = 3;
public int height = 2;
private const int MAX_CAP_RES = 3;
private const int MAX_RADIUS = 1;

void ComputeCylinder(out Vector3[] vertices, out Vector2[] uvs, out Vector3[] normals, out int[] faces)
    {

        if (capResolution < MAX_CAP_RES) capResolution = MAX_CAP_RES;
        if (radius < MAX_RADIUS) radius = MAX_RADIUS;

        //define total columns and rows
        int noOfColumns = capResolution + 1;
        int noOfRows = height + 1;

        //total number of vertices that make up the cylinder
        int noOfVertices = noOfColumns * noOfRows;

        //no of normals for each vertex
        int noOfNormals = noOfVertices;

        //uvs are always equal to no of vertices in a mesh
        int noOfUvs = noOfVertices;

        //side faces (tris) without the top and bottom caps
        int noOfSideFaces = capResolution * height * 2;

        //cap faces (2 caps bottom and top)
        int noOfCapFaces = capResolution - 2;

        //initialize all the arrays
        vertices = new Vector3[noOfVertices];
        normals = new Vector3[noOfNormals];
        uvs = new Vector2[noOfUvs];
        faces = new int[(noOfSideFaces + noOfCapFaces * 2) * 3];

        //angle step for each column for side tris
        float step = Mathf.PI * 2 / capResolution;

        /*
           first for loop computes all the side faces of the cylinder
           second loop computes tris for top and bottom caps
         */
        for (int i = 0; i < noOfRows; i++)
        {
            for (int j = 0; j < noOfColumns; j++)
            {
                float angle = j * step;

                //folding from the first and last vertex
                if (j == noOfColumns - 1) angle = 0;

                //compute vertices, uvs and normals for each row and column offsets
                vertices[i * noOfColumns + j] = new Vector3(radius * Mathf.Cos(angle),i * height,radius * Mathf.Sin(angle)); //build a cylinder with an upwards orientation
                uvs[i * noOfColumns + j] = new Vector2(j * 1 / radius, i * 1 / halfAxis.y);
                normals[i * noOfColumns + j] = new Vector3(0, 0, -1.0f);

                /*
                   To create faces, we ignore the first row and the last column
                   for every other vertex we create two triangle faces at the same time in one loop
                 */
                if (i != 0 && j < noOfColumns - 1)
                {
                    //offset the initial space for storing tris for bottom cap
                    int index = noOfCapFaces * 3 + (i - 1) * capResolution * 6 + j * 6;

                    //create the first face
                    faces[index + 0] = i * noOfColumns + j;
                    faces[index + 1] = i * noOfColumns + j + 1;
                    faces[index + 2] = (i - 1) * noOfColumns + j;

                    //create the second face
                    faces[index + 3] = (i - 1) * noOfColumns + j;
                    faces[index + 4] = i * noOfColumns + j + 1;
                    faces[index + 5] = (i - 1) * noOfColumns + j + 1;
                }
            }
        }

           /*drawing top and bottom caps
           we need the firstIndex, midIndex and lastIndex as vertices for cap tris and store it in the faces array*/

        int firstIndex = 0;
        int midIndex = 0;
        int lastIndex = 0;
        int topCapOffset = noOfVertices - noOfColumns;

        for (int i = 0; i < noOfCapFaces; i++)
        {
            //we get the bottom index to populate faces for bottom cap
            int bottomIndex = i * 3;

            //top cap tris will be stored in the empty end location of faces array
            int topIndex = (noOfCapFaces + noOfSideFaces) * 3 + i * 3;

            //get the three index for each vertex to make a cap tri
            if (i == 0)
            {
                firstIndex = 1;
                midIndex = 0;
                lastIndex = noOfColumns - 2;
            }
            else
            {
                midIndex = lastIndex;
                lastIndex = lastIndex - 1;
            }

            //populate triangle vertices for bottom cap
            faces[bottomIndex + 0] = lastIndex;
            faces[bottomIndex + 1] = midIndex;
            faces[bottomIndex + 2] = firstIndex;

            //populate triangle vertices for top cap
            faces[topIndex + 0] = topCapOffset + firstIndex;
            faces[topIndex + 1] = topCapOffset + midIndex;
            faces[topIndex + 2] = topCapOffset + lastIndex;
        }
    }

1 个答案:

答案 0 :(得分:1)

您是否真的需要旋转网格数据,还是可以旋转附加此网格的游戏对象?后者易于实现且更加用户友好,因为在变换检查器中查看旋转度更加清晰。

如果需要创建旋转网格,可以使用Quaternion.LookAt创建指向halfAxis的四元数。然后将四元数与每个顶点相乘。你也应该将旋转与法线相乘。

加成:

这就是我计算侧壁法线的方法:

var vertexLocal = new Vector3(radius * Mathf.Cos(angle), radius * Mathf.Sin(angle), i * height);
vertices[i * noOfColumns + j] = vertexLocal; //build a cylinder with an upwards orientation
uvs[i * noOfColumns + j] = new Vector2(j * 1 / radius, i * 1 / halfAxis.y);
vertexLocal.y = 0f;
normals[i * noOfColumns + j] = vertexLocal.normalized;