Planar Texture coordinates calculation algorithm

This topic is 1575 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hello.

I am trying to write correct algorithm for calculating planar texture coordinates, but It doesnt calculate coordinates correctly.

If I understand it well, I need to find normal for each triangle to find orientation of the face. Then, transform it so that if will lay along Z axis and then calculate coordinates without Y axis because Z will be like Y in transformed face.

public void CalculatePlanarTextureCoordinates(GeometryData geometryData)
{
List<Vector2> texCoordinates = new List<Vector2>();
OrientedBoundingBox boundingBox;
List<PositionData> positions = TransformPoints(geometryData, out boundingBox);
foreach (var positionData in positions)
{
GetPlanarCoordinates(boundingBox.Extents.X, positionData.Position.X,
geometryData.OrientedBoundingBox.Size.X),
GetPlanarCoordinates(boundingBox.Extents.Z, positionData.Position.Z,
geometryData.OrientedBoundingBox.Size.Z)));
}

geometryData.TextureCoordinates = texCoordinates;
}

private float GetPlanarCoordinates(float start, float end, float width)
{
return (end - start)/width;
}

private List<PositionData> TransformPoints(GeometryData geometryData, out OrientedBoundingBox boundingBox)
{
PositionData[] transformedPositionData = new PositionData[geometryData.Positions.Count];
Matrix transformationMatrix = Matrix.Identity;
for (int i = 0; i < geometryData.IndexBuffer.Count; i += 3)
{
Vector3 v0 = geometryData.Positions[geometryData.IndexBuffer[i + 1]].Position -
geometryData.Positions[geometryData.IndexBuffer[i]].Position;
Vector3 v1 = geometryData.Positions[geometryData.IndexBuffer[i + 2]].Position -
geometryData.Positions[geometryData.IndexBuffer[i]].Position;

Vector3 direction = Vector3.Cross(v0, v1);
direction = Vector3.Normalize(direction);
Vector3 vertex1 = geometryData.Positions[geometryData.IndexBuffer[i]].Position;
Vector3 vertex2 = geometryData.Positions[geometryData.IndexBuffer[i + 1]].Position;
Vector3 vertex3 = geometryData.Positions[geometryData.IndexBuffer[i + 2]].Position;

if (direction == Vector3.UnitY)
{
transformedPositionData[geometryData.IndexBuffer[i]].Position = vertex1;
transformedPositionData[geometryData.IndexBuffer[i + 1]].Position = vertex2;
transformedPositionData[geometryData.IndexBuffer[i + 2]].Position = vertex3;
}

Vector3 rotationAxis = Vector3.Cross(direction, Vector3.UnitY);
float rotationAngle = Vector3.Dot(direction, Vector3.UnitY);
Quaternion qRot;

if (rotationAxis.X != 0.0f || rotationAxis.Y != 0.0f || rotationAxis.Z != 0.0f)
{
qRot = new Quaternion(rotationAxis, rotationAngle);
}
else
{
qRot = new Quaternion(Vector3.UnitX, rotationAngle);
}

transformationMatrix = Matrix.Translation(-geometryData.OrientedBoundingBox.Center) *
Matrix.RotationQuaternion(qRot);

transformedPositionData[geometryData.IndexBuffer[i]].Position = Vector3.Transform(vertex1,
Quaternion.RotationMatrix(transformationMatrix));
transformedPositionData[geometryData.IndexBuffer[i + 1]].Position = Vector3.Transform(vertex2,
Quaternion.RotationMatrix(transformationMatrix));
transformedPositionData[geometryData.IndexBuffer[i + 2]].Position = Vector3.Transform(vertex3,
Quaternion.RotationMatrix(transformationMatrix));
}
BoundingBox basicBoundingBox =
BoundingBox.FromPoints(transformedPositionData.Select(x => x.Position).ToArray());
boundingBox = new OrientedBoundingBox(basicBoundingBox);
boundingBox.Transform(transformationMatrix);
return transformedPositionData.ToList();
}


But in result I receive completely wrong coordinates with wrong side and even more that range [0..1].

Could someone tell me what is wrong here? Maybe I translate vertices incorrectly or something else?

I would appreciate for any help.

Share on other sites

But in result I receive completely wrong coordinates

First, with regard to debugging code, after you examine your code visually for typos and logical errors, the next thing to do is to examine the actual values that the code produces. It appears you've begun to do that, and you need to continue that process. You should follow the data step-by-step in one of two ways:

1. Find a point in your code where the values are correct. Look at the values after the next few lines of code and determine if the results are correct. If they are correct, continue stepping through the code, until you find a line of code that does not produce the values you expect. That line (or section) of code needs to be fixed.

2. Find a point in your code where the values are incorrect. Start the process again with the same correct input data, and examine the values at some line of code that executes before the point where the values are incorrect. If those values are incorrect, repeat step 2. Otherwise, go to step 1.

