shithub: 3dee

Download patch

ref: 520550a84683772707aa639497c3a79ba385d65e
parent: 951412ce94bc89bbd781fda16dc5a9cf3cc09d28
author: rodri <rgl@antares-labs.eu>
date: Sun Feb 25 15:18:22 EST 2024

implement a phong shader. add a shader selection menu. update the light source.

--- a/main.c
+++ b/main.c
@@ -72,7 +72,8 @@
 	80*DEG, 0.01, 100, PERSPECTIVE
 };
 Point3 center = {0,0,0,1};
-Point3 light = {0,1,1,1};	/* global point light */
+LightSource light;		/* global point light */
+Point3 lightdir;
 
 static int doprof;
 static int inception;
@@ -110,7 +111,7 @@
 vertshader(VSparams *sp)
 {
 	sp->v->n = qrotate(sp->v->n, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
-	sp->v->intensity = fmax(0, dotvec3(sp->v->n, light));
+	sp->v->intensity = fmax(0, dotvec3(sp->v->n, lightdir));
 	sp->v->p = qrotate(sp->v->p, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
 	return world2clip(maincam, model2world(sp->su->entity, sp->v->p));
 }
@@ -118,12 +119,47 @@
 Memimage *
 gouraudshader(FSparams *sp)
 {
-	double intens;
+	sp->cbuf[1] *= sp->su->var_intensity;
+	sp->cbuf[2] *= sp->su->var_intensity;
+	sp->cbuf[3] *= sp->su->var_intensity;
+	memfillcolor(sp->frag, *(ulong*)sp->cbuf);
 
-	intens = dotvec3(Vec3(sp->su->var_intensity[0], sp->su->var_intensity[1], sp->su->var_intensity[2]), sp->bc);
-	sp->cbuf[1] *= intens;
-	sp->cbuf[2] *= intens;
-	sp->cbuf[3] *= intens;
+	return sp->frag;
+}
+
+Point3
+phongvshader(VSparams *sp)
+{
+	sp->v->n = qrotate(sp->v->n, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
+	sp->v->p = qrotate(sp->v->p, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI));
+	sp->v->pos = model2world(sp->su->entity, sp->v->p);
+	return world2clip(maincam, model2world(sp->su->entity, sp->v->p));
+}
+
+Memimage *
+phongshader(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;
+	Point3 lookdir, lightdir₂;
+
+	ambient = mulpt3(light.c, Ka);
+
+	lightdir₂ = normvec3(subpt3(light.p, sp->su->var_pos));
+	Kd = fmax(0, dotvec3(sp->su->var_normal, lightdir₂));
+	diffuse = mulpt3(light.c, Kd);
+
+	lookdir = normvec3(subpt3(maincam->p, sp->su->var_pos));
+	lightdir₂ = qrotate(lightdir₂, sp->su->var_normal, PI);
+	spec = pow(fmax(0, dotvec3(lookdir, lightdir₂)), 64);
+	specular = mulpt3(light.c, spec*Ks);
+
+	sp->cbuf[1] *= fclamp(ambient.b + diffuse.b + specular.b, 0, 1);
+	sp->cbuf[2] *= fclamp(ambient.g + diffuse.g + specular.g, 0, 1);
+	sp->cbuf[3] *= fclamp(ambient.r + diffuse.r + specular.r, 0, 1);
 	memfillcolor(sp->frag, *(ulong*)sp->cbuf);
 
 	return sp->frag;
@@ -134,7 +170,7 @@
 {
 	double intens;
 
-	intens = dotvec3(Vec3(sp->su->var_intensity[0], sp->su->var_intensity[1], sp->su->var_intensity[2]), sp->bc);
+	intens = sp->su->var_intensity;
 	intens = intens > 0.85? 1: intens > 0.60? 0.80: intens > 0.45? 0.60: intens > 0.30? 0.45: intens > 0.15? 0.30: 0;
 	sp->cbuf[1] = 0;
 	sp->cbuf[2] = 155*intens;
@@ -262,7 +298,7 @@
 Point3
 ivshader(VSparams *sp)
 {
-	return world2clip(maincam, sp->v->p);
+	return world2clip(maincam, model2world(sp->su->entity, sp->v->p));
 }
 
 Memimage *
@@ -277,6 +313,7 @@
 	{ "circle", ivshader, circleshader },
 	{ "box", ivshader, boxshader },
 	{ "sf", ivshader, sfshader },
+	{ "phong", phongvshader, phongshader },
 	{ "gouraud", vertshader, gouraudshader },
 	{ "toon", vertshader, toonshader },
 	{ "ident", vertshader, identshader },
@@ -354,13 +391,37 @@
 				if((model->tex = readmemimage(fd)) == nil)
 					sysfatal("readmemimage: %r");
 			}
+			light.p = qrotate(light.p, Vec3(0,1,0), θ+fmod(ω*Δt/1e9, 2*PI));
 		}
 	}
 }
 
+static char *
+genrmbmenuitem(int idx)
+{
+	if(idx < nelem(shadertab))
+		return shadertab[idx].name;
+	return nil;
+}
+
 void
+rmb(void)
+{
+	static Menu menu = { .gen = genrmbmenuitem };
+	int idx;
+
+	idx = menuhit(3, mctl, &menu, _screen);
+	if(idx < 0)
+		return;
+	shader = &shadertab[idx];
+	nbsendp(drawc, nil);
+}
+
+void
 mouse(void)
 {
+	if((mctl->buttons & 4) != 0)
+		rmb();
 	if((mctl->buttons & 8) != 0){
 		maincam->fov = fclamp(maincam->fov - 1*DEG, 1*DEG, 359*DEG);
 		reloadcamera(maincam);
@@ -504,7 +565,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-t texture] [-s shader] [-ω yrot] model...\n", argv0);
+	fprint(2, "usage: %s [-t texture] [-n normals] [-s shader] [-ω yrot] model...\n", argv0);
 	exits("usage");
 }
 
@@ -513,17 +574,19 @@
 {
 	Viewport *v;
 	Channel *keyc;
-	char *mdlpath, *texpath, *sname;
+	char *texpath, *norpath, *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'ω': ω = strtod(EARGF(usage()), nil)*DEG; break;
-	case L'σ': inception++; break;
+	case L'ι': inception++; break;
 	case 'p': doprof++; break;
 	default: usage();
 	}ARGEND;
@@ -553,6 +616,14 @@
 				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);
+		}
 		refreshmodel(model);
 	}
 
@@ -571,7 +642,10 @@
 		cams[i].s = scene;
 	}
 	maincam = &cams[0];
-	light = normvec3(subpt3(light, center));
+	light.p = Pt3(0,100,100,1);
+	light.c = Pt3(1,1,1,1);
+	light.type = LIGHT_POINT;
+	lightdir = normvec3(subpt3(light.p, center));
 
 	keyc = chancreate(sizeof(void*), 1);
 	drawc = chancreate(sizeof(void*), 1);