Skip to main content
GameDev.net gamedev.net
🔒 Locked

Perspective correct barycentric coordinates

Started by OrangyTang Oct 18, 2011 at 11:58 PM 0 replies 3k views
Original Post
OrangyTang
OrangyTang
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 Erik Rufelt here, 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.

Maxest's thesis 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:

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;

}



}

}

}

}

}



Any pointers as to what I'm conceptually not getting would be helpful. Thanks.
OrangyTang
OrangyTang
Oh, I also found this presentation, 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.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.