Tachyon (current)  Current Main Branch
light.c
Go to the documentation of this file.
1 /*
2  * light.c - This file contains declarations and defines for light sources.
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: light.c,v 1.30 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 
16 #define TACHYON_INTERNAL 1
17 #include "tachyon.h"
18 #include "macros.h"
19 #include "vector.h"
20 #include "intersect.h"
21 #include "util.h"
22 
23 #define LIGHT_PRIVATE
24 #include "light.h"
25 
26 static object_methods light_methods = {
27  (void (*)(const void *, void *))(light_intersect),
28  (void (*)(const void *, const void *, const void *, void *))(light_normal),
29  light_bbox,
30  free
31 };
32 
33 /* special routine to free directional lights which are */
34 /* not freed by object list deallocation */
35 void free_light_special(void *voidlight) {
36  light *l = (light *) voidlight;
37  if (l->shade_diffuse == (flt (*)(struct light_t *, shadedata *)) directional_light_shade_diffuse)
38  free(l);
39 }
40 
41 
42 directional_light * newdirectionallight(void * tex, vector dir) {
44 
45  l=(directional_light *) malloc(sizeof(directional_light));
46  memset(l, 0, sizeof(directional_light));
47  l->methods = &light_methods;
49 
50  l->tex=tex;
51  l->tex->flags = RT_TEXTURE_SHADOWCAST | RT_TEXTURE_ISLIGHT;
52  l->tex->diffuse=0.0;
53  l->tex->specular=0.0;
54  l->tex->opacity=1.0;
55 
56  l->dir.x=-dir.x; /* store negated light direction for high shading speed */
57  l->dir.y=-dir.y;
58  l->dir.z=-dir.z;
59 
60  return l;
61 }
62 
63 point_light * newpointlight(void * tex, vector ctr, flt rad) {
64  point_light * l;
65 
66  l=(point_light *) malloc(sizeof(point_light));
67  memset(l, 0, sizeof(point_light));
68  l->methods = &light_methods;
70 
71  l->tex=tex;
72  l->tex->flags = RT_TEXTURE_SHADOWCAST | RT_TEXTURE_ISLIGHT;
73  l->tex->diffuse=0.0;
74  l->tex->specular=0.0;
75  l->tex->opacity=1.0;
76 
77  l->ctr=ctr;
78  l->rad=rad;
79 
81  l->Kc = 1.0;
82  l->Kl = 0.0;
83  l->Kq = 0.0;
84 
86  l->spotdir.x = 0.0;
87  l->spotdir.y = 0.0;
88  l->spotdir.z = 1.0;
89  l->fallstart = 0.3;
90  l->fallend = 0.7;
91 
92  return l;
93 }
94 
95 point_light * newspotlight(void * tex, vector ctr, flt rad, vector dir,
96  flt fallstart, flt fallend) {
97  point_light * l;
98 
99  l=(point_light *) malloc(sizeof(point_light));
100  memset(l, 0, sizeof(point_light));
101  l->methods = &light_methods;
103 
104  l->tex=tex;
105  l->tex->flags = RT_TEXTURE_SHADOWCAST | RT_TEXTURE_ISLIGHT;
106  l->tex->diffuse=0.0;
107  l->tex->specular=0.0;
108  l->tex->opacity=1.0;
109 
110  l->ctr=ctr;
111  l->rad=rad;
112 
114  l->Kc = 1.0;
115  l->Kl = 0.0;
116  l->Kq = 0.0;
117 
119  l->spotdir = dir;
120  l->fallstart = fallstart;
121  l->fallend = fallend;
122 
123  return l;
124 }
125 
126 /*
127  * Set the attenuation equation for a positional light
128  */
129 void light_set_attenuation(point_light * li, flt Kc, flt Kl, flt Kq) {
130  li->Kc = Kc; /* constant attenuation coefficient */
131  li->Kl = Kl; /* linear attenuation coefficient */
132  li->Kq = Kq; /* quadratic attenuation coefficient */
133 
135  li->shade_diffuse = point_light_shade_diffuse; /* use the complex shader */
136 }
137 
138 
139 /*
140  * Private / Internal lighting routines.
141  */
142 
143 
144 
145 /*
146  * Direction Lighting - calculate diffuse contribution of directional light
147  */
148 static flt directional_light_shade_diffuse(directional_light * li, shadedata *shadevars) {
149  flt inten;
150  shadevars->L = li->dir; /* set light direction */
151  shadevars->Llen = FHUGE; /* infinite distance tolight */
152  VDOT(inten, (shadevars->N), li->dir) /* light intensity */
153  return inten;
154 }
155 
156 
157 /*
158  * Point Light - calculate diffuse contribution of positional light
159  * This version handles the simplest case only.
160  */
161 static flt simple_point_light_shade_diffuse(point_light * li, shadedata *shadevars) {
162  flt inten, len;
163 
164  VSUB(li->ctr, (shadevars->hit), (shadevars->L)) /* find the light vector */
165 
166  /* calculate the distance to the light from the hit point */
167  len = SQRT(shadevars->L.x*shadevars->L.x + shadevars->L.y*shadevars->L.y + shadevars->L.z*shadevars->L.z) + EPSILON;
168 
169  shadevars->L.x /= len; /* normalize the light direction */
170  shadevars->L.y /= len;
171  shadevars->L.z /= len;
172  shadevars->Llen = len; /* set distance to the light */
173 
174  VDOT(inten, shadevars->N, shadevars->L) /* light intensity */
175  return inten;
176 }
177 
178 
179 /*
180  * Point Light - calculate diffuse contribution of positional light
181  * This version handles spotlights and attenuation as well.
182  */
183 static flt point_light_shade_diffuse(point_light * li, shadedata *shadevars) {
184  flt inten, len;
185 
186  VSUB(li->ctr, (shadevars->hit), (shadevars->L)) /* find the light vector */
187 
188  /* calculate the distance to the light from the hit point */
189  len = SQRT(shadevars->L.x*shadevars->L.x + shadevars->L.y*shadevars->L.y + shadevars->L.z*shadevars->L.z) + EPSILON;
190 
191  shadevars->L.x /= len; /* normalize the light direction */
192  shadevars->L.y /= len;
193  shadevars->L.z /= len;
194  shadevars->Llen = len; /* set distance to the light */
195 
196  VDOT(inten, shadevars->N, shadevars->L) /* light intensity */
197  inten *= li->attenuationfunc(li, shadevars->Llen);
198  inten *= li->spotfunc(li, &shadevars->L);
199  return inten;
200 }
201 
202 
203 /*
204  * Attenuation functions.
205  */
206 static flt light_no_attenuation(void * vli, flt Llen) {
207  return 1.0;
208 }
209 
210 static flt light_complex_attenuation(void * vli, flt Llen) {
211  point_light * li = (point_light *) vli;
212  return 1.0 / (li->Kc + ((li->Kl + li->Kq*Llen) * Llen));
213 }
214 
215 
216 /*
217  * Falloff functions for spotlights.
218  */
219 static flt light_no_falloff(void * vli, vector * L) {
220  return 1.0;
221 }
222 
223 
224 static flt light_spotlight_falloff(void * vli, vector * L) {
225  point_light * li = (point_light *) vli;
226  flt ang, cang;
227 
228  VDOT(cang, li->spotdir, (*L))
229 
230  ang = ACOS(-cang);
231 
232  if (ang > li->fallstart) {
233  if (ang > li->fallend)
234  return 0.0;
235  else
236  return 1.0 - ((ang - li->fallstart) / (li->fallend - li->fallstart));
237  }
238 
239  return 1.0;
240 }
241 
242 
243 static int light_bbox(void * obj, vector * min, vector * max) {
244  return 0; /* lights are unbounded currently */
245 }
246 
247 
248 static void light_intersect(const point_light * l, ray * ry) {
249  flt b, disc, t1, t2, temp;
250  vector V;
251 
252  /* Lights do not cast shadows.. */
253  if (ry->flags & RT_RAY_SHADOW)
254  return;
255 
256  VSUB(l->ctr, ry->o, V);
257  VDOT(b, V, ry->d);
258  VDOT(temp, V, V);
259 
260  disc=b*b + l->rad*l->rad - temp;
261 
262  if (disc<=0.0) return;
263  disc=SQRT(disc);
264 
265  t2=b+disc;
266  if (t2 <= SPEPSILON)
267  return;
268  ry->add_intersection(t2, (object *) l, ry);
269 
270  t1=b-disc;
271  if (t1 > SPEPSILON)
272  ry->add_intersection(t1, (object *) l, ry);
273 }
274 
275 static void light_normal(const point_light * l, const vector * pnt, const ray * incident, vector * N) {
276  flt invlen;
277 
278  N->x = pnt->x - l->ctr.x;
279  N->y = pnt->y - l->ctr.y;
280  N->z = pnt->z - l->ctr.z;
281 
282  invlen = 1.0 / SQRT(N->x*N->x + N->y*N->y + N->z*N->z);
283  N->x *= invlen;
284  N->y *= invlen;
285  N->z *= invlen;
286 
287  /* Flip surface normal to point toward the viewer if necessary */
288  if (VDot(N, &(incident->d)) > 0.0) {
289  N->x=-N->x;
290  N->y=-N->y;
291  N->z=-N->z;
292  }
293 }
294 
295 
296 
297 
298 
static flt directional_light_shade_diffuse(directional_light *li, shadedata *shadevars)
Definition: light.c:148
flt Kq
quadratic attenuation factor
Definition: light.h:26
static flt light_complex_attenuation(void *vli, flt Llen)
Definition: light.c:210
static flt light_no_falloff(void *vli, vector *L)
Definition: light.c:219
flt fallstart
fallof start angle
Definition: light.h:29
Definition: light.h:13
flt Kl
linear attenuation factor
Definition: light.h:25
static flt simple_point_light_shade_diffuse(point_light *li, shadedata *shadevars)
Definition: light.c:161
static int light_bbox(void *obj, vector *min, vector *max)
Definition: light.c:243
flt rad
point light radius when visible
Definition: light.h:22
flt(* attenuationfunc)(void *, flt)
attenuation fctn pointer
Definition: light.h:23
flt(* spotfunc)(void *, vector *)
spotlight fctn pointer
Definition: light.h:27
RT_OBJECT_HEAD flt(* shade_diffuse)(struct light_t *, shadedata *)
diffuse shading function
Definition: light.h:15
#define VSUB(a, b, c)
Definition: macros.h:24
static void light_normal(const point_light *l, const vector *pnt, const ray *incident, vector *N)
Definition: light.c:275
flt VDot(apivector *a, apivector *b)
point_light * newpointlight(void *tex, vector ctr, flt rad)
Definition: light.c:63
static flt light_no_attenuation(void *vli, flt Llen)
Definition: light.c:206
double flt
generic floating point number, using double
Definition: tachyon.h:47
static object_methods light_methods
Definition: light.c:26
flt fallend
fallof end angle
Definition: light.h:30
#define ACOS(x)
Definition: util.h:25
flt Kc
constant attenuation factor
Definition: light.h:24
vector ctr
point light position
Definition: light.h:21
#define VDOT(return, a, b)
Definition: macros.h:15
void light_set_attenuation(point_light *li, flt Kc, flt Kl, flt Kq)
Definition: light.c:129
RT_OBJECT_HEAD flt(* shade_diffuse)(struct directional_light_t *, shadedata *)
diffuse shading function
Definition: light.h:35
static flt light_spotlight_falloff(void *vli, vector *L)
Definition: light.c:224
Tachyon cross-platform timers, special math function wrappers, and RNGs.
vector spotdir
spotlight direction
Definition: light.h:28
#define SQRT(x)
Definition: util.h:31
point_light * newspotlight(void *tex, vector ctr, flt rad, vector dir, flt fallstart, flt fallend)
Definition: light.c:95
static flt point_light_shade_diffuse(point_light *li, shadedata *shadevars)
Definition: light.c:183
static void light_intersect(const point_light *l, ray *ry)
Definition: light.c:248
RT_OBJECT_HEAD flt(* shade_diffuse)(struct point_light_t *, shadedata *)
diffuse shading function
Definition: light.h:20
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
vector dir
lighting direction
Definition: light.h:36
directional_light * newdirectionallight(void *tex, vector dir)
Definition: light.c:42
void free_light_special(void *voidlight)
Definition: light.c:35