Direct3D Texture Coordinates

Started by
8 comments, last by johnp 23 years, 12 months ago
Okay, I give up. For the last week I have been killing myself trying to find out how to calculate vertex texture coordinates in Direct3D immediate mode. I have found plenty of tutorials on doing the actual mapping, but i''m not drawing the polygons, Direct3D is doing that. I just want a u/v coordinate from an x/y/z. Surely it can''t be that tricky? Please help with this one as I''m close to giving up with this 3D stuff. Regards. John.
Advertisement
It can be tricky

I have this Problem too, and i only get some Planar Mapping working (Projecting the 3D Coordinates onto 2D ones), and
simple spherical Mapping.
I am still working on an algorithm that equally distributes an Rectangle Texture on to an Complex 3D Mesh without to much streching.

But for the simple Planarmapping, just assign the x Values to u and the z Value to v and scale them, so that they go from 0 to 1.

Lars
--------> http://www.larswolter.de <---------
Will assigning x to u and z to v work for triangles. Also will it work for triangles at any angle, even with a 0 z value?

Thanks for your response.
For me, I let the texture coordinates go beyond 1 and 0. All I did was check which direction the plane normal is facing. (if nx > ny and nx > nz etc.) After that I got the position of the vertex and divided it by a constant 256. This is what the code looks like (in visual basic)

With TriangleList(I).TriangleVerts(II)
NormalVec.X = Abs(.nx)
NormalVec.Y = Abs(.ny)
NormalVec.Z = Abs(.nz)
If NormalVec.X >= NormalVec.Y And NormalVec.X >= NormalVec.Z Then
.tu = .Z / TexSizeU
.tv = .Y / TexSizeV
End If
If NormalVec.Y >= NormalVec.X And NormalVec.Y >= NormalVec.Z Then
.tu = .X / TexSizeU
.tv = .Z / TexSizeV
End If
If NormalVec.Z >= NormalVec.Y And NormalVec.Z >= NormalVec.X Then
.tu = .X / TexSizeU
.tv = .Y / TexSizeV
End If
End With
There are 2 sides to the texture co-ordinate problem, one incredibly easy, and one much more difficult, and I am unsure which side you are on. On the difficult side, there are numerous complex ways of mapping a skin onto a mesh, which I''m not going to go into because I am no expert in that field. But if you''re just starting out, to get a triangle to map part of your texture is very simple. There is no set formula for mapping x,y,z to u,v as that would defeat the object. These variables are for you to do what you want with. But to get started, you can just pick some arbitrary scheme. Imagine you have a right angled triangle, vertical line on the left, horizontal line on the bottom, diagonal line (hypotenuse) from top-left to bottom right. To map the bottom left half of a square texture onto that triangle, you would assign (0,0) to the top left vertex, (0, 1) to the bottom left vertex, and (1,1) to the bottom right vertex. If it helps, think of the U and V values as percentages of the source texture. A vertex with U=0.5 and V=0.5 will be drawing whatever is right in the middle of your texture.

I may not be understanding (and therefore answering) your question, in which case, I apologize and wish you the best of luck
It works with z-Values of 0, but it doesn''t look that good, so if you want it simple check if your objects largest side is lying in the x,y Plane or is it in the x,z plane or the y,z plane, and use the appropriate Values for u,v. You could even decide that per Vertex instead of per Object (like nes8bit) by checking the normals of the Triangle.
So you achieve somekind of Boxed Mapping.

Lars
--------> http://www.larswolter.de <---------
Thanks for the input on this everyone. I have tried the nes8bit solution but and tried tecturing a triangle at all different angles but it does not seem to work if the triangle is on the z axis (all x values the same). Any ideas? Lars W, your ideas sonds interesting. Are you saying I can calculate texture coordinates per vertex based on just the vertex normal? Can you explain a bit further please.

Regards.

John
I got some code working based on the suggestions given and it seems to work triangles on any axis. Here it is. This may not be the best way but it works.

//----------------------------------------------------------
void CalculateTextureCoords()
{
//fdata is an array of vertex indices.
//vlist is an array of vertexes
for (unsigned int n = 0; n < fdata.size(); n += 3)
{

//Reference the 3 vertexes that make up the
//triangle
D3DVERTEX& ve1 = vlist[fdata[n]];
D3DVERTEX& ve2 = vlist[fdata[n+1]];
D3DVERTEX& ve3 = vlist[fdata[n+2]];

//create 3 vectors from the vertex structure
D3DVECTOR v1 = D3DVECTOR(ve1.x, ve1.y, ve1.z);
D3DVECTOR v2 = D3DVECTOR(ve2.x, ve2.y, ve2.z);
D3DVECTOR v3 = D3DVECTOR(ve3.x, ve3.y, ve3.z);

//calculate the face normal
D3DVECTOR norm = Normalize( CrossProduct( v3-v2, v3-v1));
norm.x = fabs(norm.x);
norm.y = fabs(norm.y);
norm.z = fabs(norm.z);

//Determine axis and setup x/y variables for min/max tests
float x1, y1, x2, y2, x3, y3;

if (norm.x >= norm.y && norm.x >= norm.z)
{
x1 = v1.z;
y1 = v1.y;
x2 = v2.z;
y2 = v2.y;
x3 = v3.z;
y3 = v3.y;
}
else if (norm.y >= norm.z && norm.y >= norm.z)
{
x1 = v1.x;
y1 = v1.z;
x2 = v2.x;
y2 = v2.z;
x3 = v3.x;
y3 = v3.z;
} else if (norm.z >= norm.y && norm.z >= norm.x)
{
x1 = v1.x;
y1 = v1.y;
x2 = v2.x;
y2 = v2.y;
x3 = v3.x;
y3 = v3.y;
}

TFloatRect r = BoundingRect(x1, y1, x2, y2, x3, y3);

float width = r.right - r.left;
float height = r.top - r.bottom;


//Set the u/v coordinates. This will stretch the entire texture
//over the triangle.
ve1.tu = (x1 - r.left) / width;
ve1.tv = (r.top - y1) / height;

ve2.tu = (x2 - r.left) / width;
ve2.tv = (r.top - y2) / height;

ve3.tu = (x3 - r.left) / width;
ve3.tv = (r.top - y3) / height;

}
}
//----------------------------------------------------------
TFloatRect BoundingRect(float x1, float y1, float x2, float y2, float x3, float y3)
{
//Initialise bounding box to maximum size and do min max
//tests on the 3 xy pairs
TFloatRect r(FLT_MAX, -FLT_MAX, -FLT_MAX, FLT_MAX);

r.left = std::min(x1, r.left);
r.right = std::max(x1, r.right);
r.left = std::min(x2, r.left);
r.right = std::max(x2, r.right);
r.left = std::min(x3, r.left);
r.right = std::max(x3, r.right);

r.bottom = std::min(y1, r.bottom);
r.top = std::max(y1, r.top);
r.bottom = std::min(y2, r.bottom);
r.top = std::max(y2, r.top);
r.bottom = std::min(y3, r.bottom);
r.top = std::max(y3, r.top);

return r;
}


It looks like you have solved your Problem, or are there still some Problems ?

Lars
--------> http://www.larswolter.de <---------
Thanks Lars. For now this solution seems to work. Thanks again the help I got from yourself and others on this. Posting the code will hopefully help others.

Regards.

John

This topic is closed to new replies.

Advertisement