With regard to the code you've posted, it appears you're trying to orient each triangle such that it "lays" in the X-Z plane and calculate tex coords based on that orientation. Rather than write the code for you, here are some comments that may help you correct your code.

- The following section of code has no effect. Following that if statement, you continue with the calculations anyway. In addition, because of the way floating point calculations are done, it's very unlikely that the cross-product calculation will produce floating point values exactly equal to (what I assume to be) { 0.0f, 1.0f, 0.0f }. It's not clear what purpose this section of code serves.

if (direction == Vector3.UnitY)
{
...
}


- This line of code does not produce an angle, it results in the cosine of the angle:

float rotationAngle = Vector3.Dot(direction, Vector3.UnitY);

- The following section of code is apparently intended to test whether the triangle normal is already pointing in the Y direction. I.e., the rotationAxis is the cross between the triangle normal and the Y-axis, and the magnitude will be zero if the normal is parallel to the Y-axis. As mentioned above, comparing floating point numbers in this way will rarely produce the expected results. If, by chance but very unlikely, the calculated rotationAxis is exactly { 0, 0, 0 }, that would indicate that the triangle is already oriented correctly, but the code then rotates the triangle about the X-axis by the cosine(1) = 1. The intent of that isn't clear.

if (rotationAxis.X != 0.0f || rotationAxis.Y != 0.0f || rotationAxis.Z != 0.0f)
{
qRot = new Quaternion(rotationAxis, rotationAngle);
}
else
{
qRot = new Quaternion(Vector3.UnitX, rotationAngle);
}

Hope that helps a bit.

EDIT: As an example of a debugging approach that may help, start with a triangle which has a normal = { 0, 1, 0 }. Step through your code and determine if you get the desired results. If it does not, determine why it doesn't result in the correct values. Then try a triangle with vertices such as (1,0,0); (0,1,0); (0,0,1). Step through your code and compare the results of just a few lines of code at a time to determine where incorrect values are produced.

Edited by Buckeye

Share on other sites

I rewrite my algorithm due to fix that errors, but I am not sure in which place it faults.

Here is the code:

Vector2[] texCoordinates = new Vector2[geometryData.Positions.Count];
PositionData[] transformedPositionData = new PositionData[geometryData.Positions.Count];
Matrix transformationMatrix = Matrix.Identity;
for (int i = 0; i < geometryData.IndexBuffer.Count; i += 3)
{
Vector3 v0 = geometryData.Positions[geometryData.IndexBuffer[i + 1]].Position -
geometryData.Positions[geometryData.IndexBuffer].Position;
Vector3 v1 = geometryData.Positions[geometryData.IndexBuffer[i + 2]].Position -
geometryData.Positions[geometryData.IndexBuffer].Position;

Vector3 direction = Vector3.Cross(v0, v1);
direction = Vector3.Normalize(direction);
Vector3 vertex1 = geometryData.Positions[geometryData.IndexBuffer].Position;
Vector3 vertex2 = geometryData.Positions[geometryData.IndexBuffer[i + 1]].Position;
Vector3 vertex3 = geometryData.Positions[geometryData.IndexBuffer[i + 2]].Position;

Vector3 rotationAxis = Vector3.Cross(direction, Vector3.UnitY);
float rotationAngle = Vector3.Dot(direction, Vector3.UnitY);
Quaternion qRot;
qRot = new Quaternion(rotationAxis, rotationAngle);

transformationMatrix = Matrix.RotationQuaternion(qRot);

vertex1 = Vector3.Transform(vertex1, Quaternion.RotationMatrix(transformationMatrix));
vertex2 = Vector3.Transform(vertex2, Quaternion.RotationMatrix(transformationMatrix));
vertex3 = Vector3.Transform(vertex3, Quaternion.RotationMatrix(transformationMatrix));

BoundingBox basicBoundingBox =
BoundingBox.FromPoints(new []{vertex1, vertex2, vertex3});
boundingBox = new OrientedBoundingBox(basicBoundingBox);
Vector2 coords1 = new Vector2(
GetPlanarCoordinates(boundingBox.Extents.X,
vertex1.X,
boundingBox.Size.X),
GetPlanarCoordinates(boundingBox.Extents.Z,
vertex1.Z,
boundingBox.Size.Z));

Vector2 coords2 = new Vector2(
GetPlanarCoordinates(boundingBox.Extents.X,
vertex2.X,
boundingBox.Size.X),
GetPlanarCoordinates(boundingBox.Extents.Z,
vertex2.Z,
boundingBox.Size.Z));

Vector2 coords3 = new Vector2(
GetPlanarCoordinates(boundingBox.Extents.X,
vertex3.X,
boundingBox.Size.X),
GetPlanarCoordinates(boundingBox.Extents.Z,
vertex3.Z,
boundingBox.Size.Z));
texCoordinates[geometryData.IndexBuffer] = coords1;
texCoordinates[geometryData.IndexBuffer] = coords2;
texCoordinates[geometryData.IndexBuffer] = coords3;
}

