shithub: libgraphics

Download patch

ref: e490447bf7b3688ced181e8aa6315b28537b4e61
parent: 99a743a7965404b12d05c2d675083209c326433b
author: rodri <rgl@antares-labs.eu>
date: Sun Mar 9 19:28:49 EDT 2025

add support for multiple light sources and fix lighting functions.

--- a/graphics.h
+++ b/graphics.h
@@ -208,6 +208,7 @@
 	void (*addent)(Scene*, Entity*);
 	void (*delent)(Scene*, Entity*);
 	Entity *(*getent)(Scene*, char*);
+	void (*addlight)(Scene*, LightSource*);
 };
 
 struct Shaderparams
@@ -467,6 +468,7 @@
 double sign(double);
 double step(double, double);
 double smoothstep(double, double, double);
-Color getlightcolor(LightSource*, Point3);
+Color getlightcolor(LightSource*, Point3, Point3);
+Color getscenecolor(Scene*, Point3, Point3);
 
 extern Rectangle UR;	/* unit rectangle */
--- a/scene.c
+++ b/scene.c
@@ -163,6 +163,16 @@
 	return nil;
 }
 
+static void
+scene_addlight(Scene *s, LightSource *l)
+{
+	l->prev = s->lights.prev;
+	l->next = s->lights.prev->next;
+	s->lights.prev->next = l;
+	s->lights.prev = l;
+	s->nlights++;
+}
+
 Scene *
 newscene(char *name)
 {
@@ -172,10 +182,13 @@
 	s->name = name == nil? nil: strdup(name);
 	s->ents.prev = s->ents.next = &s->ents;
 	s->nents = 0;
+	s->lights.prev = s->lights.next = &s->lights;
+	s->nlights = 0;
 	s->skybox = nil;
 	s->addent = scene_addent;
 	s->delent = scene_delent;
 	s->getent = scene_getent;
+	s->addlight = scene_addlight;
 	return s;
 }
 
--- a/shadeop.c
+++ b/shadeop.c
@@ -30,20 +30,67 @@
 	return t*t * (3 - 2*t);
 }
 
-/* TODO apply attenuation for punctual lights */
+/* see Equation 5.16, Real-Time Rendering 4th ed. § 5.2.2 */
+static double
+dfalloff(double d)
+{
+	enum { RMAX = 3000 };	/* cutoff distance */
+	d = d/RMAX;
+	d *= d;
+	d = max(0, 1 - d);
+	return d*d;
+}
+
 Color
-getlightcolor(LightSource *l, Point3 dir)
+getlightcolor(LightSource *l, Point3 p, Point3 n)
 {
-	double cθs, cθu, cθp, t;
+	double cθs, cθu, cθp, t, r;
+	Point3 ldir;
+	Color c;
 
-	/* see “Spotlights”, Real-Time Rendering 4th ed. § 5.2.2 */
-	if(l->type == LightSpot){
-		cθs = dotvec3(mulpt3(dir, -1), l->dir);
+	ldir = subpt3(l->p, p);
+	r = vec3len(ldir);
+	ldir = divpt3(ldir, r);
+
+	switch(l->type){
+	case LightPoint:
+		t = max(0, dotvec3(ldir, n));
+		c = mulpt3(l->c, t);
+
+		/* attenuation */
+		c = mulpt3(c, dfalloff(r));
+		break;
+	case LightDirectional:
+		t = max(0, dotvec3(mulpt3(l->dir, -1), n));
+		c = mulpt3(l->c, t);
+		break;
+	case LightSpot:
+		/* see “Spotlights”, Real-Time Rendering 4th ed. § 5.2.2 */
+		cθs = dotvec3(mulpt3(ldir, -1), l->dir);
 		cθu = cos(l->θu);
 		cθp = cos(l->θp);
+
 //		return mulpt3(l->c, smoothstep(cθu, cθp, cθs));
 		t = fclamp((cθs - cθu)/(cθp - cθu), 0, 1);
-		return mulpt3(l->c, t*t);
+
+		c = mulpt3(l->c, t*t);
+
+		/* attenuation */
+		c = mulpt3(c, dfalloff(r));
+		break;
+	default: sysfatal("alien light form detected");
 	}
-	return l->c;
+	return c;
+}
+
+Color
+getscenecolor(Scene *s, Point3 p, Point3 n)
+{
+	LightSource *l;
+	Color c;
+
+	c = Vec3(0,0,0);
+	for(l = s->lights.next; l != &s->lights; l = l->next)
+		c = addpt3(c, getlightcolor(l, p, n));
+	return c;
 }