0
\$\begingroup\$

I am working on creating a procedural cylinder mesh with Unity C#. I have everything working but there is one thing I would like to implement in my existing code is to define a vector3 halfAxis which determines the height and direction of the cylinder. So if halfAxis is (0,1,0), the center of the cylinder coincides with the y-axis if the cylinder is at the origin in world space and length would be 2 since its a half axis.

Currently all my code does is generate the cylinder based on a height factor only in the y direction. There is capResolution which determines the smoothness of the cylinder and a radius to define cylinder radius

Below is my code. How would I modify it to add the halfAxis vector and determine its orientation

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;
        }
    }
\$\endgroup\$
  • \$\begingroup\$ why don't you attach it to a game object and rotate it accordingly to the correct direction? \$\endgroup\$ – Leggy7 Apr 3 '15 at 8:35
1
\$\begingroup\$

You could rotate every single point after you created them like this:

    var rotation = Quaternion.FromToRotation(Vector3.up, axis.normalized);
    var rotatedPoint = rotation * point;

But I still think that rotating the object node is a more elegant way.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.