shithub: 3dee

Download patch

ref: 8674cb151144982ca5146268bad8a6b226fd8b62
parent: 1d61030857e868dee98386e5b07ec98416322d7f
author: rodri <rgl@antares-labs.eu>
date: Fri Aug 23 11:04:21 EDT 2024

correct the gouraud and phong shaders. add a blinn shader.

--- a/med.c
+++ b/med.c
@@ -136,8 +136,7 @@
 		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 */
@@ -144,8 +143,7 @@
 		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 */
@@ -152,15 +150,13 @@
 		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 @@
 	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 @@
 				}
 
 		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 @@
 	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,34 +242,40 @@
 	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);
 }
  
@@ -278,7 +282,7 @@
 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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,10 +368,21 @@
 		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);
@@ -376,17 +389,8 @@
 	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;
 }
 
--- a/readme
+++ b/readme
@@ -21,8 +21,7 @@
 
 	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.
--- a/vis.c
+++ b/vis.c
@@ -129,34 +129,40 @@
 	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 @@
 	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 @@
 	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 @@
 	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,10 +255,21 @@
 		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);
@@ -262,16 +276,80 @@
 	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 @@
 	{ "ident", identvshader, identshader },
 	{ "gouraud", gouraudvshader, gouraudshader },
 	{ "phong", phongvshader, phongshader },
+	{ "blinn", phongvshader, blinnshader },
 };
 Shadertab *
 getshader(char *name)
@@ -596,6 +675,9 @@
 		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 @@
 		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 @@
 			}
 
 		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 @@
 		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){