Created
January 7, 2020 21:32
-
-
Save kgabis/4cc0fe974595ca8370eddcbdf86a3ea0 to your computer and use it in GitHub Desktop.
Rasterise triangle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define EDGE_FUNC(a, b, c) (((c).x - (a).x) * ((b).y - (a).y) - ((c).y - (a).y) * ((b).x - (a).x)) | |
static void rasterize_triangle(old_renderer_t *r, const scene_t *scene, const triangle_t *t) { | |
vec3_t a = t->a, b = t->b, c = t->c; | |
float inv_az = 1.0f/a.z; | |
float inv_bz = 1.0f/b.z; | |
float inv_cz = 1.0f/c.z; | |
// projected | |
vec2_t a_2p = vec2_mults(vec2_make(a.x, a.y), inv_az); | |
vec2_t b_2p = vec2_mults(vec2_make(b.x, b.y), inv_bz); | |
vec2_t c_2p = vec2_mults(vec2_make(c.x, c.y), inv_cz); | |
// backface culling | |
vec2_t a2b2 = vec2_sub(b_2p, a_2p); | |
vec2_t a2c2 = vec2_sub(c_2p, a_2p); | |
float x = vec2_cross(a2b2, a2c2); | |
if (x > 0.0) { | |
return; | |
} | |
// ndc | |
vec2_t a_2ndc = vec2_div(vec2_add(a_2p, vec2_make(CANVAS_WIDTH/2.0, CANVAS_HEIGHT/2.0)), vec2_make(CANVAS_WIDTH, CANVAS_HEIGHT)); | |
vec2_t b_2ndc = vec2_div(vec2_add(b_2p, vec2_make(CANVAS_WIDTH/2.0, CANVAS_HEIGHT/2.0)), vec2_make(CANVAS_WIDTH, CANVAS_HEIGHT)); | |
vec2_t c_2ndc = vec2_div(vec2_add(c_2p, vec2_make(CANVAS_WIDTH/2.0, CANVAS_HEIGHT/2.0)), vec2_make(CANVAS_WIDTH, CANVAS_HEIGHT)); | |
// raster | |
vec2_t a_2r = vec2_mult(a_2ndc, vec2_make(r->width, r->height)); | |
vec2_t b_2r = vec2_mult(b_2ndc, vec2_make(r->width, r->height)); | |
vec2_t c_2r = vec2_mult(c_2ndc, vec2_make(r->width, r->height)); | |
int xmin = min3i(a_2r.x, b_2r.x, c_2r.x); | |
int xmax = max3i(a_2r.x, b_2r.x, c_2r.x); | |
int ymin = min3i(a_2r.y, b_2r.y, c_2r.y); | |
int ymax = max3i(a_2r.y, b_2r.y, c_2r.y); | |
if ((xmin < 0 && xmax < 0) || (ymin < 0 && ymax < 0) | |
|| (xmin > r->width && xmax > r->width) | |
|| (ymin > r->height && ymax > r->height)) { | |
return; | |
} | |
xmin = max2i(xmin, 0); | |
xmax = min2i(xmax, r->width-1); | |
ymin = max2i(ymin, 0); | |
ymax = min2i(ymax, r->height-1); | |
float area = EDGE_FUNC(a_2r, b_2r, c_2r); | |
if (area == 0) { | |
return; | |
} | |
float inv_area = 1.0f / area; | |
int fdid = -1; | |
vec2_t v0 = a_2r, v1 = b_2r, v2 = c_2r; | |
float a12 = (v2.y - v1.y); | |
float b12 = (v1.x - v2.x); | |
float c12 = (v2.x*v1.y - v2.y*v1.x); | |
float a20 = (v0.y - v2.y); | |
float b20 = (v2.x - v0.x); | |
float c20 = (v0.x*v2.y - v0.y*v2.x); | |
float a01 = (v1.y - v0.y); | |
float b01 = (v0.x - v1.x); | |
float c01 = (v1.x*v0.y - v1.y*v0.x); | |
vec2_t p = vec2_make(xmin+0.5f, ymin+0.5f); | |
float row_f12 = a12*p.x + b12*p.y + c12; | |
float row_f20 = a20*p.x + b20*p.y + c20; | |
float row_f01 = a01*p.x + b01*p.y + c01; | |
for (int y = ymin; y <= ymax; y+=1) { | |
bool was_inside = false; | |
float f12 = row_f12; | |
float f20 = row_f20; | |
float f01 = row_f01; | |
for (int x = xmin; x <= xmax; x+=1) { | |
if (f12 < 0 || f20 < 0 || f01 < 0) { | |
if (was_inside) { | |
break; | |
} | |
f12 += a12; | |
f20 += a20; | |
f01 += a01; | |
continue; | |
} | |
was_inside = true; | |
float w0 = f12 * inv_area; | |
float w1 = f20 * inv_area; | |
float w2 = f01 * inv_area; | |
float inv_z = (w0*inv_az) + (w1*inv_bz) + (w2*inv_cz); | |
int ix = (r->width*(r->height-y-1)+(r->width-x-1)); | |
if (inv_z < r->zbuffer[ix]) { | |
f12 += a12; | |
f20 += a20; | |
f01 += a01; | |
continue; | |
} | |
r->zbuffer[ix] = inv_z; | |
if (fdid == -1) { | |
vec2_t st0 = vec2_mults(t->ta, inv_az); | |
vec2_t st1 = vec2_mults(t->tb, inv_bz); | |
vec2_t st2 = vec2_mults(t->tc, inv_cz); | |
vec3_t n = vec3_cross(vec3_sub(t->b, t->a), vec3_sub(t->c, t->a)); | |
n = vec3_normalize(n); | |
float pxa = (t->a.x*-inv_az), pxb = (t->b.x*-inv_bz), pxc = (t->c.x*-inv_cz); | |
float pya = (t->a.y*-inv_az), pyb = (t->b.y*-inv_bz), pyc = (t->c.y*-inv_cz); | |
fragment_data_t fd = (fragment_data_t) { | |
.inv_az = inv_az, | |
.inv_bz = inv_bz, | |
.inv_cz = inv_cz, | |
.st0 = st0, | |
.st1 = st1, | |
.st2 = st2, | |
.n = n, | |
.pxa = pxa, .pxb = pxb, .pxc = pxc, | |
.pya = pya, .pyb = pyb, .pyc = pyc, | |
.tex = t->texture, | |
}; | |
dynarray_append(&r->fragment_data, &fd); | |
fdid = (int)r->fragment_data.count-1; | |
} | |
r->fragment_buffer[ix] = (fragment_t){ | |
.data_id = fdid, | |
.w0 = w0, | |
.w1 = w1, | |
.inv_z = inv_z, | |
}; | |
f12 += a12; | |
f20 += a20; | |
f01 += a01; | |
} | |
row_f12 += b12; | |
row_f20 += b20; | |
row_f01 += b01; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment