Skip to content

Instantly share code, notes, and snippets.

@seobyeongky
Last active August 19, 2024 10:24
Show Gist options
  • Save seobyeongky/78b659accacac2051770ac9ee54dc8d6 to your computer and use it in GitHub Desktop.
Save seobyeongky/78b659accacac2051770ac9ee54dc8d6 to your computer and use it in GitHub Desktop.
Triangle fill algorithm (scanline)
public class RenderUtils
{
//Modified From : http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html
public static void FillTriangleInGrid(Vector2 a, Vector2 b, Vector2 c, System.Action<int,int> plot)
{
/* at first sort the three vertices by y-coordinate ascending so v1 is the topmost vertice */
if (a.y < b.y)
swap(ref a, ref b);
if (b.y < c.y)
swap(ref b, ref c);
if (a.y < b.y)
swap(ref a, ref b);
/* here we know that v1.y <= v2.y <= v3.y */
/* check for trivial case of bottom-flat triangle */
if (b.y == c.y)
{
FillBottomFlatTriangle(a, b, c, plot);
}
/* check for trivial case of top-flat triangle */
else if (a.y == b.y)
{
FillTopFlatTriangle(a, b, c, plot);
}
else
{
/* general case - split the triangle in a topflat and bottom-flat one */
Vector2 d = new Vector2((a.x + ((float)(b.y - a.y) / (float)(c.y - a.y)) * (c.x - a.x)), b.y);
FillBottomFlatTriangle(a, b, d, plot);
FillTopFlatTriangle(b, d, c, plot);
}
}
static void FillBottomFlatTriangle(Vector2 v1, Vector2 v2, Vector2 v3, System.Action<int,int> plot)
{
if (IsApproximatelyZero(v1.y - v2.y)) // 예외처리
return;
if (v2.x > v3.x)
(v2,v3) = (v3,v2);
float invslope1 = (v2.x - v1.x) / (v2.y - v1.y);
float invslope2 = (v3.x - v1.x) / (v3.y - v1.y);
float curx1 = v2.x;
float curx2 = v3.x;
int scanlineYBegin = (int)(v2.y);
float err = v2.y - (scanlineYBegin + 0.5f);
curx1 -= invslope1 * err;
curx2 -= invslope2 * err;
if (err > 0) //예외처리 : 보외법에 의해 삐져나가기 때문에 아예 한 row전체를 skip한다
{
scanlineYBegin++;
curx1 += invslope1;
curx2 += invslope2;
}
for (int scanlineY = scanlineYBegin; scanlineY < (v1.y + 0.5f); scanlineY++)
{
for (int x = (int)(curx1 + 0.5f); x <= (curx2 - 0.5f); x++)
plot(x, scanlineY);
curx1 += invslope1;
curx2 += invslope2;
}
}
static void FillTopFlatTriangle(Vector2 v1, Vector2 v2, Vector2 v3, System.Action<int,int> plot)
{
if (IsApproximatelyZero(v3.y - v1.y)) // 예외처리
return;
if (v1.x > v2.x)
(v1,v2) = (v2,v1);
float invslope1 = (v3.x - v1.x) / (v3.y - v1.y);
float invslope2 = (v3.x - v2.x) / (v3.y - v2.y);
float curx1 = v1.x;
float curx2 = v2.x;
int scanlineYBegin = (int)(v1.y);
float err = v1.y - (scanlineYBegin + 0.5f);
curx1 -= invslope1 * err;
curx2 -= invslope2 * err;
if (err < 0) //예외처리 : 보외법에 의해 삐져나가기 때문에 아예 한 row전체를 skip한다
{
scanlineYBegin--;
curx1 -= invslope1;
curx2 -= invslope2;
}
for (int scanlineY = scanlineYBegin; scanlineY >= (v3.y-0.5f); scanlineY--)
{
for (int x = (int)(curx1 + 0.5f); x <= (curx2 - 0.5f); x++)
plot(x, scanlineY);
// drawLine((int)curx1, scanlineY, (int)curx2, scanlineY);
curx1 -= invslope1;
curx2 -= invslope2;
}
}
static void swap<T>(ref T a, ref T b)
{
(a,b) = (b,a);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool IsApproximatelyZero(float f, float eps = 0.001f)
{
// return Mathf.Approximately(f, 0); => 1.49011612E-08도 false로 너무 엄격한 함수
return -eps <= f && f <= eps;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment