0
101 Feb 01, 2013 at 12:58

Hi folks!

Now I am learning perspective correct texture mapping. I had wrote a bit of code. My code do not works correctly. I understand common sense of perspective correct text.map. x/z and y/z -> u/z and v/z. But x and y in 3D space but u and v in 2D space- what is means? How works perspective correct texture mapping inside? I read many articles in Internet by this issue- but I had caught only common comprehend. My code I posted below. What is wrong in my code?

void CMy3DApp::Draw_Textured_Triangle(My3DTriangle tri,
UCHAR *dest_buffer,   // pointer to video buffer
int mem_pitch)       // bytes per line, 320, 640 etc.
{
double du,dv,dudyl,dvdyl,dudyr,dvdyr,ui,vi,ul,vl,ur,vr;
int dx,dy,dyl,dyr,        // general deltas
xi,yi,                // the current interpolated x,y
xstart,
xend,
ystart,
yrestart,
yend,
xl,
dxdyl,
xr,
dxdyr;
int x0,y0,  // cached vertices
x1,y1,
x2,y2;
double tu0,tv0, // cached vertices
tu1,tv1,
tu2,tv2;
int texture_shift2 = logbase2ofx[64];
irestart = INTERP_LHS;
// degenerate triangle
if ( ((tri.v1.x==tri.v2.x) && (tri.v2.x==tri.v3.x)) ||
((tri.v1.y==tri.v2.y) && (tri.v2.y==tri.v3.y)))
return;
My3DTexturedVert temp_1;
int temp;

// sort vertices
if (tri.v2.y < tri.v1.y)
{SWAP(tri.v1,tri.v2,temp_1);}
if (tri.v3.y < tri.v1.y)
{SWAP(tri.v1,tri.v3,temp_1);}
if (tri.v3.y < tri.v2.y)
{SWAP(tri.v2,tri.v3,temp_1);}

z0 = (double)1.0/ tri.v1.z;
z1 = (double)1.0/ tri.v2.z;
z2 = (double)1.0/ tri.v3.z;
x0  = (int)(tri.v1.x+0.5);
y0  = (int)(tri.v1.y+0.5);

x1  = (int)(tri.v2.x+0.5);
y1  = (int)(tri.v2.y+0.5);
x2  = (int)(tri.v3.x+0.5);
y2  = (int)(tri.v3.y+0.5);

tu0 = (double)(tri.v1.tu/ tri.v1.z);
tv0 = (double)(tri.v1.tv/ tri.v1.z);
tu1 = (double)(tri.v2.tu/ tri.v2.z);
tv1 = (double)(tri.v2.tv/ tri.v2.z);

tu2 = (double)(tri.v3.tu/ tri.v3.z);
tv2 = (double)(tri.v3.tv/ tri.v3.z);
// compute all deltas
// LHS
dyl = (y1 - y0);
dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
dudyl = (tu1 - tu0)/dyl;
dvdyl = (tv1 - tv0)/dyl;
dzdyl = z1 - z0;
// RHS
dyr = (y2 - y0);
dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dyr;
dudyr = (tu2 - tu0) /dyr;
dvdyr = (tv2 - tv0) /dyr;
dzdyr = z2 - z0;
xl = (x0 << FIXP16_SHIFT);
xr = (x0 << FIXP16_SHIFT);
ul = tu0;
vl = tv0;
ur = tu0;
vr = tv0;
zl = z0;
zr = z0;
ystart = y0;
// test if we need swap to keep rendering left to right
if (dxdyr < dxdyl)
{
SWAP(dxdyl,dxdyr,temp);
SWAP(dudyl,dudyr,temp);
SWAP(dvdyl,dvdyr,temp);
SWAP(xl,xr,temp);
SWAP(ul,ur,temp);
SWAP(vl,vr,temp);
SWAP(x1,x2,temp);
SWAP(y1,y2,temp);
SWAP(tu1,tu2,temp);
SWAP(tv1,tv2,temp);
// set interpolation restart
irestart = INTERP_RHS;
}
screen_ptr = dest_buffer + (ystart * mem_pitch);

for (yi = ystart; yi<=yend; yi++)
{
// compute span endpoints
xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
// compute starting points for u,v interpolants
ui = ul;
vi = vl;
zi = zl;
// compute u,v interpolants
if ((dx = (xend - xstart))>0)
{
du = (ur - ul)/dx;
dv = (vr - vl)/dx;
dz = (zr - zl)/dx;
} // end if
else
{
du = (ur - ul);
dv = (vr - vl);
dz = (zr - zl);
}
int indx = xstart*4;
for (xi=xstart; xi<=xend; xi++)
{
double z = 1.0 / (1.0/zi);
int u = (ui / z) * z;
int v = (vi / z) * z;
int t = (u ) + ((v) << texture_shift2);
t= t*3;
screen_ptr[indx] = pRes[t];
indx++;
screen_ptr[indx] = pRes[t+1];
indx++;
screen_ptr[indx] = pRes[t+2];
indx++;
screen_ptr[indx] = 0;
indx++;
ui+=du;
vi+=dv;
zi+=dz;
} // end for xi
// interpolate u,v,x along right and left edge
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
zl+=dzdyl;
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
zr+=dzdyr;
screen_ptr+=mem_pitch;
if (yi==yrestart)
{
if (irestart == INTERP_LHS)
{

// LHS
dyl = (y2 - y1);
dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
dudyl = (tu2 - tu1)/dyl;
dvdyl = (tv2 - tv1)/dyl;
dzdyl = z2 - z1;
// set starting values
xl = (x1  << FIXP16_SHIFT);
ul = tu1;
vl = tv1;
zl = z1;
// interpolate down on LHS to even up
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
zl+=dzdyl;
}
else
{
// RHS

dyr = (y1 - y2);
dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
dudyr = (tu1 - tu2)/dyr;
dvdyr = (tv1 - tv2)/dyr;
dzdyr = z1 - z2;
// set starting values
xr = (x2  << FIXP16_SHIFT);
ur = tu2;
vr = tv2;
zr = z2;
// interpolate down on RHS to even up
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
zr+=dzdyr;

}
} //end for y


#### 3 Replies

0
102 Feb 02, 2013 at 02:42

With Haswell around the corner, now is a great time to learn software rendering! B)

Here’s an excellent paper on perspective correct interpolation: Triangle Scan Conversion using 2D Homogeneous Coordinates (section 4 in particular). It might also be useful to read my article on Advanced Rasterization.

0
117 Feb 02, 2013 at 17:11

I second the Nick’s awesome article on Advanced Rasterization. If you wish to see some *real* (=code where it works & could be used for some game, after like tons of optimizations) implementation of software renderer - look here - http://www.otte.cz/G…_Sample1.tar.gz - It’s more likely proof-of-concept of how could useful software renderer work. For more real (=useful) implementation one would need to utilize multiple cores and hopefully SIMD intrinsics. On the other hand the code in current state is understandable, with intrinsics everywhere it would be a lot harder.

I also had an WIP article somewhere, which I wanted to publish here (talked with Reedbeta about it some time ago, though it still needs quite a bit of work on it), the problem was (and still is) that my work came in and I’m still too busy to work on the article.

0
101 Feb 03, 2013 at 11:02