Skip to content

Instantly share code, notes, and snippets.

@kgabis
Created January 7, 2020 21:32
Show Gist options
  • Save kgabis/4cc0fe974595ca8370eddcbdf86a3ea0 to your computer and use it in GitHub Desktop.
Save kgabis/4cc0fe974595ca8370eddcbdf86a3ea0 to your computer and use it in GitHub Desktop.
Rasterise triangle
#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