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!