From 8674cb151144982ca5146268bad8a6b226fd8b62 Mon Sep 17 00:00:00 2001 From: rodri Date: Fri, 23 Aug 2024 15:04:21 +0000 Subject: correct the gouraud and phong shaders. add a blinn shader. --- med.c | 88 +++++++++++++++++++++-------------------- readme | 3 +- vis.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 161 insertions(+), 68 deletions(-) diff --git a/med.c b/med.c index 25dccec..8ecb72b 100644 --- a/med.c +++ b/med.c @@ -136,31 +136,27 @@ materializefrustum(void) l.v[0].p = world2model(subject, viewport2world(cam, p[i])); l.v[1].p = world2model(subject, viewport2world(cam, p[(i+1)%nelem(p)])); qlock(&scenelk); - model->prims = erealloc(model->prims, ++model->nprims*sizeof(*model->prims)); - model->prims[model->nprims-1] = l; + model->addprim(model, l); qunlock(&scenelk); /* middle frame */ l.v[0].p = world2model(subject, viewport2world(cam, subpt3(p[i], Vec3(0,0,0.5)))); l.v[1].p = world2model(subject, viewport2world(cam, subpt3(p[(i+1)%nelem(p)], Vec3(0,0,0.5)))); qlock(&scenelk); - model->prims = erealloc(model->prims, ++model->nprims*sizeof(*model->prims)); - model->prims[model->nprims-1] = l; + model->addprim(model, l); qunlock(&scenelk); /* back frame */ l.v[0].p = world2model(subject, viewport2world(cam, subpt3(p[i], Vec3(0,0,1)))); l.v[1].p = world2model(subject, viewport2world(cam, subpt3(p[(i+1)%nelem(p)], Vec3(0,0,1)))); qlock(&scenelk); - model->prims = erealloc(model->prims, ++model->nprims*sizeof(*model->prims)); - model->prims[model->nprims-1] = l; + model->addprim(model, l); qunlock(&scenelk); /* struts */ l.v[1].p = world2model(subject, viewport2world(cam, p[i])); qlock(&scenelk); - model->prims = erealloc(model->prims, ++model->nprims*sizeof(*model->prims)); - model->prims[model->nprims-1] = l; + model->addprim(model, l); qunlock(&scenelk); } } @@ -186,10 +182,12 @@ addcube(void) t[0].v[1].n = addpt3(p, v1); t[0].v[2].p = addpt3(center, addpt3(p, addpt3(v1, v2))); t[0].v[2].n = addpt3(p, addpt3(v1, v2)); + t[0].v[0].c = t[0].v[1].c = t[0].v[2].c = Pt3(1,1,1,1); t[1].v[0] = t[0].v[0]; t[1].v[1] = t[0].v[2]; t[1].v[2].p = addpt3(center, addpt3(p, v2)); t[1].v[2].n = addpt3(p, v2); + t[1].v[2].c = Pt3(1,1,1,1); /* make a cube by rotating the reference face */ for(i = 0; i < 6; i++){ @@ -201,9 +199,8 @@ addcube(void) } qlock(&scenelk); - model->prims = erealloc(model->prims, (model->nprims += 2)*sizeof(*model->prims)); - model->prims[model->nprims-2] = t[0]; - model->prims[model->nprims-1] = t[1]; + model->addprim(model, t[0]); + model->addprim(model, t[1]); qunlock(&scenelk); } } @@ -230,8 +227,9 @@ addbasis(void) prims[2].v[1].p = addpt3(center, e->bz); prims[2].v[1].c = Pt3(0,0,1,1); - m->prims = erealloc(m->prims, (m->nprims += 3)*sizeof(*m->prims)); - memmove(m->prims, prims, sizeof prims); + m->addprim(m, prims[0]); + m->addprim(m, prims[1]); + m->addprim(m, prims[2]); scene->addent(scene, e); } @@ -244,41 +242,47 @@ gouraudvshader(VSparams *sp) double Kd; /* diffuse factor */ double spec; Point3 pos, lightdir, lookdir; - Material *m; + Material m; Color ambient, diffuse, specular, lightc; sp->v->n = model2world(sp->su->entity, sp->v->n); sp->v->p = model2world(sp->su->entity, sp->v->p); pos = sp->v->p; - m = sp->v->mtl; + + if(sp->v->mtl != nil) + m = *sp->v->mtl; + else{ + memset(&m, 0, sizeof m); + m.diffuse = sp->v->c; + m.specular = Pt3(1,1,1,1); + m.shininess = 1; + } lightdir = normvec3(subpt3(light.p, pos)); lightc = getlightcolor(&light, lightdir); ambient = mulpt3(lightc, Ka); - if(m != nil) - ambient = modulapt3(ambient, m->ambient); + ambient = modulapt3(ambient, m.diffuse); Kd = fmax(0, dotvec3(sp->v->n, lightdir)); diffuse = mulpt3(lightc, Kd); - if(m != nil) - diffuse = modulapt3(diffuse, m->diffuse); + diffuse = modulapt3(diffuse, m.diffuse); lookdir = normvec3(subpt3(sp->su->camera->p, pos)); lightdir = qrotate(lightdir, sp->v->n, PI); - spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m? m->shininess: 1); + spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m.shininess); specular = mulpt3(lightc, spec*Ks); - if(m != nil) - specular = modulapt3(specular, m->specular); + specular = modulapt3(specular, m.specular); sp->v->c = addpt3(ambient, addpt3(diffuse, specular)); + sp->v->c.a = m.diffuse.a; return world2clip(sp->su->camera, pos); } Color gouraudshader(FSparams *sp) { - Color tc, c; + Color tc; if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0) tc = sampletexture(sp->su->entity->mdl->tex, sp->v.uv, tsampler); @@ -287,10 +291,7 @@ gouraudshader(FSparams *sp) else tc = Pt3(1,1,1,1); - c = modulapt3(sp->v.c, tc); - c.a = 1; - - return c; + return modulapt3(sp->v.c, tc); } Point3 @@ -304,6 +305,10 @@ phongvshader(VSparams *sp) sp->v->p = model2world(sp->su->entity, sp->v->p); pos = sp->v->p; addvattr(sp->v, "pos", VAPoint, &pos); + if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){ + sp->v->tangent = model2world(sp->su->entity, sp->v->tangent); + addvattr(sp->v, "tangent", VAPoint, &sp->v->tangent); + } if(sp->v->mtl != nil){ a = sp->v->mtl->ambient; d = sp->v->mtl->diffuse; @@ -324,7 +329,7 @@ phongshader(FSparams *sp) static double Ks = 0.5; /* specular factor */ double Kd; /* diffuse factor */ double spec; - Color ambient, diffuse, specular, tc, c, lightc; + Color ambient, diffuse, specular, lightc, c; Point3 pos, n, lightdir, lookdir; Material m; RFrame3 TBN; @@ -336,7 +341,7 @@ phongshader(FSparams *sp) va = getvattr(&sp->v, "ambient"); m.ambient = va != nil? va->p: Pt3(1,1,1,1); va = getvattr(&sp->v, "diffuse"); - m.diffuse = va != nil? va->p: Pt3(1,1,1,1); + m.diffuse = va != nil? va->p: sp->v.c; va = getvattr(&sp->v, "specular"); m.specular = va != nil? va->p: Pt3(1,1,1,1); va = getvattr(&sp->v, "shininess"); @@ -345,9 +350,6 @@ phongshader(FSparams *sp) lightdir = normvec3(subpt3(light.p, pos)); lightc = getlightcolor(&light, lightdir); - ambient = mulpt3(lightc, Ka); - ambient = modulapt3(ambient, m.ambient); - /* normal mapping */ va = getvattr(&sp->v, "tangent"); if(va == nil) @@ -366,27 +368,29 @@ phongshader(FSparams *sp) sp->v.n = n; } + if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0) + m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v.uv, tsampler); + else if(sp->v.mtl != nil && sp->v.mtl->diffusemap != nil && sp->v.uv.w != 0) + m.diffuse = sampletexture(sp->v.mtl->diffusemap, sp->v.uv, tsampler); + + ambient = mulpt3(lightc, Ka); + ambient = modulapt3(ambient, m.diffuse); + Kd = fmax(0, dotvec3(n, lightdir)); diffuse = mulpt3(lightc, Kd); diffuse = modulapt3(diffuse, m.diffuse); + if(sp->v.mtl != nil && sp->v.mtl->specularmap != nil && sp->v.uv.w != 0) + m.specular = sampletexture(sp->v.mtl->specularmap, sp->v.uv, tsampler); + lookdir = normvec3(subpt3(sp->su->camera->p, pos)); lightdir = qrotate(lightdir, n, PI); spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m.shininess); specular = mulpt3(lightc, spec*Ks); specular = modulapt3(specular, m.specular); - if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0) - tc = sampletexture(sp->su->entity->mdl->tex, sp->v.uv, tsampler); - else if(sp->v.mtl != nil && sp->v.mtl->diffusemap != nil && sp->v.uv.w != 0) - tc = sampletexture(sp->v.mtl->diffusemap, sp->v.uv, tsampler); - else - tc = Pt3(1,1,1,1); - c = addpt3(ambient, addpt3(diffuse, specular)); - c = modulapt3(c, tc); - c.a = 1; - + c.a = m.diffuse.a; return c; } diff --git a/readme b/readme index d304939..59b7e8f 100644 --- a/readme +++ b/readme @@ -21,8 +21,7 @@ USAGE The s option will switch the skybox on (performance will drop considerably). - The t flag takes as input an image(6) file used to texture the first model - (if it happens to have no materials). + The t flag takes as input an image(6) file used to texture the first model. The g flag takes as input the dimensions of the camera viewport. If it's smaller than screen the image will be upscaled to fit it as much as possible, otherwise it will default to the screen dimensions. diff --git a/vis.c b/vis.c index c9d674e..afc8354 100644 --- a/vis.c +++ b/vis.c @@ -129,34 +129,40 @@ gouraudvshader(VSparams *sp) double Kd; /* diffuse factor */ double spec; Point3 pos, lightdir, lookdir; - Material *m; + Material m; Color ambient, diffuse, specular, lightc; sp->v->n = model2world(sp->su->entity, sp->v->n); sp->v->p = model2world(sp->su->entity, sp->v->p); pos = sp->v->p; - m = sp->v->mtl; + + if(sp->v->mtl != nil) + m = *sp->v->mtl; + else{ + memset(&m, 0, sizeof m); + m.diffuse = sp->v->c; + m.specular = Pt3(1,1,1,1); + m.shininess = 1; + } lightdir = normvec3(subpt3(light.p, pos)); lightc = getlightcolor(&light, lightdir); ambient = mulpt3(lightc, Ka); - if(m != nil) - ambient = modulapt3(ambient, m->ambient); + ambient = modulapt3(ambient, m.diffuse); Kd = fmax(0, dotvec3(sp->v->n, lightdir)); diffuse = mulpt3(lightc, Kd); - if(m != nil) - diffuse = modulapt3(diffuse, m->diffuse); + diffuse = modulapt3(diffuse, m.diffuse); lookdir = normvec3(subpt3(sp->su->camera->p, pos)); lightdir = qrotate(lightdir, sp->v->n, PI); - spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m? m->shininess: 1); + spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m.shininess); specular = mulpt3(lightc, spec*Ks); - if(m != nil) - specular = modulapt3(specular, m->specular); + specular = modulapt3(specular, m.specular); sp->v->c = addpt3(ambient, addpt3(diffuse, specular)); + sp->v->c.a = m.diffuse.a; return world2clip(sp->su->camera, pos); } @@ -210,7 +216,7 @@ phongshader(FSparams *sp) static double Ks = 0.5; /* specular factor */ double Kd; /* diffuse factor */ double spec; - Color ambient, diffuse, specular, tc, c, lightc; + Color ambient, diffuse, specular, lightc, c; Point3 pos, n, lightdir, lookdir; Material m; RFrame3 TBN; @@ -222,7 +228,7 @@ phongshader(FSparams *sp) va = getvattr(&sp->v, "ambient"); m.ambient = va != nil? va->p: Pt3(1,1,1,1); va = getvattr(&sp->v, "diffuse"); - m.diffuse = va != nil? va->p: Pt3(1,1,1,1); + m.diffuse = va != nil? va->p: sp->v.c; va = getvattr(&sp->v, "specular"); m.specular = va != nil? va->p: Pt3(1,1,1,1); va = getvattr(&sp->v, "shininess"); @@ -231,9 +237,6 @@ phongshader(FSparams *sp) lightdir = normvec3(subpt3(light.p, pos)); lightc = getlightcolor(&light, lightdir); - ambient = mulpt3(lightc, Ka); - ambient = modulapt3(ambient, m.ambient); - /* normal mapping */ va = getvattr(&sp->v, "tangent"); if(va == nil) @@ -252,26 +255,101 @@ phongshader(FSparams *sp) sp->v.n = n; } + if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0) + m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v.uv, tsampler); + else if(sp->v.mtl != nil && sp->v.mtl->diffusemap != nil && sp->v.uv.w != 0) + m.diffuse = sampletexture(sp->v.mtl->diffusemap, sp->v.uv, tsampler); + + ambient = mulpt3(lightc, Ka); + ambient = modulapt3(ambient, m.diffuse); + Kd = fmax(0, dotvec3(n, lightdir)); diffuse = mulpt3(lightc, Kd); diffuse = modulapt3(diffuse, m.diffuse); + if(sp->v.mtl != nil && sp->v.mtl->specularmap != nil && sp->v.uv.w != 0) + m.specular = sampletexture(sp->v.mtl->specularmap, sp->v.uv, tsampler); + lookdir = normvec3(subpt3(sp->su->camera->p, pos)); lightdir = qrotate(lightdir, n, PI); spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m.shininess); specular = mulpt3(lightc, spec*Ks); specular = modulapt3(specular, m.specular); + c = addpt3(ambient, addpt3(diffuse, specular)); + c.a = m.diffuse.a; + return c; +} + +Color +blinnshader(FSparams *sp) +{ + static double Ka = 0.1; /* ambient factor */ + static double Ks = 0.5; /* specular factor */ + double Kd; /* diffuse factor */ + double spec; + Color ambient, diffuse, specular, lightc, c; + Point3 pos, n, lightdir, lookdir; + Material m; + RFrame3 TBN; + Vertexattr *va; + + va = getvattr(&sp->v, "pos"); + pos = va->p; + + va = getvattr(&sp->v, "ambient"); + m.ambient = va != nil? va->p: Pt3(1,1,1,1); + va = getvattr(&sp->v, "diffuse"); + m.diffuse = va != nil? va->p: sp->v.c; + va = getvattr(&sp->v, "specular"); + m.specular = va != nil? va->p: Pt3(1,1,1,1); + va = getvattr(&sp->v, "shininess"); + m.shininess = va != nil? va->n: 1; + + lightdir = normvec3(subpt3(light.p, pos)); + lightc = getlightcolor(&light, lightdir); + + /* normal mapping */ + va = getvattr(&sp->v, "tangent"); + if(va == nil) + n = sp->v.n; + else{ + /* TODO implement this on the VS instead and apply Gram-Schmidt here */ + n = sampletexture(sp->v.mtl->normalmap, sp->v.uv, neartexsampler); + n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1))); + + TBN.p = Pt3(0,0,0,1); + TBN.bx = va->p; /* T */ + TBN.bz = sp->v.n; /* N */ + TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */ + + n = normvec3(invrframexform3(n, TBN)); + sp->v.n = n; + } + if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0) - tc = sampletexture(sp->su->entity->mdl->tex, sp->v.uv, tsampler); + m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v.uv, tsampler); else if(sp->v.mtl != nil && sp->v.mtl->diffusemap != nil && sp->v.uv.w != 0) - tc = sampletexture(sp->v.mtl->diffusemap, sp->v.uv, tsampler); - else - tc = Pt3(1,1,1,1); + m.diffuse = sampletexture(sp->v.mtl->diffusemap, sp->v.uv, tsampler); - c = addpt3(ambient, addpt3(diffuse, specular)); - c = modulapt3(c, tc); + ambient = mulpt3(lightc, Ka); + ambient = modulapt3(ambient, m.diffuse); + Kd = fmax(0, dotvec3(n, lightdir)); + diffuse = mulpt3(lightc, Kd); + diffuse = modulapt3(diffuse, m.diffuse); + + if(sp->v.mtl != nil && sp->v.mtl->specularmap != nil && sp->v.uv.w != 0) + m.specular = sampletexture(sp->v.mtl->specularmap, sp->v.uv, tsampler); + + lookdir = normvec3(subpt3(sp->su->camera->p, pos)); + lightdir = normvec3(addpt3(lookdir, lightdir)); /* half vector */ + spec = pow(fmax(0, dotvec3(n, lightdir)), m.shininess); + specular = mulpt3(lightc, spec*Ks); + specular = modulapt3(specular, m.specular); + + c = addpt3(ambient, addpt3(diffuse, specular)); + c.a = m.diffuse.a; return c; } @@ -436,6 +514,7 @@ Shadertab shadertab[] = { { "ident", identvshader, identshader }, { "gouraud", gouraudvshader, gouraudshader }, { "phong", phongvshader, phongshader }, + { "blinn", phongvshader, blinnshader }, }; Shadertab * getshader(char *name) @@ -596,6 +675,9 @@ lmb(void) Point p; Color c, n; double z; +// Abuf *abuf; +// Astk *astk; +// int i; p = subpt(mctl->xy, screen->r.min); p₂ = Pt2(p.x, p.y, 1); @@ -608,6 +690,15 @@ lmb(void) c = ul2col(fb->cb[p.y*Dx(fb->r) + p.x]); n = ul2col(fb->nb[p.y*Dx(fb->r) + p.x]); z = fb->zb[p.y*Dx(fb->r) + p.x]; +// abuf = &fb->abuf; +// if(abuf->stk != nil){ +// astk = &abuf->stk[p.y*Dx(fb->r) + p.x]; +// if(astk->active){ +// fprint(2, "p %P nfrags %lud\n", p, astk->size); +// for(i = 0; i < astk->size; i++) +// fprint(2, "\t%d: %V %g\n", i, astk->items[i].c, astk->items[i].z); +// } +// } qunlock(maincam->view->fbctl); snprint(stats[Spixcol], sizeof(stats[Spixcol]), "c %V z %g", c, z); snprint(stats[Snorcol], sizeof(stats[Snorcol]), "n %V", n); @@ -903,9 +994,8 @@ mkblendtestscene(void) } mdl = newmodel(); - mdl->prims = erealloc(mdl->prims, (mdl->nprims += 2)*sizeof(*mdl->prims)); - mdl->prims[mdl->nprims-2] = t[0]; - mdl->prims[mdl->nprims-1] = t[1]; + mdl->addprim(mdl, t[0]); + mdl->addprim(mdl, t[1]); ent = newentity(nil, mdl); scene->addent(scene, ent); } @@ -996,7 +1086,7 @@ threadmain(int argc, char *argv[]) mdlpath = argv[argc]; model = readobjmodel(mdlpath); subject = newentity(mdlpath, model); -// subject->p.x = argc*4; +// subject->p.z = -argc*4; scene->addent(scene, subject); if(argc == 0 && texpath != nil){ -- cgit v1.2.3