ref: ca7f3196863e0012ec244f7e0354005275e69726
parent: b01c3136f69f5375e3317412375831fa4a6fb991
author: rodri <rgl@antares-labs.eu>
date: Tue Jun 4 14:15:33 EDT 2024
vis: same as previous commit, and add normal mapping to the phong shader. implemented tangent space normal mapping and now diablo3 looks sick!
--- a/vis.c
+++ b/vis.c
@@ -48,7 +48,6 @@
int kdown;
Shadertab *shader;
Model *model;
-Entity *subject;
Scene *scene;
QLock drawlk;
Mouse om;
@@ -119,9 +118,9 @@
Material *m;
Color ambient, diffuse, specular;
- sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
- sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
- pos = model2world(sp->su->entity, sp->v->p);
+ 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;
ambient = mulpt3(light.c, Ka);
@@ -184,10 +183,14 @@
Color a, d, s;
double ss;
- sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
- sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
- pos = model2world(sp->su->entity, sp->v->p);
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ 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;
@@ -209,8 +212,9 @@
double Kd; /* diffuse factor */
double spec;
Color ambient, diffuse, specular, tc, c;
- Point3 pos, lookdir, lightdir;
+ Point3 pos, n, lightdir, lookdir;
Material m;
+ RFrame3 TBN;
Vertexattr *va;
va = getvattr(&sp->v, "pos");
@@ -231,8 +235,25 @@
ambient.b *= m.ambient.b;
ambient.a *= m.ambient.a;
+ /* 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 = texture(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));
+ }
+
lightdir = normvec3(subpt3(light.p, pos));
- Kd = fmax(0, dotvec3(sp->v.n, lightdir));
+ Kd = fmax(0, dotvec3(n, lightdir));
diffuse = mulpt3(light.c, Kd);
diffuse.r *= m.diffuse.r;
diffuse.g *= m.diffuse.g;
@@ -240,7 +261,7 @@
diffuse.a *= m.diffuse.a;
lookdir = normvec3(subpt3(maincam->p, pos));
- lightdir = qrotate(lightdir, sp->v.n, PI);
+ lightdir = qrotate(lightdir, n, PI);
spec = pow(fmax(0, dotvec3(lookdir, lightdir)), m.shininess);
specular = mulpt3(light.c, spec*Ks);
specular.r *= m.specular.r;
@@ -270,9 +291,9 @@
Point3 pos, lightdir;
double intens;
- sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
- sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
- pos = model2world(sp->su->entity, sp->v->p);
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ pos = sp->v->p;
lightdir = normvec3(subpt3(light.p, pos));
intens = fmax(0, dotvec3(sp->v->n, lightdir));
addvattr(sp->v, "intensity", VANumber, &intens);
@@ -317,9 +338,9 @@
Point3
ivshader(VSparams *sp)
{
- sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient)));
- sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w);
- return world2clip(maincam, model2world(sp->su->entity, sp->v->p));
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ return world2clip(maincam, sp->v->p);
}
Color
@@ -537,8 +558,20 @@
void
lmb(void)
{
- if((om.buttons^mctl->buttons) == 0)
+ Entity *e;
+ Quaternion Δorient;
+
+ if((om.buttons^mctl->buttons) == 0){
+ Δorient = orient;
qball(screen->r, om.xy, mctl->xy, &orient, nil);
+ Δorient = mulq(orient, invq(Δorient));
+
+ for(e = scene->ents.next; e != &scene->ents; e = e->next){
+ e->bx = Vecquat(mulq(mulq(Δorient, Quatvec(0, e->bx)), invq(Δorient)));
+ e->by = Vecquat(mulq(mulq(Δorient, Quatvec(0, e->by)), invq(Δorient)));
+ e->bz = Vecquat(mulq(mulq(Δorient, Quatvec(0, e->bz)), invq(Δorient)));
+ }
+ }
}
void
@@ -763,7 +796,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [-t texture] [-n normals] [-s shader] model...\n", argv0);
+ fprint(2, "usage: %s [-t texture] [-s shader] model...\n", argv0);
exits("usage");
}
@@ -773,17 +806,16 @@
Viewport *v;
Renderer *rctl;
Channel *keyc;
+ Entity *subject;
OBJ *obj;
- char *texpath, *norpath, *sname, *mdlpath;
+ char *texpath, *sname, *mdlpath;
int i, fd;
GEOMfmtinstall();
texpath = nil;
- norpath = nil;
sname = "gouraud";
ARGBEGIN{
case 't': texpath = EARGF(usage()); break;
- case 'n': norpath = EARGF(usage()); break;
case 's': sname = EARGF(usage()); break;
case L'ι': inception++; break;
case 'p': doprof++; break;
@@ -815,14 +847,6 @@
if(fd < 0)
sysfatal("open: %r");
if((model->tex = readmemimage(fd)) == nil)
- sysfatal("readmemimage: %r");
- close(fd);
- }
- if(argc == 0 && norpath != nil){
- fd = open(norpath, OREAD);
- if(fd < 0)
- sysfatal("open: %r");
- if((model->nor = readmemimage(fd)) == nil)
sysfatal("readmemimage: %r");
close(fd);
}