From d3b48593b0fee862ea60687336031fd9374ab667 Mon Sep 17 00:00:00 2001 From: rodri Date: Sat, 10 Aug 2024 17:57:02 +0000 Subject: experimental A-buffer implementation. very simple, without anti-aliasing, made for getting OIT (order independent transparency) rendering of arbitrary objects. also added switches for blending, depth testing and the A-buffer to the camera. --- camera.c | 1 + fb.c | 11 +++++++ graphics.h | 29 +++++++++++++++++ render.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 132 insertions(+), 15 deletions(-) diff --git a/camera.c b/camera.c index 2a31738..8395c0e 100644 --- a/camera.c +++ b/camera.c @@ -126,6 +126,7 @@ newcamera(void) c = emalloc(sizeof *c); memset(c, 0, sizeof *c); + c->enabledepth = 1; return c; } diff --git a/fb.c b/fb.c index 88883fd..6bd22e9 100644 --- a/fb.c +++ b/fb.c @@ -211,6 +211,16 @@ framebufctl_swap(Framebufctl *ctl) qunlock(ctl); } +static void +resetAbuf(Abuf *buf) +{ + while(buf->nact--) + free(buf->act[buf->nact]->items); + free(buf->act); + free(buf->stk); + memset(buf, 0, sizeof *buf); +} + static void framebufctl_reset(Framebufctl *ctl) { @@ -218,6 +228,7 @@ framebufctl_reset(Framebufctl *ctl) /* address the back buffer—resetting the front buffer is VERBOTEN */ fb = ctl->getbb(ctl); + resetAbuf(&fb->abuf); memset(fb->nb, 0, Dx(fb->r)*Dy(fb->r)*4); memsetf(fb->zb, Inf(-1), Dx(fb->r)*Dy(fb->r)); memset(fb->cb, 0, Dx(fb->r)*Dy(fb->r)*4); diff --git a/graphics.h b/graphics.h index 4aa18f1..c9a7f67 100644 --- a/graphics.h +++ b/graphics.h @@ -54,6 +54,9 @@ typedef struct Shadertab Shadertab; typedef struct Renderer Renderer; typedef struct Rendertime Rendertime; typedef struct Renderjob Renderjob; +typedef struct Fragment Fragment; +typedef struct Astk Astk; +typedef struct Abuf Abuf; typedef struct Framebuf Framebuf; typedef struct Framebufctl Framebufctl; typedef struct Viewport Viewport; @@ -246,11 +249,34 @@ struct Renderjob Renderjob *next; }; +struct Fragment +{ + Color c; + float z; +}; + +struct Astk +{ + Point p; + Fragment *items; + ulong size; + int active; +}; + +struct Abuf +{ + QLock; + Astk *stk; /* framebuffer fragment stacks */ + Astk **act; /* active fragment stacks */ + ulong nact; +}; + struct Framebuf { ulong *cb; /* color buffer */ float *zb; /* z/depth buffer */ ulong *nb; /* normals buffer (DBG only) */ + Abuf abuf; /* A-buffer */ Rectangle r; }; @@ -300,6 +326,9 @@ struct Camera Matrix3 proj; /* VCS to clip space xform */ Projection projtype; int cullmode; + int enableblend; + int enabledepth; + int enableAbuff; struct { uvlong min, avg, max, acc, n, v; diff --git a/render.c b/render.c index 41b0939..764dbca 100644 --- a/render.c +++ b/render.c @@ -35,12 +35,14 @@ ul2col(ulong l) } static void -pixel(Framebuf *fb, Point p, Color c) +pixel(Framebuf *fb, Point p, Color c, int blend) { Color dc; - dc = srgb2linear(ul2col(getpixel(fb, p))); - c = lerp3(dc, c, c.a); /* SoverD */ + if(blend){ + dc = srgb2linear(ul2col(getpixel(fb, p))); + c = lerp3(dc, c, c.a); /* SoverD */ + } putpixel(fb, p, col2ul(linear2srgb(c))); } @@ -75,6 +77,57 @@ isfacingback(Primitive *p) return sa <= 0; } +static void +pushtoAbuf(Framebuf *fb, Point p, Color c, float z) +{ + Abuf *buf; + Astk *stk; + int i; + + buf = &fb->abuf; + stk = &buf->stk[p.y*Dx(fb->r) + p.x]; + stk->items = erealloc(stk->items, ++stk->size*sizeof(*stk->items)); + +//fprint(2, "stk %#p items %#p size %lud (%d bytes)\n", stk, stk->items, stk->size, sizeof(*stk)); + + for(i = 0; i < stk->size; i++) + if(z < stk->items[i].z) + break; + + if(i < stk->size){ + memmove(&stk->items[i+1], &stk->items[i], (stk->size-1 - i)*sizeof(*stk->items)); + stk->items[i] = (Fragment){c, z}; + }else + stk->items[stk->size-1] = (Fragment){c, z}; + + if(!stk->active){ + stk->active++; + stk->p = p; + qlock(buf); + buf->act = erealloc(buf->act, ++buf->nact*sizeof(*buf->act)); + buf->act[buf->nact-1] = stk; + qunlock(buf); +//fprint(2, "act %#p nact %lud (%d bytes)\n", buf->act, buf->nact, sizeof(*buf->act)); + } +} + +static void +squashAbuf(Framebuf *fb, int blend) +{ + Abuf *buf; + Astk *stk; + int i; + + buf = &fb->abuf; + for(i = 0; i < buf->nact; i++){ + stk = buf->act[i]; + while(stk->size--) + pixel(fb, stk->p, stk->items[stk->size].c, blend); + /* write to the depth buffer as well */ +// fb->zb[stk->p.x + stk->p.y*Dx(fb->r)] = stk->items[stk->size].z; + } +} + static Point3 _barycoords(Triangle2 t, Point2 p) { @@ -115,14 +168,19 @@ rasterize(Rastertask *task) p = Pt(prim.v[0].p.x, prim.v[0].p.y); z = fclamp(prim.v[0].p.z, 0, 1); - if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) - break; - params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + if(params->camera->enabledepth){ + if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + break; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + } fsp.v = dupvertex(&prim.v[0]); fsp.p = p; c = params->fshader(&fsp); - pixel(params->fb, p, c); + if(params->camera->enableAbuff) + pushtoAbuf(params->fb, p, c, z); + else + pixel(params->fb, p, c, params->camera->enableblend); delvattrs(&fsp.v); break; case PLine: @@ -159,9 +217,11 @@ rasterize(Rastertask *task) z = flerp(prim.v[0].p.z, prim.v[1].p.z, perc); /* TODO get rid of the bounds check and make sure the clipping doesn't overflow */ - if(!ptinrect(p, params->fb->r) || z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) - goto discard; - params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + if(params->camera->enabledepth){ + if(!ptinrect(p, params->fb->r) || z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + goto discard; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + } /* interpolate z⁻¹ and get actual z */ z = flerp(prim.v[0].p.w, prim.v[1].p.w, perc); @@ -173,7 +233,10 @@ rasterize(Rastertask *task) fsp.p = p; c = params->fshader(&fsp); - pixel(params->fb, p, c); + if(params->camera->enableAbuff) + pushtoAbuf(params->fb, p, c, z); + else + pixel(params->fb, p, c, params->camera->enableblend); delvattrs(&fsp.v); discard: if(steep) SWAP(int, &p.x, &p.y); @@ -206,9 +269,11 @@ discard: continue; z = fberp(prim.v[0].p.z, prim.v[1].p.z, prim.v[2].p.z, bc); - if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) - continue; - params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + if(params->camera->enabledepth){ + if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + continue; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + } /* interpolate z⁻¹ and get actual z */ z = fberp(prim.v[0].p.w, prim.v[1].p.w, prim.v[2].p.w, bc); @@ -220,7 +285,10 @@ discard: fsp.p = p; c = params->fshader(&fsp); - pixel(params->fb, p, c); + if(params->camera->enableAbuff) + pushtoAbuf(params->fb, p, c, z); + else + pixel(params->fb, p, c, params->camera->enableblend); pixeln(params->fb, p, fsp.v.n); delvattrs(&fsp.v); } @@ -249,6 +317,8 @@ rasterizer(void *arg) /* end of job */ if(params->entity == nil){ if(decref(params->job) < 1){ + if(params->job->camera->enableAbuff) + squashAbuf(params->job->fb, params->job->camera->enableblend); nbsend(params->job->donec, nil); free(params); } @@ -571,6 +641,12 @@ renderer(void *arg) continue; } + /* initialize the A-buffer */ + if(job->camera->enableAbuff){ + job->fb->abuf.stk = emalloc(Dx(job->fb->r)*Dy(job->fb->r)*sizeof(Astk)); + memset(job->fb->abuf.stk, 0, Dx(job->fb->r)*Dy(job->fb->r)*sizeof(Astk)); + } + for(ent = sc->ents.next; ent != &sc->ents; ent = ent->next){ params = emalloc(sizeof *params); memset(params, 0, sizeof *params); -- cgit v1.2.3