Creating procedural mesh with orientation

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. All of this works perfect. Now I just want to implement the logic behind orienting the vertices based on the halfAxis vector. I am stuck here.

Below is my code. How would I modify it to orient all the vertices based on halfAxis vector? Any direction or help would be much appreciated!

Thanks!

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

----------------- Update One ---------------

As per the link provided by Cherno, I tried the following. At the end of drawing all the faces, I tried to rotate the mesh as follows

Vector3 center = new Vector3(0, 2, 0);
Quaternion rotation = Quaternion.LookRotation(halfAxis);
for (int i = 0; i < vertices.Length; i++)
{
vertices = rotation * (vertices - center) + center;
}
But this doesn’t work. I am not sure if this is the right way to do it especially the quaternion angle part confuses me.
In my initial code, the line below create the cylinder with upwards orientation in Y
vertices[i * noOfColumns + j] = new Vector3(radius * Mathf.Cos(angle),i * height,radius * Mathf.Sin(angle));
If I change that to below, it would create the mesh with orientation in X axis and so on…
vertices[i * noOfColumns + j] = new Vector3(i * length,radius * Mathf.Cos(angle),radius * Mathf.Sin(angle));
But how do I orient it with the halfAxis vector. Any ideas or direction? Thanks!

I don’t know if it’ll help you, but you can rotate any number of vertices around a set point with the method detailed in this thread:

1

Not sure I understand what you want to achieve, but I’m taking a guess:
you want a vector3 that scales on the “y” axis and rotates it in 3D?

If so, the first thing you are doing wrong is trying to fit 1 float of scale and 3 of orientation (actually 4… more on this later) into a vector3.

Now, you can use the in-editor scale an rotate tools, but if you want it to be part of the mesh, the best way is with a matrix: a square table of numbers which basically contains how much of each of the original coordinates go into each of the new ones.

unity has this function:

 Matrix4x4.TRS(Vector3 pos, Quaternion q, Vector3 s); 

Use it to generate your matrix, and multiply the Vector3 coordinates of the vertices by it.

//get the matrix, do this once before generating the vertexes.
Quaternion rotation;
Vector3 scale;
Matrix4x4 matrix = Matrix4x4.TRS(Vector3.zero, rotation, scale);

//for every vertex
vertices[i * noOfColumns + j] = matrix.MultiplyVector(new Vector3(radius * Mathf.Cos(angle),i * height,radius * Mathf.Sin(angle)));

Now, about quaternions: They consist of 4 angles to rotate by: first around the “x” axis, then “y”, then “z”, and the last one I believe is around the “x” axis again, only it’s rotating whats left after the first three rotations. Why? Some rotations (x=90º,y=90º) can lead to the third rotation having the same axis as the first…