Add documentation for barycentric coordinates
This commit is contained in:
parent
0738326384
commit
afcd158d7d
@ -143,21 +143,22 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NOTE(doyle): Given two points that form a line and an extra point
|
/////////////////////////////////////////////////////////////////////////
|
||||||
to test, we can determine whether a point lies on the line, or is
|
// Rearranging the Determinant
|
||||||
to the left or right of a the line.
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
Given two points that form a line and an extra point to test, we can
|
||||||
|
determine whether a point lies on the line, or is to the left or right of
|
||||||
|
a the line.
|
||||||
|
|
||||||
First forming a 3x3 matrix of our terms and deriving a 2x2 matrix
|
First forming a 3x3 matrix of our terms and deriving a 2x2 matrix by
|
||||||
by subtracting the 1st column from the 2nd and 1st column from
|
subtracting the 1st column from the 2nd and 1st column from the third.
|
||||||
the third.
|
|
||||||
|
|
||||||
| ax bx cx | | (bx - ax) (cx - ax) |
|
| ax bx cx | | (bx - ax) (cx - ax) |
|
||||||
m = | ay by cy | ==> | (by - ay) (cy - ay) |
|
m = | ay by cy | ==> | (by - ay) (cy - ay) |
|
||||||
| 1 1 1 |
|
| 1 1 1 |
|
||||||
|
|
||||||
From our 2x2 representation we can calculate the determinant
|
From our 2x2 representation we can calculate the determinant which gives
|
||||||
which gives us the signed area of the triangle extended into
|
us the signed area of the triangle extended into a parallelogram.
|
||||||
a parallelogram.
|
|
||||||
|
|
||||||
det(m) = (bx - ax)(cy - ay) - (by - ay)(cx - ax)
|
det(m) = (bx - ax)(cy - ay) - (by - ay)(cx - ax)
|
||||||
|
|
||||||
@ -167,38 +168,77 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer,
|
|||||||
- CW and c(x,y) is outside the triangle, the signed area is positive
|
- CW and c(x,y) is outside the triangle, the signed area is positive
|
||||||
- CW and c(x,y) is inside the triangle, the signed area is negative
|
- CW and c(x,y) is inside the triangle, the signed area is negative
|
||||||
|
|
||||||
NOTE(doyle): The det(m) can be rearranged if expanded to be
|
/////////////////////////////////////////////////////////////////////////
|
||||||
SignedArea(cx, cy) = (ay - by)cx + (bx - ay)cy + (ax*by + ay*bx)
|
// Optimising the Determinant Calculation
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
The det(m) can be rearranged if expanded to be
|
||||||
|
SignedArea(cx, cy) = (ay - by)cx + (bx - ay)cy + (ax*by - ay*bx)
|
||||||
|
|
||||||
When we scan to fill our triangle we go pixel by pixel, left to right,
|
When we scan to fill our triangle we go pixel by pixel, left to right,
|
||||||
bottom to top, notice that this translates to +1 for x and +1 for y, i.e.
|
bottom to top, notice that this translates to +1 for x and +1 for y, i.e.
|
||||||
|
|
||||||
The first pixel's signed area is cx, then cx+1, cx+2 .. etc
|
The first pixel's signed area is cx, then cx+1, cx+2 .. etc
|
||||||
SignedArea(cx, cy) = (ay - by)cx + (bx - ax)cy + (ax*by + ay*bx)
|
SignedArea(cx, cy) = (ay - by)cx + (bx - ax)cy + (ax*by - ay*bx)
|
||||||
SignedArea(cx+1, cy) = (ay - by)cx+1 + (bx - ax)cy + (ax*by + ay*bx)
|
SignedArea(cx+1, cy) = (ay - by)cx+1 + (bx - ax)cy + (ax*by - ay*bx)
|
||||||
|
|
||||||
Then
|
Then
|
||||||
SignedArea(cx+1, cy) - SignedArea(cx, cy) =
|
SignedArea(cx+1, cy) - SignedArea(cx, cy) =
|
||||||
(ay - by)cx+1 + (bx - ax)cy + (ax*by + ay*bx)
|
(ay - by)cx+1 + (bx - ax)cy + (ax*by - ay*bx)
|
||||||
- (ay - by)cx + (bx - ax)cy + (ax*by + ay*bx)
|
- (ay - by)cx + (bx - ax)cy + (ax*by - ay*bx)
|
||||||
= (ay - by)cx+1 - (ay - by)cx
|
= (ay - by)cx+1 - (ay - by)cx
|
||||||
= (ay - by)(cx+1 - cx)
|
= (ay - by)(cx+1 - cx)
|
||||||
= (ay - by)(1) = (ay - by)
|
= (ay - by)(1) = (ay - by)
|
||||||
|
|
||||||
Similarly when progressing in y
|
Similarly when progressing in y
|
||||||
SignedArea(cx, cy) = (ay - by)cx + (bx - ay)cy + (ax*by + ay*bx)
|
SignedArea(cx, cy) = (ay - by)cx + (bx - ay)cy + (ax*by - ay*bx)
|
||||||
SignedArea(cx, cy+1) = (ay - by)cx + (bx - ay)cy+1 + (ax*by + ay*bx)
|
SignedArea(cx, cy+1) = (ay - by)cx + (bx - ay)cy+1 + (ax*by - ay*bx)
|
||||||
|
|
||||||
Then
|
Then
|
||||||
SignedArea(cx, cy+1) - SignedArea(cx, cy) =
|
SignedArea(cx, cy+1) - SignedArea(cx, cy) =
|
||||||
(ay - by)cx + (bx - ax)cy+1 + (ax*by + ay*bx)
|
(ay - by)cx + (bx - ax)cy+1 + (ax*by - ay*bx)
|
||||||
- (ay - by)cx + (bx - ax)cy + (ax*by + ay*bx)
|
- (ay - by)cx + (bx - ax)cy + (ax*by - ay*bx)
|
||||||
= (bx - ax)cy+1 - (bx - ax)cy
|
= (bx - ax)cy+1 - (bx - ax)cy
|
||||||
= (bx - ax)(cy+1 - cy)
|
= (bx - ax)(cy+1 - cy)
|
||||||
= (bx - ax)(1) = (bx - ax)
|
= (bx - ax)(1) = (bx - ax)
|
||||||
|
|
||||||
Then we can see that when we progress along x, we only need to change by
|
Then we can see that when we progress along x, we only need to change by
|
||||||
the value of SignedArea by (ay - by) and similarly for y, (bx - ay)
|
the value of SignedArea by (ay - by) and similarly for y, (bx - ay)
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// Barycentric Coordinates
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
At this point we have an equation that can be used to calculate the
|
||||||
|
2x the signed area of a triangle, or the signed area of a parallelogram,
|
||||||
|
the two of which are equivalent.
|
||||||
|
|
||||||
|
det(m) = (bx - ax)(cy - ay) - (by - ay)(cx - ax)
|
||||||
|
SignedArea(cx, cy) = (ay - by)cx + (bx - ay)cy + (ax*by - ay*bx)
|
||||||
|
|
||||||
|
A barycentric coordinate is some coefficient on A, B, C that allows us to
|
||||||
|
specify an arbitrary point in the triangle as a linear combination of the
|
||||||
|
three usually with some coefficient [0, 1].
|
||||||
|
|
||||||
|
The SignedArea turns out to be actually the barycentric coord for c(x, y)
|
||||||
|
normalised to the sum of the parallelogram area. For example a triangle
|
||||||
|
with points, A, B, C and an arbitrary point P inside the triangle. Then
|
||||||
|
|
||||||
|
SignedArea(P) with vertex A and B = Barycentric Coordinate for C
|
||||||
|
SignedArea(P) with vertex B and C = Barycentric Coordinate for A
|
||||||
|
SignedArea(P) with vertex C and A = Barycentric Coordinate for B
|
||||||
|
|
||||||
|
B
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ P \
|
||||||
|
/_______\
|
||||||
|
A C
|
||||||
|
|
||||||
|
This is normalised to the area's sum, but we can trivially turn this into
|
||||||
|
a normalised version by dividing the area of the parallelogram, i.e.
|
||||||
|
|
||||||
|
BaryCentricA(P) = (SignedArea(P) w. vertex C and B)/SignedArea(of the orig triangle)
|
||||||
|
BaryCentricB(P) = (SignedArea(P) w. vertex A and C)/SignedArea(of the orig triangle)
|
||||||
|
BaryCentricC(P) = (SignedArea(P) w. vertex A and B)/SignedArea(of the orig triangle)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DqnV2i scanP = DqnV2i_2i(min.x, min.y);
|
DqnV2i scanP = DqnV2i_2i(min.x, min.y);
|
||||||
@ -263,7 +303,6 @@ FILE_SCOPE void DrawText(PlatformRenderBuffer *const renderBuffer,
|
|||||||
stbtt_aligned_quad alignedQuad = {};
|
stbtt_aligned_quad alignedQuad = {};
|
||||||
stbtt_GetPackedQuad(font.atlas, font.bitmapDim.w, font.bitmapDim.h,
|
stbtt_GetPackedQuad(font.atlas, font.bitmapDim.w, font.bitmapDim.h,
|
||||||
charIndex, &pos.x, &pos.y, &alignedQuad, true);
|
charIndex, &pos.x, &pos.y, &alignedQuad, true);
|
||||||
stbtt_packedchar *charData = font.atlas + charIndex;
|
|
||||||
|
|
||||||
DqnRect fontRect = {};
|
DqnRect fontRect = {};
|
||||||
fontRect.min = DqnV2_2f(alignedQuad.s0 * font.bitmapDim.w, alignedQuad.t1 * font.bitmapDim.h);
|
fontRect.min = DqnV2_2f(alignedQuad.s0 * font.bitmapDim.w, alignedQuad.t1 * font.bitmapDim.h);
|
||||||
@ -279,7 +318,13 @@ FILE_SCOPE void DrawText(PlatformRenderBuffer *const renderBuffer,
|
|||||||
u8 *fontPtr = font.bitmap + fontOffset;
|
u8 *fontPtr = font.bitmap + fontOffset;
|
||||||
|
|
||||||
DQN_ASSERT(sizeof(u32) == renderBuffer->bytesPerPixel);
|
DQN_ASSERT(sizeof(u32) == renderBuffer->bytesPerPixel);
|
||||||
|
|
||||||
|
// NOTE(doyle): This offset, yOffset and flipping t1, t0 is necessary
|
||||||
|
// for reversing the order of the font since its convention is 0,0 top
|
||||||
|
// left and -ve Y.
|
||||||
|
stbtt_packedchar *const charData = font.atlas + charIndex;
|
||||||
f32 fontHeightOffset = charData->yoff2 + charData->yoff;
|
f32 fontHeightOffset = charData->yoff2 + charData->yoff;
|
||||||
|
|
||||||
u32 screenOffset = (u32)(screenRect.min.x + (screenRect.min.y - fontHeightOffset) * renderBuffer->width);
|
u32 screenOffset = (u32)(screenRect.min.x + (screenRect.min.y - fontHeightOffset) * renderBuffer->width);
|
||||||
u32 *screenPtr = ((u32 *)renderBuffer->memory) + screenOffset;
|
u32 *screenPtr = ((u32 *)renderBuffer->memory) + screenOffset;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user