summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2024-08-23 15:04:21 +0000
committerrodri <rgl@antares-labs.eu>2024-08-23 15:04:21 +0000
commit8674cb151144982ca5146268bad8a6b226fd8b62 (patch)
treefc3b2ff5c76e60990e5a9ea9d00f3232d77b9c26
parent1d61030857e868dee98386e5b07ec98416322d7f (diff)
download3dee-8674cb151144982ca5146268bad8a6b226fd8b62.tar.gz
3dee-8674cb151144982ca5146268bad8a6b226fd8b62.tar.bz2
3dee-8674cb151144982ca5146268bad8a6b226fd8b62.zip
correct the gouraud and phong shaders. add a blinn shader.
-rw-r--r--med.c88
-rw-r--r--readme3
-rw-r--r--vis.c138
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){