Sign in to follow this  
OrangyTang

Perspective correct barycentric coordinates

Recommended Posts

As title, I'm trying to do perspective correct texturing in a software renderer. So far I have non-perspective correct texturing by looping over the bounding box of a triangle, calculating the barycentric coords, then either rejecting the pixel or using the coords to do texturing. Simple (and slow) but works, and I'm trying not to worry *too* much about performance right now.

In particular, I'm trying to implement this as described by [url=http://www.gamedev.net/topic/595604-resources-for-writing-a-software-renderer/page__view__findpost__p__4775563]Erik Rufelt here[/url], that is, some magic barycentric coord formula that I can't quite find/grasp that generates perspective correct interpolants, instead of going the long way and correcting them manually for every value to be interpolated.

[url=http://maxest.gct-game.net/vainmoinen/bachelor_thesis.pdf]Maxest's thesis[/url] lists pseudo code for this, but I can't figure out what the distance() pseudo instruction does, nor how it relates to my existing barycentric coord calculation, as it appears to be using a completely different approach.

So far, I have this:
[code]
public void rasteriseTriangle(Vector3f ndc0, Colour4f c0, Vector2f uv0,

Vector3f ndc1, Colour4f c1, Vector2f uv1,

Vector3f ndc2, Colour4f c2, Vector2f uv2)

{

Vector2f p0 = ndcToScreen(ndc0);

Vector2f p1 = ndcToScreen(ndc1);

Vector2f p2 = ndcToScreen(ndc2);



// First find screen rect (clamped to screen bounds)

final int screenXMin = Math.max((int)Math.floor( Math.min(Math.min(p0.x, p1.x), p2.x) ), 0);

final int screenYMin = Math.max((int)Math.floor( Math.min(Math.min(p0.y, p1.y), p2.y) ), 0);



final int screenXMax = Math.min((int)Math.ceil( Math.max(Math.max(p0.x, p1.x), p2.x) ), backbuffer.getWidth()-1);

final int screenYMax = Math.min((int)Math.ceil( Math.max(Math.max(p0.y, p1.y), p2.y) ), backbuffer.getHeight()-1);



// Iterate



final float detT = (p1.y - p2.y) * (p0.x - p2.x) + (p2.x - p1.x) * (p0.y - p2.y);




// If detT == 0, then triangle is degenerate, so skip

if (detT != 0.0f)

{

// Loop over screen bounds

for (int y=screenYMin; y<=screenYMax; y++)

{

for (int x=screenXMin; x<=screenXMax; x++)

{

// l1 = (y2 - y3)(x - x3) + (x3 - x2)(y - y3) / detT

// l2 = (y3 - y1)(x - x3) + (x1 - x3)(y - y3) / detT

// l3 = 1 - l2 - l1



final float l1 = ( (p1.y - p2.y) * ((float)x - p2.x) + (p2.x - p1.x) * ((float)y - p2.y) ) / detT;

final float l2 = ( (p2.y - p0.y) * ((float)x - p2.x) + (p0.x - p2.x) * ((float)y - p2.y) ) / detT;

final float l3 = 1.0f - l2 - l1;



// If barycentric coords are all in the range [0, 1] then we lie in the triangle

// - we add a small epsilon on the compare with zero check to fill the edges correctly

// - we don't actually have to compare againct one because with the equation above none

// all of the coords sum to one



final float epsilon = -0.000000059604645f;

if (l1 >= epsilon // && l1 <= 1.0f

&& l2 >= epsilon //&& l2 <= 1.0f

&& l3 >= epsilon //&& l3 <= 1.0f

)

{

// Within triangle!



// Find depth by lerping vertex depths

final float z = ndc0.z * l1 + ndc1.z * l2 + ndc2.z * l3;



// Depth buffer just has raw depth values



// Test depth buffer

final int pixelLoc = x + y * backbuffer.getWidth();

if (z <= depthBuffer[pixelLoc]) // TODO: Also test for z<1 for far plane clipping

{

// Write depth buffer

depthBuffer[pixelLoc] = z;



// Lerp vertex colours

final float r = c0.r * l1 + c1.r * l2 + c2.r * l3;

final float g = c0.g * l1 + c1.g * l2 + c2.g * l3;

final float b = c0.b * l1 + c1.b * l2 + c2.b * l3;

final float a = c0.a * l1 + c1.a * l2 + c2.a * l3;



// Lerp texture coords

final float u = uv0.x * l1 + uv1.x * l2 + uv2.x * l3;

final float v = uv0.y * l1 + uv1.y * l2 + uv2.y * l3;



// Sample texture

Colour4f textureColour = testTexture.sample(u, v);



final int red = (int)((r * 255.0f) * (textureColour.r));

final int green = (int)((g * 255.0f) * (textureColour.g));

final int blue = (int)((b * 255.0f) * (textureColour.b));

final int alpha = (int)((a * 255.0f) * (textureColour.a));



final int argb = packRgba(red, green, blue, alpha);



int[] pixels=((DataBufferInt)(backbuffer.getRaster().getDataBuffer())).getData();

pixels[pixelLoc] = argb;

}



}

}

}

}

}[/code]


Any pointers as to what I'm conceptually not getting would be helpful. Thanks.

Share this post


Link to post
Share on other sites
Oh, I also found [url=http://fileadmin.cs.lth.se/cs/Education/EDAN35/lectures/L2-rasterization.pdf]this presentation[/url], which superficially makes more sense, but again the actual formulas escape me, probably because it seems to introduce new variables / letters without actually defining them. >_< If anyone can give me some hints as to how to understand the 'edge vectors' in it then that would be helpful. Thanks.

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