Tachyon (current)  Current Main Branch
shade.c
Go to the documentation of this file.
1 /*
2  * shade.c - This file contains the functions that perform surface shading.
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: shade.c,v 1.120 2022/03/25 06:02:56 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 "threads.h"
20 #include "light.h"
21 #include "intersect.h"
22 #include "vector.h"
23 #include "trace.h"
24 #include "shade.h"
25 
26 
27 /*
28  * Lowest Quality Shader - Returns the raw color of an object.
29  *
30  */
31 
32 color lowest_shader(ray * incident) {
33  int numints;
34  object const * obj;
35  flt t = FHUGE;
36  color col;
37 
38  numints=closest_intersection(&t, &obj, incident);
39  /* find the number of intersections */
40  /* and return the closest one. */
41 
42  if (numints < 1) {
43  /* if there weren't any object intersections then return the */
44  /* black for the pixel color. */
45  col.r = 0.0;
46  col.g = 0.0;
47  col.b = 0.0;
48 
49  return col;
50  }
51 
52  col.r = 1.0;
53  col.g = 1.0;
54  col.b = 1.0;
55 
56  return col;
57 }
58 
59 
60 /*
61  * Low Quality Shader - Returns raw texture color of objects hit, nothing else.
62  *
63  */
64 
65 color low_shader(ray * incident) {
66  int numints;
67  object const * obj;
68  vector hit;
69  flt t = FHUGE;
70 
71  numints=closest_intersection(&t, &obj, incident);
72  /* find the number of intersections */
73  /* and return the closest one. */
74 
75  if (numints < 1) {
76  /* if there weren't any object intersections then return the */
77  /* background texture for the pixel color. */
78  return incident->scene->bgtexfunc(incident);
79  }
80 
81  RAYPNT(hit, (*incident), t) /* find the point of intersection from t */
82  incident->opticdist = FHUGE;
83  return obj->tex->texfunc(&hit, obj->tex, incident);
84 }
85 
86 
87 
88 /*
89  * Medium Quality Shader - Includes a subset of the rendering features
90  *
91  */
92 
93 color medium_shader(ray * incident) {
94  color col, diffuse, phongcol;
95  shadedata shadevars;
96  flt inten;
97  flt t = FHUGE;
98  object const * obj;
99  int numints;
100  list * cur;
101 
102  numints=closest_intersection(&t, &obj, incident);
103  /* find the number of intersections */
104  /* and return the closest one. */
105 
106  if (numints < 1) {
107  /* if there weren't any object intersections then return the */
108  /* background texture for the pixel color. */
109  col=incident->scene->bgtexfunc(incident);
110 
111  /* Fog overrides the background color if we're using */
112  /* Tachyon radial fog, but not for OpenGL style fog. */
113  if (incident->scene->fog.type == RT_FOG_NORMAL &&
114  incident->scene->fog.fog_fctn != NULL) {
115  col = fog_color(incident, col, t);
116  }
117 
118  return col;
119  }
120 
121  RAYPNT(shadevars.hit, (*incident), t) /* find point of intersection from t */
122  incident->opticdist += t;
123  obj->methods->normal(obj, &shadevars.hit, incident, &shadevars.N); /* find the surface normal */
124 
125  /* don't render transparent surfaces if we've reached the max count */
126  if ((obj->tex->opacity < 1.0) && (incident->transcnt < 1)) {
127  /* spawn transmission rays / refraction */
128  /* note: this will overwrite the old intersection list */
129  return shade_transmission(incident, &shadevars, 1.0);
130  }
131 
132  /* execute the object's texture function */
133  col = obj->tex->texfunc(&shadevars.hit, obj->tex, incident);
134 
135  if (obj->tex->flags & RT_TEXTURE_ISLIGHT) {
136  /* if the current object is a light, then we */
137  return col; /* will only use the object's base color */
138  }
139 
140  diffuse.r = 0.0;
141  diffuse.g = 0.0;
142  diffuse.b = 0.0;
143  phongcol = diffuse;
144 
145  if ((obj->tex->diffuse > MINCONTRIB) || (obj->tex->phong > MINCONTRIB)) {
146  flt light_scale = incident->scene->light_scale;
147  cur = incident->scene->lightlist;
148  while (cur != NULL) { /* loop for light contributions */
149  light * li=(light *) cur->item; /* set li=to the current light */
150  inten = light_scale * li->shade_diffuse(li, &shadevars);
151 
152  /* add in diffuse lighting for this light if we're facing it */
153  if (inten > MINCONTRIB) {
154  /* calculate diffuse lighting component */
155  ColorAddS(&diffuse, &((standard_texture *)li->tex)->col, inten);
156 
157  /* phong type specular highlights */
158  if (obj->tex->phong > MINCONTRIB) {
159  flt phongval = light_scale * incident->scene->phongfunc(incident, &shadevars, obj->tex->phongexp);
160  if (obj->tex->phongtype == RT_PHONG_METAL)
161  ColorAddS(&phongcol, &col, phongval * obj->tex->phong);
162  else
163  ColorAddS(&phongcol, &((standard_texture *)li->tex)->col, phongval * obj->tex->phong);
164  }
165  }
166 
167  cur = cur->next;
168  }
169  }
170 
171  if (obj->tex->outline > 0.0) {
172  flt outlinefactor;
173  flt edgefactor = VDot(&shadevars.N, &incident->d);
174  edgefactor *= edgefactor;
175  edgefactor = 1.0 - edgefactor;
176  edgefactor = 1.0 - POW(edgefactor, (1.0 - obj->tex->outlinewidth) * 32.0);
177  outlinefactor = (1.0-obj->tex->outline) + (edgefactor * obj->tex->outline);
178  ColorScale(&diffuse, obj->tex->diffuse * outlinefactor);
179  } else {
180  ColorScale(&diffuse, obj->tex->diffuse);
181  }
182 
183  col.r *= (diffuse.r + obj->tex->ambient); /* do a product of the */
184  col.g *= (diffuse.g + obj->tex->ambient); /* diffuse intensity with */
185  col.b *= (diffuse.b + obj->tex->ambient); /* object color + ambient */
186 
187  if (obj->tex->phong > MINCONTRIB) {
188  ColorAccum(&col, &phongcol);
189  }
190 
191  /* spawn reflection rays if necessary */
192  /* note: this will overwrite the old intersection list */
193  if (obj->tex->specular > MINCONTRIB) {
194  color specol;
195  specol = shade_reflection(incident, &shadevars, obj->tex->specular);
196  ColorAccum(&col, &specol);
197  }
198 
199  /* spawn transmission rays / refraction */
200  /* note: this will overwrite the old intersection list */
201  if (obj->tex->opacity < (1.0 - MINCONTRIB)) {
202  color transcol;
203  float alpha = obj->tex->opacity;
204 
205  /* Emulate Raster3D's angle-dependent surface opacity if enabled */
206  if ((incident->scene->transmode | obj->tex->transmode) & RT_TRANS_RASTER3D) {
207  alpha = 1.0 + COS(3.1415926 * (1.0-alpha) * VDot(&shadevars.N, &incident->d));
208  alpha = alpha*alpha * 0.25;
209  }
210 
211  transcol = shade_transmission(incident, &shadevars, 1.0 - alpha);
212  if (incident->scene->transmode & RT_TRANS_VMD)
213  ColorScale(&col, alpha);
214 
215  ColorAccum(&col, &transcol);
216  }
217 
218  /* calculate fog effects */
219  if (incident->scene->fog.fog_fctn != NULL) {
220  col = fog_color(incident, col, t);
221  }
222 
223  return col; /* return the color of the shaded pixel... */
224 }
225 
226 
227 
228 /*
229  * Full Quality Shader - Includes all possible rendering features
230  *
231  */
232 
233 color full_shader(ray * incident) {
234  color col, diffuse, ambocccol, phongcol;
235  shadedata shadevars;
236  ray shadowray;
237  flt inten;
238  flt t = FHUGE;
239  object const * obj;
240  int numints;
241  list * cur;
242 
243  numints=closest_intersection(&t, &obj, incident);
244  /* find the number of intersections */
245  /* and return the closest one. */
246 
247  if (numints < 1) {
248  /* if there weren't any object intersections then return the */
249  /* background texture for the pixel color. */
250  col=incident->scene->bgtexfunc(incident);
251 
252  /* Fog overrides the background color if we're using */
253  /* Tachyon radial fog, but not for OpenGL style fog. */
254  if (incident->scene->fog.type == RT_FOG_NORMAL &&
255  incident->scene->fog.fog_fctn != NULL) {
256  col = fog_color(incident, col, t);
257  }
258 
259  return col;
260  }
261 
262  RAYPNT(shadevars.hit, (*incident), t) /* find point of intersection from t */
263  incident->opticdist += t;
264  obj->methods->normal(obj, &shadevars.hit, incident, &shadevars.N); /* find the surface normal */
265 
266  /* don't render transparent surfaces if we've reached the max count */
267  if ((obj->tex->opacity < 1.0) && (incident->transcnt < 1)) {
268  /* spawn transmission rays / refraction */
269  /* note: this will overwrite the old intersection list */
270  return shade_transmission(incident, &shadevars, 1.0);
271  }
272 
273  /* execute the object's texture function */
274  col = obj->tex->texfunc(&shadevars.hit, obj->tex, incident);
275 
276  if (obj->tex->flags & RT_TEXTURE_ISLIGHT) {
277  /* if the current object is a light, then we */
278  return col; /* will only use the object's base color */
279  }
280 
281  diffuse.r = 0.0;
282  diffuse.g = 0.0;
283  diffuse.b = 0.0;
284  ambocccol = diffuse;
285  phongcol = diffuse;
286  if ((obj->tex->diffuse > MINCONTRIB) || (obj->tex->phong > MINCONTRIB)) {
287  flt light_scale = incident->scene->light_scale;
288  cur = incident->scene->lightlist;
289 
290  if (incident->scene->flags & RT_SHADE_CLIPPING) {
291  shadowray.add_intersection = add_clipped_shadow_intersection;
292  } else {
293  shadowray.add_intersection = add_shadow_intersection;
294  }
295  shadowray.serial = incident->serial + 1; /* track ray serial number */
296  shadowray.mbox = incident->mbox;
297  shadowray.scene = incident->scene;
298 
299  while (cur != NULL) { /* loop for light contributions */
300  light * li=(light *) cur->item; /* set li=to the current light */
301  inten = light_scale * li->shade_diffuse(li, &shadevars);
302 
303  /* add in diffuse lighting for this light if we're facing it */
304  if (inten > MINCONTRIB) {
305  /* test for a shadow */
306  shadowray.o = shadevars.hit;
307  shadowray.d = shadevars.L;
308  shadowray.maxdist = shadevars.Llen;
309  shadowray.flags = RT_RAY_SHADOW;
310  shadowray.serial++;
311  intersect_objects(&shadowray); /* trace the shadow ray */
312 
313  if (!shadow_intersection(&shadowray)) {
314  /* If the light isn't occluded, then we modulate it by any */
315  /* transparent surfaces the shadow ray encountered, and */
316  /* proceed with illumination calculations */
317  inten *= shadowray.intstruct.shadowfilter;
318 
319  /* calculate diffuse lighting component */
320  ColorAddS(&diffuse, &((standard_texture *)li->tex)->col, inten);
321 
322  /* phong type specular highlights */
323  if (obj->tex->phong > MINCONTRIB) {
324  flt phongval = light_scale * incident->scene->phongfunc(incident, &shadevars, obj->tex->phongexp);
325  if (obj->tex->phongtype == RT_PHONG_METAL)
326  ColorAddS(&phongcol, &col, phongval * obj->tex->phong);
327  else
328  ColorAddS(&phongcol, &((standard_texture *)li->tex)->col, phongval * obj->tex->phong);
329  }
330  }
331  }
332 
333  cur = cur->next;
334  }
335  incident->serial = shadowray.serial; /* track ray serial number */
336 
337  /* add ambient occlusion lighting, if enabled */
338  if (incident->scene->ambocc.numsamples > 0) {
339  ambocccol = shade_ambient_occlusion(incident, &shadevars);
340  }
341  }
342 
343  /* accumulate diffuse and ambient occlusion together */
344  diffuse.r += ambocccol.r;
345  diffuse.g += ambocccol.g;
346  diffuse.b += ambocccol.b;
347 
348  if (obj->tex->outline > 0.0) {
349  flt outlinefactor;
350  flt edgefactor = VDot(&shadevars.N, &incident->d);
351  edgefactor *= edgefactor;
352  edgefactor = 1.0 - edgefactor;
353  edgefactor = 1.0 - POW(edgefactor, (1.0 - obj->tex->outlinewidth) * 32.0);
354  outlinefactor = (1.0-obj->tex->outline) + (edgefactor * obj->tex->outline);
355  ColorScale(&diffuse, obj->tex->diffuse * outlinefactor);
356  } else {
357  ColorScale(&diffuse, obj->tex->diffuse);
358  }
359 
360  /* do a product of the diffuse intensity with object color + ambient */
361  col.r *= (diffuse.r + obj->tex->ambient);
362  col.g *= (diffuse.g + obj->tex->ambient);
363  col.b *= (diffuse.b + obj->tex->ambient);
364 
365  if (obj->tex->phong > MINCONTRIB) {
366  ColorAccum(&col, &phongcol);
367  }
368 
369  /* spawn reflection rays if necessary */
370  /* note: this will overwrite the old intersection list */
371  if (obj->tex->specular > MINCONTRIB) {
372  color specol;
373  specol = shade_reflection(incident, &shadevars, obj->tex->specular);
374  ColorAccum(&col, &specol);
375  }
376 
377  /* spawn transmission rays / refraction */
378  /* note: this will overwrite the old intersection list */
379  if (obj->tex->opacity < (1.0 - MINCONTRIB)) {
380  color transcol;
381  float alpha = obj->tex->opacity;
382 
383  /* Emulate Raster3D's angle-dependent surface opacity if enabled */
384  if ((incident->scene->transmode | obj->tex->transmode) & RT_TRANS_RASTER3D) {
385  alpha = 1.0 + COS(3.1415926 * (1.0-alpha) * VDot(&shadevars.N, &incident->d));
386  alpha = alpha*alpha * 0.25;
387  }
388 
389  transcol = shade_transmission(incident, &shadevars, 1.0 - alpha);
390  if (incident->scene->transmode & RT_TRANS_VMD)
391  ColorScale(&col, alpha);
392 
393  ColorAccum(&col, &transcol);
394  }
395 
396  /* calculate fog effects */
397  if (incident->scene->fog.fog_fctn != NULL) {
398  col = fog_color(incident, col, t);
399  }
400 
401  return col; /* return the color of the shaded pixel... */
402 }
403 
404 
405 /*
406  * Ambient Occlusion shader, implements a simple global illumination-like
407  * lighting model which does well for highly diffuse natural lighting
408  * scenes.
409  */
410 color shade_ambient_occlusion(ray * incident, const shadedata * shadevars) {
411  ray ambray;
412  color ambcol;
413  int i;
414  flt ndotambl;
415  flt inten = 0.0;
416 
417  /* The integrated hemisphere for an unweighted non-importance-sampled */
418  /* ambient occlusion case has a maximum sum (when uniformly sampled) */
419  /* of 0.5 relative to an similar direct illumination case oriented */
420  /* exactly with the surface normal. So, we prescale the normalization */
421  /* for ambient occlusion by a factor of 2.0. This will have to change */
422  /* when importance sampling is implemented. If a small number of */
423  /* occlusion samples are taken, and they coincidentally end up facing */
424  /* with the surface normal, we could exceed the expected normalization */
425  /* factor, but the results will be correctly clamped by the rest of */
426  /* shading code, so we don't worry about it here. */
427  flt lightscale = 2.0 / incident->scene->ambocc.numsamples;
428 
429  ambray.o=shadevars->hit;
430  ambray.d=shadevars->N;
431  ambray.o=Raypnt(&ambray, EPSILON); /* avoid numerical precision bugs */
432  ambray.serial = incident->serial + 1; /* next serial number */
433  ambray.idx=incident->idx; /* 1-D pixel index for RNG seeding */
434  ambray.randval=incident->randval; /* random number seed */
435  ambray.frng=incident->frng; /* 32-bit FP RNG handle */
436  if (incident->scene->flags & RT_SHADE_CLIPPING) {
437  ambray.add_intersection = add_clipped_shadow_intersection;
438  } else {
439  ambray.add_intersection = add_shadow_intersection;
440  }
441  ambray.mbox = incident->mbox;
442  ambray.scene=incident->scene; /* global scenedef info */
443 
444  for (i=0; i<incident->scene->ambocc.numsamples; i++) {
445  float dir[3];
446  ambray.maxdist = incident->scene->ambocc.ao_maxdist; /* occ dist limit */
447  ambray.flags = RT_RAY_SHADOW; /* shadow ray */
448  ambray.serial++;
449 
450  /* generate a randomly oriented ray */
451  jitter_sphere3f(&ambray.frng, dir);
452  ambray.d.x = dir[0];
453  ambray.d.y = dir[1];
454  ambray.d.z = dir[2];
455 
456  /* flip the ray so it's in the same hemisphere as the surface normal */
457  ndotambl = VDot(&ambray.d, &shadevars->N);
458  if (ndotambl < 0) {
459  ndotambl = -ndotambl;
460  ambray.d.x = -ambray.d.x;
461  ambray.d.y = -ambray.d.y;
462  ambray.d.z = -ambray.d.z;
463  }
464 
465  intersect_objects(&ambray); /* trace the shadow ray */
466 
467  /* if no occlusions found within ao_maxdist, add AO contribution */
468  if (!shadow_intersection(&ambray)) {
469  /* If the light isn't occluded, then we modulate it by any */
470  /* transparent surfaces the shadow ray encountered, and */
471  /* proceed with illumination calculations */
472  ndotambl *= ambray.intstruct.shadowfilter;
473 
474  inten += ndotambl;
475  }
476  }
477  ambcol.r = lightscale * inten * incident->scene->ambocc.col.r;
478  ambcol.g = lightscale * inten * incident->scene->ambocc.col.g;
479  ambcol.b = lightscale * inten * incident->scene->ambocc.col.b;
480 
481  incident->serial = ambray.serial + 1; /* update the serial number */
482  incident->frng = ambray.frng; /* update AO RNG state */
483 
484  return ambcol;
485 }
486 
487 
488 
489 color shade_reflection(ray * incident, const shadedata * shadevars, flt specular) {
490  ray specray;
491  color col;
492  vector R;
493 
494  /* Do recursion depth test immediately to early-exit ASAP */
495  if (incident->depth <= 1) {
496  /* if ray is truncated, return the background texture as its color */
497  return incident->scene->bgtexfunc(incident);
498  }
499  specray.depth=incident->depth - 1; /* go up a level in recursion depth */
500  specray.transcnt=incident->transcnt; /* maintain trans surface count */
501 
502  VAddS(-2.0 * (incident->d.x * shadevars->N.x +
503  incident->d.y * shadevars->N.y +
504  incident->d.z * shadevars->N.z), &shadevars->N, &incident->d, &R);
505 
506  specray.o=shadevars->hit;
507  specray.d=R; /* reflect incident ray about normal */
508  specray.o=Raypnt(&specray, EPSILON); /* avoid numerical precision bugs */
509  specray.maxdist = FHUGE; /* take any intersection */
510  specray.opticdist = incident->opticdist;
511  specray.add_intersection=incident->add_intersection; /* inherit ray type */
512  specray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
513  specray.serial = incident->serial + 1; /* next serial number */
514  specray.mbox = incident->mbox;
515  specray.scene=incident->scene; /* global scenedef info */
516  specray.idx=incident->idx; /* 1-D pixel index for RNG seeding */
517  specray.randval=incident->randval; /* random number seed */
518  specray.frng=incident->frng; /* 32-bit FP RNG handle */
519 
520  /* inlined code from trace() to eliminate one level of recursion */
521  intersect_objects(&specray); /* trace specular reflection ray */
522  col=specray.scene->shader(&specray);
523 
524  incident->serial = specray.serial; /* update the serial number */
525  incident->frng = specray.frng; /* update AO RNG state */
526 
527  ColorScale(&col, specular);
528 
529  return col;
530 }
531 
532 
533 color shade_transmission(ray * incident, const shadedata * shadevars, flt trans) {
534  ray transray;
535  color col;
536 
537  /* Do recursion depth test immediately to early-exit ASAP */
538  if (incident->depth <= 1) {
539  /* if ray is truncated, return the background texture as its color */
540  return incident->scene->bgtexfunc(incident);
541  }
542  transray.o=shadevars->hit;
543  transray.d=incident->d; /* ray continues on incident path */
544  transray.o=Raypnt(&transray, EPSILON); /* avoid numerical precision bugs */
545  transray.maxdist = FHUGE; /* take any intersection */
546  transray.opticdist = incident->opticdist;
547  transray.add_intersection=incident->add_intersection; /* inherit ray type */
548  transray.depth=incident->depth - 1; /* track recursion depth */
549  transray.transcnt=incident->transcnt-1; /* maintain trans surface count */
550  transray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
551  transray.serial = incident->serial + 1; /* update serial number */
552  transray.mbox = incident->mbox;
553  transray.scene=incident->scene; /* global scenedef info */
554  transray.idx=incident->idx; /* 1-D pixel index for RNG seeding */
555  transray.randval=incident->randval; /* random number seed */
556  transray.frng=incident->frng; /* 32-bit FP RNG handle */
557 
558  /* inlined code from trace() to eliminate one level of recursion */
559  intersect_objects(&transray); /* trace transmission ray */
560  col=transray.scene->shader(&transray);
561 
562  incident->serial = transray.serial; /* update the serial number */
563  incident->frng = transray.frng; /* update AO RNG state */
564 
565  ColorScale(&col, trans);
566 
567  return col;
568 }
569 
570 
571 /*
572  * Phong shader, always returns 0.0, used for testing
573  */
574 flt shade_nullphong(const ray * incident, const shadedata * shadevars, flt specpower) {
575  return 0.0;
576 }
577 
578 /*
579  * Phong shader, implements specular highlight model
580  * using Blinn's halfway vector dotted with the surface normal.
581  * This is also the shading model used by OpenGL and Direct3D.
582  */
583 flt shade_blinn(const ray * incident, const shadedata * shadevars, flt specpower) {
584  vector H; /* Blinn's halfway vector */
585  flt inten; /* calculated intensity */
586 
587  /* since incident ray is negated direction to viewer, we subtract... */
588  /* sub. incoming ray dir. from light direction */
589  H.x = shadevars->L.x - incident->d.x;
590  H.y = shadevars->L.y - incident->d.y;
591  H.z = shadevars->L.z - incident->d.z;
592 
593  inten = shadevars->N.x * H.x + shadevars->N.y * H.y + shadevars->N.z * H.z;
594  if (inten > MINCONTRIB) {
595  /* normalize the previous dot product */
596  inten /= SQRT(H.x * H.x + H.y * H.y + H.z * H.z);
597 
598  /* calculate specular exponent */
599  inten = POW(inten, specpower);
600  } else {
601  inten = 0.0;
602  }
603 
604  return inten;
605 }
606 
607 
608 
609 /*
610  * Phong shader, implements specular highlight model
611  * using Blinn's halfway vector dotted with the surface normal.
612  * This is also the shading model used by OpenGL and Direct3D.
613  * Uses Graphics Gems IV chapter VI.1 algorithm for phong exponent
614  * instead of the usual call to pow().
615  */
616 flt shade_blinn_fast(const ray * incident, const shadedata * shadevars, flt specpower) {
617  vector H; /* Blinn's halfway vector */
618  flt inten; /* calculated intensity */
619 
620  /* since incident ray is negated direction to viewer, we subtract... */
621  /* sub. incoming ray dir. from light direction */
622  H.x = shadevars->L.x - incident->d.x;
623  H.y = shadevars->L.y - incident->d.y;
624  H.z = shadevars->L.z - incident->d.z;
625 
626  inten = shadevars->N.x * H.x + shadevars->N.y * H.y + shadevars->N.z * H.z;
627  if (inten > 0.0) {
628  /* normalize the previous dot product */
629  inten /= SQRT(H.x * H.x + H.y * H.y + H.z * H.z);
630 
631  /* replace specular exponent with a simple approximation */
632  inten = inten / (specpower - (specpower * inten) + inten);
633  } else {
634  inten = 0.0;
635  }
636 
637  return inten;
638 }
639 
640 
641 /*
642  * Phong shader, implements a Phong specular highlight model
643  * using the reflection vector about the surface normal, dotted
644  * with the direction to the viewer. This is the "classic" phong
645  */
646 flt shade_phong(const ray * incident, const shadedata * shadevars, flt specpower) {
647  vector R; /* reflection vector */
648  vector V; /* direction to viewpoint */
649  vector LL; /* reverse direction to light */
650  flt inten; /* calculated intensity */
651 
652  LL = shadevars->L;
653  VScale(&LL, -1.0);
654  VAddS(-2.0 * (LL.x * shadevars->N.x +
655  LL.y * shadevars->N.y +
656  LL.z * shadevars->N.z), &shadevars->N, &LL, &R);
657 
658  V = incident->d;
659  VScale(&V, -1.0);
660  VNorm(&R); /* normalize reflection vector */
661  inten = VDot(&V, &R); /* dot product of halfway vector and surface normal */
662  inten = (inten > 0.0) ? POW(inten, specpower) : 0.0;
663 
664  return inten;
665 }
666 
667 
668 /*
669  * Fog functions (can be used for both radial or planar fog implementations)
670  */
671 
676 color fog_color(const ray * incident, color col, flt t) {
677  struct fogdata_t * fog = &incident->scene->fog;
678  float fogcoord = t; /* radial fog by default */
679 
680  if (fog->type == RT_FOG_OPENGL) {
681  /* Compute planar fog (e.g. to match OpenGL) by projecting t value onto */
682  /* the camera view direction vector to yield a planar a depth value. */
683  flt hitz = VDot(&incident->d, &incident->scene->camera.viewvec) * t;
684 
685  /* use the Z-depth for primary rays, radial distance otherwise */
686  fogcoord = (incident->flags & RT_RAY_PRIMARY) ? hitz : t;
687  }
688 
689  return incident->scene->fog.fog_fctn(fog, col, fogcoord);
690 }
691 
692 
696 color fog_color_linear(struct fogdata_t * fog, color col, flt r) {
697  color c;
698  flt f, t;
699 
700  f = (fog->end - r) / (fog->end - fog->start);
701  t = (f > 1.0) ? 1.0 : f;
702  f = (t < 0.0) ? 0.0 : t;
703 
704  c.r = (f * col.r) + ((1 - f) * fog->col.r);
705  c.g = (f * col.g) + ((1 - f) * fog->col.g);
706  c.b = (f * col.b) + ((1 - f) * fog->col.b);
707 
708  return c;
709 }
710 
711 
715 color fog_color_exp(struct fogdata_t * fog, color col, flt r) {
716  color c;
717  flt f, t, v;
718 
719  v = fog->density * (r - fog->start);
720  f = EXP(-v);
721  t = (f > 1.0) ? 1.0 : f;
722  f = (t < 0.0) ? 0.0 : t;
723 
724  c.r = (f * col.r) + ((1 - f) * fog->col.r);
725  c.g = (f * col.g) + ((1 - f) * fog->col.g);
726  c.b = (f * col.b) + ((1 - f) * fog->col.b);
727 
728  return c;
729 }
730 
731 
735 color fog_color_exp2(struct fogdata_t * fog, color col, flt r) {
736  color c;
737  flt f, t, v;
738 
739  v = fog->density * (r - fog->start);
740  f = EXP(-v*v);
741  t = (f > 1.0) ? 1.0 : f;
742  f = (t < 0.0) ? 0.0 : t;
743 
744  c.r = (f * col.r) + ((1 - f) * fog->col.r);
745  c.g = (f * col.g) + ((1 - f) * fog->col.g);
746  c.b = (f * col.b) + ((1 - f) * fog->col.b);
747 
748  return c;
749 }
750 
void add_clipped_shadow_intersection(flt t, const object *obj, ray *ry)
Definition: intersect.c:155
void ColorScale(color *a, flt s)
Definition: vector.c:91
color shade_reflection(ray *incident, const shadedata *shadevars, flt specular)
Definition: shade.c:489
color shade_transmission(ray *incident, const shadedata *shadevars, flt trans)
Definition: shade.c:533
int closest_intersection(flt *t, object const **obj, ray *ry)
Definition: intersect.c:119
color fog_color_exp2(struct fogdata_t *fog, color col, flt r)
OpenGL-like exponential-squared fog.
Definition: shade.c:735
void ColorAddS(color *a, const color *b, flt s)
Definition: vector.c:79
Definition: light.h:13
void ColorAccum(color *a, const color *b)
Definition: vector.c:85
#define RT_TRANS_VMD
mult shaded color by opacity, for VMD
Definition: tachyon.h:459
color shade_ambient_occlusion(ray *incident, const shadedata *shadevars)
Definition: shade.c:410
color lowest_shader(ray *incident)
Definition: shade.c:32
color fog_color_exp(struct fogdata_t *fog, color col, flt r)
OpenGL-like exponential fog.
Definition: shade.c:715
void VScale(vector *a, flt s)
Definition: vector.c:73
#define RT_FOG_OPENGL
planar OpenGL-like fog
Definition: tachyon.h:419
RT_OBJECT_HEAD flt(* shade_diffuse)(struct light_t *, shadedata *)
diffuse shading function
Definition: light.h:15
void VNorm(apivector *)
void jitter_sphere3f(rng_frand_handle *rngh, float *dir)
Definition: util.c:779
void VAddS(flt a, apivector *A, apivector *B, apivector *C)
int shadow_intersection(ray *ry)
Definition: intersect.c:195
flt VDot(apivector *a, apivector *b)
Tachyon cross-platform thread creation and management, atomic operations, and CPU feature query APIs...
#define RT_TRANS_RASTER3D
angle-dependent opacity modulation
Definition: tachyon.h:460
double flt
generic floating point number, using double
Definition: tachyon.h:47
flt shade_nullphong(const ray *incident, const shadedata *shadevars, flt specpower)
Definition: shade.c:574
flt shade_blinn_fast(const ray *incident, const shadedata *shadevars, flt specpower)
Definition: shade.c:616
#define COS(x)
Definition: util.h:26
color medium_shader(ray *incident)
Definition: shade.c:93
color full_shader(ray *incident)
Definition: shade.c:233
#define RAYPNT(c, a, b)
Definition: macros.h:18
color fog_color_linear(struct fogdata_t *fog, color col, flt r)
OpenGL-like linear fog.
Definition: shade.c:696
#define SQRT(x)
Definition: util.h:31
void add_shadow_intersection(flt t, const object *obj, ray *ry)
Definition: intersect.c:131
color fog_color(const ray *incident, color col, flt t)
Compute the fog color, given the active fogging function and fog parameters.
Definition: shade.c:676
#define POW(x, y)
Definition: util.h:29
vector Raypnt(const ray *a, flt t)
Definition: vector.c:63
color low_shader(ray *incident)
Definition: shade.c:65
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
#define RT_FOG_NORMAL
radial fog
Definition: tachyon.h:418
flt shade_phong(const ray *incident, const shadedata *shadevars, flt specpower)
Definition: shade.c:646
#define EXP(x)
Definition: util.h:27
#define RT_PHONG_METAL
Metallic Phong highlight.
Definition: tachyon.h:685
void intersect_objects(ray *ry)
Definition: intersect.c:47
flt shade_blinn(const ray *incident, const shadedata *shadevars, flt specpower)
Definition: shade.c:583