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;
}