I have an issue when in try generating mesh around a spline.
Everything is good but at random point on the spline the mesh is "twisted". Some of triangle are shifted (cf picture)
https://i.ibb.co/WsFJjdm/Low-Poly-Spline-Bug.png
More detailed mesh
https://i.ibb.co/vBDD00V/Detailed-Spline-Bug.png
And the code who create the mesh. I do not start filling the array at index 0 because i generate the cap of the "tube" before (i can share the code if needed)
for (int step = 1; step <= _splineDetail; step )
{
Vector3 centerPoint = spline.GetPoint(1f / _splineDetail * step);
Vector3 centerDir = spline.GetDirection(1f / _splineDetail * step);
Vector3 perpendicularVect = Vector3.Cross(centerDir, centerPoint).normalized * Radius;
int startVerticesIndex = step * RadiusDetail 1;
int endVerticesIndex = startVerticesIndex RadiusDetail;
for (int i = startVerticesIndex; i < endVerticesIndex; i )
{
_vertices[i] = Quaternion.AngleAxis(angle * -i, centerDir) * perpendicularVect centerPoint;
_normals[i] = _vertices[i] - centerPoint;
}
int index = 1 RadiusDetail * (step - 1);
int startTrianglesIndex = (step - 1) * RadiusDetail * 6 RadiusDetail * 3;
int endTrianglesIndex = startTrianglesIndex RadiusDetail * 6;
for (int i = startTrianglesIndex; i < endTrianglesIndex; i = 6)
{
_triangles[i] = index RadiusDetail;
_triangles[i 1] = index 1 RadiusDetail;
_triangles[i 2] = index;
_triangles[i 3] = index 1 RadiusDetail;
_triangles[i 4] = index 1;
_triangles[i 5] = index;
index ;
}
_triangles[endTrianglesIndex - 5] = _triangles[startTrianglesIndex];
_triangles[endTrianglesIndex - 3] = _triangles[startTrianglesIndex];
_triangles[endTrianglesIndex - 2] = _triangles[startTrianglesIndex 2];
}
Thanks for reading, hope anybody can help me !
CodePudding user response:
The problem is that only knowing the current position and direction of the pipe isn't enough.
To illustrate, start with two identical pipes lined up going forward, with the top marked in red and the bottom marked in cyan with paint. Bend pipe 1 upwards, then to the right, then back down, then to the right. Bend pipe 2 downwards, then to the right, then back up, then to the right. Both pipes will end up at the same point and direction, but the red and blue sides at the end are in different positions:
(also applies to round pipes, of course)
If you don't account for this ambiguity and always treat the "top" as red, you would have to have points in the pipe where the red paint "twists" around your pipe. The same principle is what is happening to the edges & faces of your mesh.
To account for this, you can use the power of quaternions to calculate where the "first vertex" on the current ring corresponds to where the "first vertex" should belong on the previous ring.
The position of this "first vertex" we will call the "index direction". We can think of this direction as the direction of our "red paint". In reality it will be the first vertex for the ring at that location in the spline. So, the same thing your perpendicularVect
did!
So, you can begin the pipe by finding any valid index direction. For the purposes of getting rid of these twists, it doesn't matter how this is found. Cross product with a constant parameter works great, just be sure to handle colinearity.
Then, at each following step, find the minimal rotation which rotates the previous direction of the pipe to the new direction. Quaternion.FromToRotation
does exactly this. Then, apply that rotation to the index direction to find the new index direction.
Regardless of the step you are on, once you have your index direction, you can proceed as you were as if it was your perpendicularVect
. Rotate it around the pipe's axis to find the other points in the ring, and connect adjacent points to each other. Then, continue to the next step.
Altogether:
Vector3 previousCenterDir, indexDir;
for (int step = 1; step <= _splineDetail; step )
{
Vector3 centerPoint = spline.GetPoint(1f / _splineDetail * step);
Vector3 centerDir = spline.GetDirection(1f / _splineDetail * step);
if (step == 1)
{
indexDir = Vector3.Cross(centerDir, Vector3.forward);
if (indexDir == Vector3.zero)
{
// handle case where pipe direction is colinear with forward
indexDir = Vector3.Cross(centerDir, Vector3.right);
}
indexDir = indexDir * Radius;
}
else
{
indexDir = Quaternion.FromToRotation(previousCenterDir,
centerDir) * indexDir;
}
previousCenterDir = centerDir;
int startVerticesIndex = step * RadiusDetail 1;
int endVerticesIndex = startVerticesIndex RadiusDetail;
for (int i = startVerticesIndex; i < endVerticesIndex; i )
{
_vertices[i] = Quaternion.AngleAxis(angle * -i, centerDir) * indexDir
centerPoint;
_normals[i] = _vertices[i] - centerPoint;
}
int index = 1 RadiusDetail * (step - 1);
// ... rest of code from question ...
}