Oh that sounds incredible! I will try to get this in my project as soon as I get back to editing tonight or tomorrow! Thank you!
When going through the 9 vert model, I was able to manually follow the triangle generation. I’m not sure what you mean about “stride”, but I assume it has to do with how it goes back and forth when trying to generate?
INCOMING WALL OF CODE
Disclaimer: I’m writing this quick and dirty until it works, then I plan on going back and making it actually efficient. I know I normally black out when I see posts like this, so I understand if I don’t get a response
As for the actual code, I’ll post a bunch here so future viewers can see the process I went through. So, I’m making a custom tire generator, starting with inputting the actual size of the tire (e.g. 235/35/19) as well as requesting a circumference resolution and a width resolution. This generates vertices basically from the center out, then re-arranges them from left to right. Also with this, I decided to use an AnimationCurve
(probably something better out there) to practically draw the profile of the tire. The last line here is setting the value for the 0 time in the curve so it creates the appropriate rim size - This is called in the update and this is all done with ExecuteInEditMode
on:
private void HandleTireSize()
{
widthInM = width * .001f;
wheelDiameterInM = wheelDiameter * 0.0254f;
sidewallHeightInM = widthInM * (sidewallHeight * .01f);
overallHeight = (wheelDiameterInM + (sidewallHeightInM * 2));
tireEdgeProfile.AddKey(0, wheelDiameterInM / overallHeight);
}
Now, the first thing I wanted to do was draw gizmo lines to view my circles:
private void OnDrawGizmos()
{
Matrix4x4 rotationMatrix = Matrix4x4.TRS(root.position, root.localRotation, root.lossyScale);
Gizmos.matrix = rotationMatrix;
Gizmos.color = Color.cyan;
int newWidthResolution = (widthResolution * 2) + 1;
float step = widthInM / (newWidthResolution - 1);
vertices = new Vector3[newWidthResolution * circumferenceResolution];
for (int i = 0; i < newWidthResolution; i++)
{
int inverseI = i - widthResolution;
float stepPercent = (step * inverseI);
float falloffPercent = (float) (widthResolution - (Mathf.Abs(inverseI))) / widthResolution;
float falloffRadius = tireEdgeProfile.Evaluate(falloffPercent) * overallHeight / 2;
Vector3 stepLocation = new Vector3((transform.localPosition.x + stepPercent), transform.localPosition.y, transform.localPosition.z);
Vector3[] points = GizmosExtensions.DrawWireCircleReturnPoints(falloffRadius, circumferenceResolution, stepLocation, transform.right);
for (int p = 0; p < points.Length; p++)
{
int index = (i * circumferenceResolution) + p;
vertices[index] = points[p];
}
}
GenerateMesh();
}
At the end of this, I added the vertices generated from my GizmosExtension.DrawWireCircleReturnPoints
to a new array. That function also actually draws Gizmo lines from i -> i+1
so I can see what the tire actually looks like as a cylinder, though there aren’t any lines connecting the circles yet.
At the very end, I have the GenerateMesh()
function which simply orders the vertices and then makes an array of indexes pointing to those vertices. I then generate a new mesh, clear it and give the mesh these verts and tris
private void GenerateMesh()
{
Vector3[] newVerts = Triangulator.OrderVertices(vertices);
triangles = Triangulator.GetTriangles(newVerts, circumferenceResolution, winding);
Mesh mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.Clear();
mesh.vertices = newVerts;
mesh.triangles = triangles;
mesh.RecalculateNormals();
mesh.name = "CleanerWheelMesh";
}
So, going back a bit, I have a class named Triangulator that does two things, one is to order the vertices, the second is to make the triangles.
This is probably where it goes wrong?
public static Vector3[] OrderVertices(Vector3[] vertices)
{
Vector3 centroid = new Vector3();
for (int i = 0; i < vertices.Length; i++)
{
centroid += vertices[i];
}
centroid /= vertices.Length;
// Sort the vertices by angle from the centroid
vertices = vertices.OrderBy(v => Mathf.Atan2(v.y - centroid.y, v.x - centroid.x)).ToArray();
return vertices;
}
Just in case, here’s the InsideTriangle
function
private static bool InsideTriangle(Vector3 A, Vector3 B, Vector3 C, Vector3 P)
{
float ax, ay, az, bx, by, bz, cx, cy, cz, apx, apy, apz, bpx, bpy, bpz, cpx, cpy, cpz;
float cCROSSap, bCROSScp, aCROSSbp;
ax = C.x - B.x; ay = C.y - B.y; az = C.z - B.z;
bx = A.x - C.x; by = A.y - C.y; bz = A.z - C.z;
cx = B.x - A.x; cy = B.y - A.y; cz = B.z - A.z;
apx = P.x - A.x; apy = P.y - A.y; apz = P.z - A.z;
bpx = P.x - B.x; bpy = P.y - B.y; bpz = P.z - B.z;
cpx = P.x - C.x; cpy = P.y - C.y; cpz = P.z - C.z;
aCROSSbp = ax * bpy - ay * bpx;
cCROSSap = cx * apy - cy * apx;
bCROSScp = bx * cpy - by * cpx;
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
}
And here is the GetTriangles
function:
public static int[] GetTriangles(Vector3[] Vertices, int resolution, string direction = "left")
{
int nbLevel = Vertices.Length / resolution;
int e = resolution;
List<int> triangles = new List<int>();
for (int i = 0; i < (nbLevel - 1); i++)
{
for (int j = 0; j < (e - 1); j++)
{
// This makes a 4-sided polygon
// triangle 1 :
triangles.Add(i * e + j);
if (direction != "right") triangles.Add(i * e + j + e);
triangles.Add(i * e + j + 1);
if (direction == "right") triangles.Add(i * e + j + e);
// triangle 2:
triangles.Add(i * e + j + 1);
if (direction != "right") triangles.Add(i * e + j + e);
triangles.Add(i * e + j + (e + 1));
if (direction == "right") triangles.Add(i * e + j + e);
}
//create the last 2 triangles
// triangle 1 :
triangles.Add(i * e + (e - 1));
if (direction != "right") triangles.Add(i * e + ((e * 2) -1));
triangles.Add(i * e + 0);
if (direction == "right") triangles.Add(i * e + ((e * 2) -1));
// triangle 2:
triangles.Add(i * e + 0);
if (direction != "right") triangles.Add(i * e + ((e * 2) -1));
triangles.Add(i * e + e);
if (direction == "right") triangles.Add(i * e + ((e * 2) -1));
}
return triangles.ToArray();
}
Anyways, congratulations if you made it this far. I was able to implement the code that shows vert numbers, but haven’t gotten a chance to actually look yet. After that I plan on checking the create cylinder mesh code above as well.