mirror of
https://git.coom.tech/drummyfish/small3dlib.git
synced 2024-11-21 20:39:57 +01:00
Fix rasterization bug (holes)
This commit is contained in:
parent
70622f2ba4
commit
5f09e37291
3 changed files with 47 additions and 62 deletions
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
#define S3L_FLAT 0
|
#define S3L_FLAT 0
|
||||||
#define S3L_STRICT_NEAR_CULLING 1
|
#define S3L_STRICT_NEAR_CULLING 1
|
||||||
#define S3L_PERSPECTIVE_CORRECTION 0
|
#define S3L_PERSPECTIVE_CORRECTION 2
|
||||||
#define S3L_SORT 0
|
#define S3L_SORT 0
|
||||||
#define S3L_STENCIL_BUFFER 0
|
#define S3L_STENCIL_BUFFER 0
|
||||||
#define S3L_Z_BUFFER 1
|
#define S3L_Z_BUFFER 1
|
||||||
|
|
104
small3dlib.h
104
small3dlib.h
|
@ -557,9 +557,8 @@ static inline void S3L_mapProjectionPlaneToScreen(
|
||||||
S3L_ScreenCoord *screenY);
|
S3L_ScreenCoord *screenY);
|
||||||
|
|
||||||
/** Draws a triangle according to given config. The vertices are specified in
|
/** Draws a triangle according to given config. The vertices are specified in
|
||||||
projection-plane space (NOT screen space!) -- they wll be mapped to screen
|
Screen Space space (pixels). If perspective correction is enabled, each
|
||||||
space by thies function. If perspective correction is enabled, each vertex
|
vertex has to have a depth (Z position in camera space) specified in the Z
|
||||||
has to have a depth (Z position in camera space) specified in the Z
|
|
||||||
component. */
|
component. */
|
||||||
void S3L_drawTriangle(
|
void S3L_drawTriangle(
|
||||||
S3L_Vec4 point0,
|
S3L_Vec4 point0,
|
||||||
|
@ -1624,22 +1623,10 @@ void S3L_drawTriangle(
|
||||||
point2.z = point2.z >= S3L_NEAR ? point2.z : S3L_NEAR;
|
point2.z = point2.z >= S3L_NEAR ? point2.z : S3L_NEAR;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
S3L_Vec4 *tPointPP, *lPointPP, *rPointPP; /* points in projction plane space
|
S3L_Vec4 *tPointSS, *lPointSS, *rPointSS; /* points in Screen Space (in
|
||||||
(in Units, normalized by
|
S3L_Units, normalized by
|
||||||
S3L_FRACTIONS_PER_UNIT) */
|
S3L_FRACTIONS_PER_UNIT) */
|
||||||
|
|
||||||
S3L_ScreenCoord x0, y0, x1, y1, x2, y2; /* points in screen space (pixel
|
|
||||||
coordinates) */
|
|
||||||
|
|
||||||
S3L_mapProjectionPlaneToScreen(point0,&x0,&y0);
|
|
||||||
S3L_mapProjectionPlaneToScreen(point1,&x1,&y1);
|
|
||||||
S3L_mapProjectionPlaneToScreen(point2,&x2,&y2);
|
|
||||||
|
|
||||||
S3L_ScreenCoord
|
|
||||||
tPointSx, tPointSy, // top point coords, in screen space
|
|
||||||
lPointSx, lPointSy, // left point coords, in screen space
|
|
||||||
rPointSx, rPointSy; // right point coords, in screen space
|
|
||||||
|
|
||||||
S3L_Unit *barycentric0; // bar. coord that gets higher from L to R
|
S3L_Unit *barycentric0; // bar. coord that gets higher from L to R
|
||||||
S3L_Unit *barycentric1; // bar. coord that gets higher from R to L
|
S3L_Unit *barycentric1; // bar. coord that gets higher from R to L
|
||||||
S3L_Unit *barycentric2; // bar. coord that gets higher from bottom up
|
S3L_Unit *barycentric2; // bar. coord that gets higher from bottom up
|
||||||
|
@ -1648,38 +1635,33 @@ void S3L_drawTriangle(
|
||||||
|
|
||||||
#define assignPoints(t,a,b)\
|
#define assignPoints(t,a,b)\
|
||||||
{\
|
{\
|
||||||
tPointSx = x##t;\
|
tPointSS = &point##t;\
|
||||||
tPointSy = y##t;\
|
|
||||||
tPointPP = &point##t;\
|
|
||||||
barycentric2 = &(p.barycentric[t]);\
|
barycentric2 = &(p.barycentric[t]);\
|
||||||
if (S3L_triangleWinding(x##t,y##t,x##a,y##a,x##b,y##b) >= 0)\
|
if (S3L_triangleWinding(point##t.x,point##t.y,point##a.x,point##a.y,\
|
||||||
|
point##b.x,point##b.y) >= 0)\
|
||||||
{\
|
{\
|
||||||
lPointSx = x##a; lPointSy = y##a;\
|
lPointSS = &point##a; rPointSS = &point##b;\
|
||||||
rPointSx = x##b; rPointSy = y##b;\
|
|
||||||
lPointPP = &point##a; rPointPP = &point##b;\
|
|
||||||
barycentric0 = &(p.barycentric[b]);\
|
barycentric0 = &(p.barycentric[b]);\
|
||||||
barycentric1 = &(p.barycentric[a]);\
|
barycentric1 = &(p.barycentric[a]);\
|
||||||
}\
|
}\
|
||||||
else\
|
else\
|
||||||
{\
|
{\
|
||||||
lPointSx = x##b; lPointSy = y##b;\
|
lPointSS = &point##b; rPointSS = &point##a;\
|
||||||
rPointSx = x##a; rPointSy = y##a;\
|
|
||||||
lPointPP = &point##b; rPointPP = &point##a;\
|
|
||||||
barycentric0 = &(p.barycentric[a]);\
|
barycentric0 = &(p.barycentric[a]);\
|
||||||
barycentric1 = &(p.barycentric[b]);\
|
barycentric1 = &(p.barycentric[b]);\
|
||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y0 <= y1)
|
if (point0.y <= point1.y)
|
||||||
{
|
{
|
||||||
if (y0 <= y2)
|
if (point0.y <= point2.y)
|
||||||
assignPoints(0,1,2)
|
assignPoints(0,1,2)
|
||||||
else
|
else
|
||||||
assignPoints(2,0,1)
|
assignPoints(2,0,1)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (y1 <= y2)
|
if (point1.y <= point2.y)
|
||||||
assignPoints(1,0,2)
|
assignPoints(1,0,2)
|
||||||
else
|
else
|
||||||
assignPoints(2,0,1)
|
assignPoints(2,0,1)
|
||||||
|
@ -1688,14 +1670,15 @@ void S3L_drawTriangle(
|
||||||
#undef assignPoints
|
#undef assignPoints
|
||||||
|
|
||||||
#if S3L_FLAT
|
#if S3L_FLAT
|
||||||
p.depth = (tPointPP->z + lPointPP->z + rPointPP->z) / 3;
|
p.depth = (tPointSS->z + lPointSS->z + rPointSS->z) / 3;
|
||||||
*barycentric0 = S3L_FRACTIONS_PER_UNIT / 3;
|
*barycentric0 = S3L_FRACTIONS_PER_UNIT / 3;
|
||||||
*barycentric1 = S3L_FRACTIONS_PER_UNIT / 3;
|
*barycentric1 = S3L_FRACTIONS_PER_UNIT / 3;
|
||||||
*barycentric2 = S3L_FRACTIONS_PER_UNIT - 2 * (S3L_FRACTIONS_PER_UNIT / 3);
|
*barycentric2 = S3L_FRACTIONS_PER_UNIT - 2 * (S3L_FRACTIONS_PER_UNIT / 3);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
p.triangleSize[0] = rPointSx - lPointSx;
|
p.triangleSize[0] = rPointSS->x - lPointSS->x;
|
||||||
p.triangleSize[1] = (rPointSy > lPointSy ? rPointSy : lPointSy) - tPointSy;
|
p.triangleSize[1] = (rPointSS->y > lPointSS->y ? rPointSS->y : lPointSS->y)
|
||||||
|
- tPointSS->y;
|
||||||
|
|
||||||
// now draw the triangle line by line:
|
// now draw the triangle line by line:
|
||||||
|
|
||||||
|
@ -1704,20 +1687,20 @@ void S3L_drawTriangle(
|
||||||
int splitOnLeft; /* whether splitY is the y coord. of left or right
|
int splitOnLeft; /* whether splitY is the y coord. of left or right
|
||||||
point */
|
point */
|
||||||
|
|
||||||
if (rPointSy <= lPointSy)
|
if (rPointSS->y <= lPointSS->y)
|
||||||
{
|
{
|
||||||
splitY = rPointSy;
|
splitY = rPointSS->y;
|
||||||
splitOnLeft = 0;
|
splitOnLeft = 0;
|
||||||
endY = lPointSy;
|
endY = lPointSS->y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
splitY = lPointSy;
|
splitY = lPointSS->y;
|
||||||
splitOnLeft = 1;
|
splitOnLeft = 1;
|
||||||
endY = rPointSy;
|
endY = rPointSS->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
S3L_ScreenCoord currentY = tPointSy;
|
S3L_ScreenCoord currentY = tPointSS->y;
|
||||||
|
|
||||||
/* We'll be using an algorithm similar to Bresenham line algorithm. The
|
/* We'll be using an algorithm similar to Bresenham line algorithm. The
|
||||||
specifics of this algorithm are among others:
|
specifics of this algorithm are among others:
|
||||||
|
@ -1756,8 +1739,8 @@ void S3L_drawTriangle(
|
||||||
S3L_FastLerpState lDepthFLS, rDepthFLS;
|
S3L_FastLerpState lDepthFLS, rDepthFLS;
|
||||||
|
|
||||||
#define initDepthFLS(s,p1,p2)\
|
#define initDepthFLS(s,p1,p2)\
|
||||||
s##DepthFLS.valueScaled = p1##PointPP->z << S3L_FAST_LERP_QUALITY;\
|
s##DepthFLS.valueScaled = p1##PointSS->z << S3L_FAST_LERP_QUALITY;\
|
||||||
s##DepthFLS.stepScaled = ((p2##PointPP->z << S3L_FAST_LERP_QUALITY) -\
|
s##DepthFLS.stepScaled = ((p2##PointSS->z << S3L_FAST_LERP_QUALITY) -\
|
||||||
s##DepthFLS.valueScaled) / (s##Dy != 0 ? s##Dy : 1);
|
s##DepthFLS.valueScaled) / (s##Dy != 0 ? s##Dy : 1);
|
||||||
#else
|
#else
|
||||||
#define initDepthFLS(s,p1,p2) ;
|
#define initDepthFLS(s,p1,p2) ;
|
||||||
|
@ -1769,9 +1752,9 @@ void S3L_drawTriangle(
|
||||||
p2 - point to (t, l or r)
|
p2 - point to (t, l or r)
|
||||||
down - whether the side coordinate goes top-down or vice versa */
|
down - whether the side coordinate goes top-down or vice versa */
|
||||||
#define initSide(s,p1,p2,down)\
|
#define initSide(s,p1,p2,down)\
|
||||||
s##X = p1##PointSx;\
|
s##X = p1##PointSS->x;\
|
||||||
s##Dx = p2##PointSx - p1##PointSx;\
|
s##Dx = p2##PointSS->x - p1##PointSS->x;\
|
||||||
s##Dy = p2##PointSy - p1##PointSy;\
|
s##Dy = p2##PointSS->y - p1##PointSS->y;\
|
||||||
initDepthFLS(s,p1,p2)\
|
initDepthFLS(s,p1,p2)\
|
||||||
s##SideFLS.stepScaled = (S3L_FRACTIONS_PER_UNIT << S3L_FAST_LERP_QUALITY)\
|
s##SideFLS.stepScaled = (S3L_FRACTIONS_PER_UNIT << S3L_FAST_LERP_QUALITY)\
|
||||||
/ (s##Dy != 0 ? s##Dy : 1);\
|
/ (s##Dy != 0 ? s##Dy : 1);\
|
||||||
|
@ -1813,13 +1796,13 @@ void S3L_drawTriangle(
|
||||||
the above after split. */
|
the above after split. */
|
||||||
|
|
||||||
tPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
|
tPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
|
||||||
/ S3L_nonZero(tPointPP->z);
|
/ S3L_nonZero(tPointSS->z);
|
||||||
|
|
||||||
lPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
|
lPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
|
||||||
/ S3L_nonZero(lPointPP->z);
|
/ S3L_nonZero(lPointSS->z);
|
||||||
|
|
||||||
rPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
|
rPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
|
||||||
/ S3L_nonZero(rPointPP->z);
|
/ S3L_nonZero(rPointSS->z);
|
||||||
|
|
||||||
lRecip0 = tPointRecipZ;
|
lRecip0 = tPointRecipZ;
|
||||||
lRecip1 = lPointRecipZ;
|
lRecip1 = lPointRecipZ;
|
||||||
|
@ -2237,10 +2220,9 @@ int8_t S3L_triangleWinding(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if given triangle (in Projection Plane space) is at least partially
|
Checks if given triangle (in Screen Space) is at least partially visible,
|
||||||
visible, i.e. returns false if the triangle is either completely outside
|
i.e. returns false if the triangle is either completely outside the frustum
|
||||||
the frustum (left, right, top, bottom, near) or is invisible due to
|
(left, right, top, bottom, near) or is invisible due to backface culling.
|
||||||
backface culling.
|
|
||||||
*/
|
*/
|
||||||
static inline int8_t S3L_triangleIsVisible(
|
static inline int8_t S3L_triangleIsVisible(
|
||||||
S3L_Vec4 p0,
|
S3L_Vec4 p0,
|
||||||
|
@ -2252,17 +2234,16 @@ static inline int8_t S3L_triangleIsVisible(
|
||||||
(p0.c cmp (v) && p1.c cmp (v) && p2.c cmp (v))
|
(p0.c cmp (v) && p1.c cmp (v) && p2.c cmp (v))
|
||||||
|
|
||||||
if ( // outside frustum?
|
if ( // outside frustum?
|
||||||
|
|
||||||
#if S3L_STRICT_NEAR_CULLING
|
#if S3L_STRICT_NEAR_CULLING
|
||||||
p0.z <= S3L_NEAR || p1.z <= S3L_NEAR || p2.z <= S3L_NEAR ||
|
p0.z <= S3L_NEAR || p1.z <= S3L_NEAR || p2.z <= S3L_NEAR ||
|
||||||
// ^ partially in front of NEAR?
|
// ^ partially in front of NEAR?
|
||||||
#else
|
#else
|
||||||
clipTest(z,<=,S3L_NEAR) || // completely in front of NEAR?
|
clipTest(z,<=,S3L_NEAR) || // completely in front of NEAR?
|
||||||
#endif
|
#endif
|
||||||
clipTest(x,<,-1 * S3L_FRACTIONS_PER_UNIT) ||
|
clipTest(x,<,0) ||
|
||||||
clipTest(x,>,S3L_FRACTIONS_PER_UNIT) ||
|
clipTest(x,>=,S3L_RESOLUTION_X) ||
|
||||||
clipTest(y,<,-1 * S3L_PROJECTION_PLANE_HEIGHT / 2) ||
|
clipTest(y,<,0) ||
|
||||||
clipTest(y,>,S3L_PROJECTION_PLANE_HEIGHT / 2)
|
clipTest(y,>,S3L_RESOLUTION_Y)
|
||||||
)
|
)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -2273,8 +2254,8 @@ static inline int8_t S3L_triangleIsVisible(
|
||||||
int8_t winding =
|
int8_t winding =
|
||||||
S3L_triangleWinding(p0.x,p0.y,p1.x,p1.y,p2.x,p2.y);
|
S3L_triangleWinding(p0.x,p0.y,p1.x,p1.y,p2.x,p2.y);
|
||||||
|
|
||||||
if ((backfaceCulling == 1 && winding < 0) ||
|
if ((backfaceCulling == 1 && winding > 0) ||
|
||||||
(backfaceCulling == 2 && winding > 0))
|
(backfaceCulling == 2 && winding < 0))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2317,6 +2298,13 @@ void _S3L_projectVertex(
|
||||||
on NEAR, the triangle will be culled. */
|
on NEAR, the triangle will be culled. */
|
||||||
|
|
||||||
S3L_perspectiveDivide(result,focalLength);
|
S3L_perspectiveDivide(result,focalLength);
|
||||||
|
|
||||||
|
S3L_ScreenCoord sX, sY;
|
||||||
|
|
||||||
|
S3L_mapProjectionPlaneToScreen(*result,&sX,&sY);
|
||||||
|
|
||||||
|
result->x = sX;
|
||||||
|
result->y = sY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void S3L_drawScene(S3L_Scene scene)
|
void S3L_drawScene(S3L_Scene scene)
|
||||||
|
|
3
todo.txt
3
todo.txt
|
@ -76,9 +76,6 @@ bugs:
|
||||||
- Any of them can exceed the range <0,511>
|
- Any of them can exceed the range <0,511>
|
||||||
- b0 + b1 can be > 511, which causes b2 (= 511 - b0 - b1) to be negative!
|
- b0 + b1 can be > 511, which causes b2 (= 511 - b0 - b1) to be negative!
|
||||||
|
|
||||||
- There still ocassionally appear holes between rasterized triangles -- can be
|
|
||||||
well seen in Pokitto demo when drawing with single color.
|
|
||||||
|
|
||||||
repeated:
|
repeated:
|
||||||
|
|
||||||
- valgrind (and similar) checks
|
- valgrind (and similar) checks
|
||||||
|
|
Loading…
Reference in a new issue