Implement Perspective Correct Texture Mapping

Started by
11 comments, last by john13to 11 years, 8 months ago
I didn't look at your code, but the pic looks like you might be using the same texture coordinates for the right and the bottom edge... maybe you mix them up somewhere.
Advertisement

I didn't look at your code, but the pic looks like you might be using the same texture coordinates for the right and the bottom edge... maybe you mix them up somewhere.


I check it out but even though I changed the values on the texture coordinates it produced the same result.
On the other hand I did a different implementation where it calculated u and v directly with the
perspective texture formula, seen in http://en.wikipedia.org/wiki/Texture_mapping#Perspective_correctness,
instead of interpolating 1/z, u/z and v/z along the edges and then obtain u and v from them.
I embedded it in the active edge list algorithm and it did render perspective corrected textures but that
was only on some of the triangles while the other triangles became completely white instead.

I noticed that while the textured triangles did have different values on u and v, the blank triangles did have
the same constant value on u and v and were at the maximum size number of the width and height of texture
all the time at in this case 2048. No matter how I change the perspective formula it always returned the same
maximum size number value. Here is how I implemented it in short and simple version using the active edge list
algorithm:
[source lang="cpp"]
vAlpha = 0.0f;
vAlphaGrad = 1.0f/(scanlineEnd - scanlineStart);
vStart = 0.0f; vEnd = 0.0f;

float Zinv0 = 0.0f;
float Zinv1 = 0.0f;

if (z0 == 0.0f && z1 != 0.0f)
{
Zinv0 = 2147483647.0f;
Zinv1 = 1.0/z1;
}
else if (z0 != 0.0f && z1 == 0.0f)
{
Zinv0 = 1.0f/z0;
Zinv1 = 2147483647.0f;
}
else if (z0 == 0.0f && z1 == 0.0f)
{
Zinv0 = 2147483647.0f;
Zinv1 = 2147483647.0f;
}
else
{
Zinv0 = 1.0/z0;
Zinv1 = 1.0/z1;
}


for each scanline:
{
//Perspective formula for v
float v = (((1.0f - valpha)*(vStart*Zinv0)) + (valpha*(vEnd*Zinv1))) /
(((1.0f - valpha)*(Zinv0)) + (valpha*(Zinv1)));

for each x along scanline
{
float ualpha = 0.0f;
float ualphaGrad = 1.0f/(xEnd - xStart);

//Perspective formula for u
float u = ((1.0f - ualpha)*(0.0f*Zinv0) + ualpha*(2048.0f*Zinv1)) /
((1.0f - ualpha)*(1.0f*Zinv0) + ualpha*(1.0f*Zinv1));

texValueR = (float)checkImage[(int)(u/16.0f)]
[(int)(v/16.0f)][0];
texValueG = (float)checkImage[(int)(u/16.0f)]
[(int)(v)][1];
texValueB = (float)checkImage[(int)(u/16.0f)]
[(int)(v)][2];


glColor3f(texValueR, texValueG, texValueB);
glVertex2f((currX), (scanline));

currX += 1.0f;
uAlpha += uAlphaGrad;
}
vAlpha += vAlphaGrad;
}


[/source]
Also, when I also rotate the object around the x-axis the texture disappear on some of the triangles and
appear on other triangles. It acts very strange and it is very hard to point what is causing all of these
problems.
I managed to fix it at last and thing was that I used Affine Mapping instead to give the texture a depth to it when it is projected on the icosahedron where I used the Perspective Correctness Mapping before.
The difference is that with Affine Mapping it does not have any 1/z that Perspective Correctness Mapping has. Here is a comparison of the two formulas:

Affine Mapping:

u = (1 - ualpha)*u0 + ualpha*u1
v = (1 - valpha)*v0 + valpha*v1

Perspective Correctness Mapping:

u = ( (1 - ualpha)*(u0/z0) + ualpha*(u1/z1) ) / ( (1 - ualpha)*(1 / z0) + ualpha*(1/z1) )
v = ( (1 - valpha)*(v0/z0) + valpha*(v1/z1) ) / ( (1 - valpha)*(1 / z0) + valpha*(1/z1) )

When I implemented Affine Mapping I just removed the 1/z0 and the 1/z1 terms from the Perspective formula completely so that I received the result from the attached image below. But then I came to realize that instead of interpolating ualpha and valpha I could interpolate u and v directly where the interpolating factor would be:

dudx = (u1 - u0) / (xEnd - xStart)
dvdy = (v1 - v0) / (scanlineEnd - scanlineStart)

For every pixel along the scanline u would be incremented with:
u = u + dudx

And for every scanline v would be incremented with:
v = v + dvdy

It was ironic that how simple it was to implement this feature in reality. I got fooled really well by this simplicity and never came across in my mind until now. Not only that but I had used the exact same kind of method when I implemented Gouraud Shading several months before when I was going to apply a shader to 2D flat polygons. So much time and energy had I spent to implement this simple thing =S

I also get the idea to implement Perspective Correctness Mapping as well even though I have not implement it (not have time! =P) but on the other hand this only seems to come in handy if I am going to apply a texture on a square that is built up by two triangles attached to each other for instance.

According to Wikipedia, if the square is to be textured with Affine it will cause discontinuity between the triangles where Perspectve eliminates that problem (http://en.wikipedia....ive_correctness). But Perspective does require more calculations since it involves 1/z divisions and that is a time consuming operation.

I got what I wanted at last I and I am very satisfied at last of the attached figure where I also have applied checkerboard textures of different colors! =)

This topic is closed to new replies.

Advertisement