private float GetPlanarCoordinates(float start, float end, float width)
{
return (end - start)/width;
}

I found perpendicular to face. Then found cosinus of that angle and use it for quaternion (hope that is correct).

After that I transform vertices to align them to 0,1,0 and find boundbox for that triangle. Next I calculate text coords for each of 3 vertices, but as a result I still receive incorrect result even for simple cube and I cant understand where is my error. Does I rotate vertices correctly? Or does I calculate texture coordinates itself correctly?

Share on other sites

float rotationAngle = Vector3.Dot(direction, Vector3.UnitY);

Again (see my comment above) .. the dot product of two vectors does not result in an angle.

I cant understand where is my error. Does I rotate vertices correctly?

As suggested above, you should step through your code and examine actual variable values to determine if the code produces correct results. For instance, if you want to determine whether the vertices have been rotated correctly, examine the actual values of the vertices produced by your code, and compare them to the values that should be produced.

Just to be sure, do you know how to set breakpoints in your code, and examine the values of variables at runtime?

Share on other sites

Just to be sure, do you know how to set breakpoints in your code, and examine the values of variables at runtime?

Sure, but I need an algorithm. I dont know what to fix and whether any data will be correct if I dont know exactly what to do.

I dont even now if I do these calculations in a correct way (in general).

I know the idea is how to calculate texture coordinates, but I cannot correctly implement that unfortunately.

Share on other sites

Sure, but I need an algorithm. I dont know what to fix and whether any data will be correct if I dont know exactly what to do.

I dont even now if I do these calculations in a correct way (in general).

You have to decide what you want to do before you determine how to do it, as the particular algorithm for calculating tex coords for the vertices depends on what you want the result to be.

The approach you've taken is close to a result for applying a texture to each individual triangle appropriately, i.e., in a planar fashion. If that's not the desired result, you'll have to describe what you want to do, rather than asking whether how you do it is correct.

The algorithm for what appears to be your desired result is very close to what you've tried to implement.

1. Calc the triangle normal.

2. Translate the triangle to a "local" origin. Depending on what you want the results to be, this isn't always necessary.

3. Rotate the vertices to align them parallel to the X-Z plane by determining the required axis of rotation, and the angle by which to rotate them.

4. Calculate tex coords based on the x-z coords of the transformed vertices, assuming the entire texture is to be mapped to that one triangle.

In general, coding an algorithm is comprised of basic steps:

1. Understand the algorithm! If you don't understand how the algorithm is intended to work, you can't debug your code. You have to understand whether the results of any single line of code are correct or not.

2. Decide what a line or section of code is intended to do.

Determine if that line or section of code actually does what is intended:

3. Code it correctly.

4. Check whether it executes correctly.

You have written code to implement an algorithm. You've gotten some comments (one of which you don't understand or just ignored). As the code as a whole doesn't seem to be providing the desired results, I suggest (and describe how) you should examine and debug smaller sections of your code to determine where it's not doing what you want it to.

As mentioned above, for instance, if you want to know if vertices are rotated correctly:

1. Understand that the intent is for the transformed vertices to form a triangle parallel with the x-z plane, and what parallel means in that context.

2. Start with a triangle for which you know the results for a correct transformation. This isn't cheating. It's like looking up the answers in the back of the book!

3. Check the values of the transformed vertices.

Understanding what each line or section of code should do is necessary to do all that successfully.

EDIT: At the end of that whole process, rather than asking why several hundred lines of code are incorrect, you should be able to post information such as: "I expect this line of code [not several hundred lines] to do such-and-such. When the input numbers are this-and-that, I get these-numbers when I expect those-numbers."

Edited by Buckeye

Share on other sites

I didnt ignore your suggestions.

Here is my formula for finding angle. Hope it correct:

float rotationAngle = (float)Math.Atan2(rotationAxis.Length(), Vector3.Dot(direction, Vector3.UnitY));


I thought on one thing:

I have an index array and I use it for finding triangles. One vertex could be use multiple time, So actually I can write to array cell many times.

Does this could create false results for me?

I need translate all triangles to some certain position? Because now I just rotate them.

I think this is the cause of the problem - I incorrectly work with triangles, but I dont know for this momemt how to fix that.

Update:

No, sorry, this is not the reason of the problem. I must get numbers in range [0..1] but I get almost random numbers....[-17..0.5] for example.

Edited by BlackJoker

• What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 11
• 15
• 11
• 11
• 9
• Forum Statistics

• Total Topics
634151
• Total Posts
3015825
×