Sign in to follow this  
Ectara

Texture mapping in software rasterizer

Recommended Posts

Ectara    3097
I am having an issue in my software renderer where if I draw a triangle or a quad that isn't parallel to the viewport, the texture will skew rather than do a perspective correct transformation. As the image below shows, along the boundaries of the triangles in the quads, the texture skews; if the quad was a parallelogram, the texture would fit without distortion. But, as it is a trapezoid, the two triangles have mismatched skewed images. The image is looking inside of a cube with the nearest face culled; the quad farthest away is a scaled down version of what the texture would look like. http://i871.photobucket.com/albums/ab274/Ectara/comp.png The question I'm wondering is, is there any sort of transformation I could be applying to the texture coordinates to gain the correct information to rotate the texture coordinates or something? Bear in mind, I do have a modelview matrix, but using it doesn't guarantee that the triangle won't just be drawn skew to the viewport plane to begin with.

Share this post


Link to post
Share on other sites
Krypt0n    4721
you are right,its not perspective correct interpolated. lookup for perspective vorrect texture interpolation on google, there are plenty of tutorials, like those from chris hecker.

Share this post


Link to post
Share on other sites
Ectara    3097
Thanks Krypt0n. I tried looking it up, and implementing the concepts found several times. But, all the formulas I could find use the so-called "poor man's projection"( x/z, y/z, 1/z). Mine uses a projection matrix and a homogenous divide by w. I can't seem to figure out how to implement this with my setup.

Share this post


Link to post
Share on other sites
ProfL    701
Quote:
Original post by Ectara
Thanks Krypt0n. I tried looking it up, and implementing the concepts found several times. But, all the formulas I could find use the so-called "poor man's projection"( x/z, y/z, 1/z). Mine uses a projection matrix and a homogenous divide by w. I can't seem to figure out how to implement this with my setup.

I've asked a similar question some time ago
http://www.gamedev.net/community/forums/topic.asp?topic_id=564019

there you have some links and explanation how to interpolate UVs (but ginkgo's explanation is kinda the short version :) ).

maybe you could tell me how you interpolate z in your none-poor-man's rasterizer.
It's working for me with just linear interpolation, but I was sure it cannot be interpolated linearly :/

Thx in advanced.

Share this post


Link to post
Share on other sites
mzeo77    168
For getting perspective correct you need to divide by a linearly interpolated value for each pixel.


// Setup values needed for each scanline
float uw = ..., vw = ..., w = ...
float duw = ..., dvw = ..., dw = ...
// Plot each pixel in scanline
for x in scanline {
float u = uw / w
fluat v = vw / w
plot(x, y, texture(u, v))
uw += duw
vw += dvw
w += dw
}


Where w are the same w you use for position. You should be able to calculate the rest of the values.


[Edited by - mzeo77 on March 18, 2010 6:29:11 AM]

Share this post


Link to post
Share on other sites
Ectara    3097
As for my projection function:

void E_renderProject(vector3 world, vector3 screen){
vector4 v;

/*These transform functions multiply {arg2[0],arg2[1],arg2[2],1.0f} by the matrix pointed to by the first argument, and the result is copied to the third argument*/
E_renderTransformVector34(E_globalRenderContext.raster.model, world, v);
/* Point is not visible, don't bother. */
if(!E_renderClipFrustumPoint(v)){
screen[0] = screen[1] = screen[2] = -1;
return;
}
/*Likewise, but with {arg2[0],arg2[1],arg2[2],arg2[3]}*/
E_renderTransformVector4(E_globalRenderContext.raster.projection, v, v);

/* Don't divide by zero, but don't raise an error; this could occur normally, I'd suppose. Set it to zero to give a clue that it failed.*/
if(!v[3]){
_E_vectorClear(screen);
return;
}

/*Divide X, Y, and Z by W*/
_E_vectorDivideScalar(v,v[3],v);
v[0] = v[0] * 0.5f + 0.5f;
v[1] = v[1] * 0.5f + 0.5f;
v[2] = v[2] * 0.5f + 0.5f;

v[0] *= E_globalRenderContext.display->image->width;
v[1] *= E_globalRenderContext.display->image->height;
v[1] = E_globalRenderContext.display->image->height - v[1];

if(v[2] > 1){
v[0] = -v[0];
v[1] = -v[1];
}

/* In this line, the w coordinate is discarded. Only using 3D for now. */
_E_vectorCopy(screen,v);
}


Then, to interpolate Z later on, I lerp 1/Z. Note that the W is discarded. Should I be keeping the extra dimension for each vertex?

Share this post


Link to post
Share on other sites
Ectara    3097
Thanks gingko, ProfL, and mzeo77 for the advice. Modified a projection function and a couple structures to use the w coordinate, and interpolated using homogeneity that way. It is now evident that the w coordinate should not be discarded after projection, and the formulae in Wikipedia and such are unusable for my purposes. I got it working, and here's a before and after image: http://i871.photobucket.com/albums/ab274/Ectara/comp.png. For the interpolation, I used pretty much the same algorithm from Wikipedia, except with 'w' replacing 'z', and several optimizations.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this