home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Raytrace & Morphing / SOS-RAYTRACE.ISO / programm / source / rayce27s / shade.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-02  |  6.5 KB  |  234 lines

  1. /*
  2.  * Shade.c -- the shading function
  3.  * 
  4.  * (c) 1994 by Shawn McHorse <Zaphod@fcircus.sat.tx.us>
  5.  * 
  6.  * Based on code by George Kyriazis and Han-Wen Nienhuys.
  7.  * 
  8.  * This program is free software; you can redistribute it and/or modify it
  9.  * under the terms of the GNU General Public License as published by the
  10.  * Free Software Foundation;
  11.  * 
  12.  * This program is distributed in the hope that it will be useful, but
  13.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU General Public License along
  18.  * with this program; if not, write to the Free Software Foundation, Inc.,
  19.  * 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include    <math.h>
  23. #include    "ray.h"
  24. #include    "proto.h"
  25. #include    "extern.h"
  26.  
  27. PRIVATE color   phong(struct intersect i, struct texture_data *tp, struct ray r, int n, double imp);
  28. PRIVATE color   microfacet(struct intersect i, struct texture_data *tp, struct ray r, int n, double imp);
  29.  
  30. PUBLIC color
  31. shade(struct intersect i, struct ray r, int recurse, double imp)
  32. {
  33.     color           col,
  34.                     tmpcol;
  35.     object         *op;
  36.     vector          refl;
  37.     double          c1 = 0.0,
  38.                     importance,
  39.                     nu,
  40.                     discr;
  41.     struct texture_data t;
  42.     struct ray      reflected;
  43.  
  44.     /* Find the first object in the hierarchy with a texture. */
  45.     for (op = i.q_ent.obj; op->text == NULL; op = op->daddy);
  46.  
  47.     /* Find texture at intersection point. */
  48.     fill_texture(&t, op->text, i);
  49.  
  50.     /* Apply the local shading model. */
  51.     switch (t.shadingtype) {
  52.     case PHONG_SHADING:
  53.     col = phong(i, &t, r, recurse, imp);
  54.     break;
  55. #ifdef UNDEFINED
  56.     case COOK:
  57.     col = microfacet(i, &t, r, recurse, imp);
  58.     break;
  59. #endif
  60.     }
  61.  
  62.     /*
  63.      * Don't bother with reflected and refracted rays if we're already as
  64.      * deep as we can go.
  65.      */
  66.     if (recurse >= max_trace_level)
  67.     return col;
  68.  
  69.     reflected.pos = i.x;
  70.     reflected.mint = INFTY;
  71.  
  72.     importance = imp * color_length(t.refr_color);
  73.     if (importance > depth_cutoff) {
  74.     ior_depth++;
  75.     if (i.q_ent.entering)
  76.         global_ior[ior_depth] = t.index;
  77.     else
  78.         global_ior[ior_depth] = global_ior[ior_depth - 2];
  79.  
  80.     /* Calculate refracted vector. */
  81.     c1 = -1 * vdot(r.dir, i.n);
  82.     nu = global_ior[ior_depth] / global_ior[ior_depth - 1];
  83.     discr = nu * nu - 1 + c1 * c1;
  84.  
  85.     /* Total Internal Reflection */
  86.     if (discr < -EPSILON) {
  87.         /* Calculate reflected vector. */
  88.         svproduct(refl, 2 * c1, i.n);
  89.         vadd(refl, r.dir, refl);
  90.  
  91.         /* Set up reflected ray. */
  92.         ior_depth--;
  93.         reflected.dir = refl;
  94.         reflected.type = R_REFLECT;
  95.  
  96.         /*
  97.          * we're reflecting and diffusing at the same time, so take
  98.          * means
  99.          */
  100.         tmpdouble = (t.refl_diffuse + t.refr_diffuse) / 2.0;
  101.         if (tmpdouble > EPSILON)
  102.         reflected = sample_ray(reflected, tmpdouble);
  103.  
  104.         tmpcol = trace(reflected, recurse + 1, importance + imp * color_length(t.refl_color));
  105.         return color_add(col, color_mul(tmpcol, color_add(t.refr_color, t.refl_color)));
  106.     }
  107.     if (discr < EPSILON)
  108.         svproduct(refl, c1, i.n);
  109.     else
  110.         svproduct(refl, c1 - sqrt(discr), i.n);
  111.     vadd(refl, r.dir, refl);
  112.     svproduct(refl, 1 / nu, refl);
  113.  
  114.     /* Set up the refracted ray. */
  115.     reflected.dir = refl;
  116.     reflected.type = R_REFRACT;
  117.     if (t.refr_diffuse > EPSILON)
  118.         reflected = sample_ray(reflected, t.refr_diffuse);
  119.     col = color_add(col, color_mul(t.refr_color, trace(reflected, recurse + 1, importance)));
  120.     ior_depth--;
  121.     }
  122.     importance = imp * color_length(t.refl_color);
  123.     if (importance > depth_cutoff) {
  124.     /* Calculate reflected vector. */
  125.     if (c1 == 0.0)
  126.         c1 = -1 * vdot(r.dir, i.n);
  127.     svproduct(refl, 2 * c1, i.n);
  128.     vadd(refl, r.dir, refl);
  129.  
  130.     /* Set up the reflected ray. */
  131.     reflected.dir = refl;
  132.     reflected.type = R_REFLECT;
  133.     reflected.mint = INFTY;
  134.     if (t.refl_diffuse > EPSILON)
  135.         reflected = sample_ray(reflected, t.refl_diffuse);
  136.     col = color_add(col, color_mul(t.refl_color, trace(reflected, recurse + 1, importance)));
  137.     }
  138.     return col;
  139. }
  140.  
  141. PRIVATE color
  142. phong(struct intersect i, struct texture_data *tp, struct ray r, int recursion, double imp)
  143. {
  144.  
  145.     object         *op;
  146.     color           col,
  147.                     factor;    /* factor to put influences of distance,
  148.                  * brilliance, etc. in */
  149.     vector          ldir,
  150.                     refl,
  151.                     normal;
  152.     double          ldist,
  153.                     ldotn,
  154.                     rdotv;
  155.     struct light_data *l;
  156.     struct ray      shadow_ray;
  157.  
  158.     /* Start off with ambient light. */
  159.     col = color_mul(ambient_light, tp->ambient);
  160.  
  161.     /* Set up the shadow ray data. */
  162.     shadow_ray.type = R_SHADOW;
  163.     shadow_ray.pos = i.x;
  164.  
  165.     /* the normal should be looking at us */
  166.     if (vdot(i.n, r.dir) > 0)
  167.     vneg(normal, i.n);    /* flip it */
  168.     else
  169.     normal = i.n;
  170.  
  171.     /* Walk the light list. */
  172.     for (op = first_light; op != NULL; op = op->next) {
  173.     l = op->data.light;
  174.  
  175.     /* Construct a normalized vector from object to light source. */
  176.     vsub(ldir, l->org, i.x);
  177.     ldist = veclen(ldir);
  178.     if (ldist < EPSILON)
  179.         continue;
  180.     svproduct(ldir, 1 / ldist, ldir);
  181.  
  182.     shadow_ray.dir = ldir;
  183.     if (l->radius != 0.0)
  184.         shadow_ray = sample_ray(shadow_ray, l->radius / ldist);
  185.  
  186.     /* Check if the light source is behind the object. */
  187.     ldotn = vdot(shadow_ray.dir, normal);
  188.     if (ldotn < EPSILON)
  189.         continue;
  190.  
  191.     if (shadow_test(shadow_ray, ldist, op, recursion))
  192.         continue;
  193.  
  194.  
  195.     /* Initialize factor. */
  196.     setcolor(factor, 0, 0, 0);
  197.  
  198.     /* Diffuse shading. */
  199.     if (color_length(tp->diffuse) > EPSILON)
  200.         if (tp->brilliance != 1.0)
  201.         factor = scolorproduct(pow(ldotn, tp->brilliance), tp->diffuse);
  202.         else
  203.         factor = scolorproduct(ldotn, tp->diffuse);
  204.  
  205.     /* Specular shading. */
  206.     if (color_length(tp->specular) > EPSILON) {
  207.  
  208.         /* Calculate the reflected vector. */
  209.         svproduct(refl, 2 * ldotn, normal);
  210.         vneg(tmpvector, shadow_ray.dir);
  211.         vadd(refl, tmpvector, refl);
  212.  
  213.         rdotv = -1 * vdot(refl, r.dir);
  214.         if (rdotv > EPSILON)
  215.         if ((tp->roughness != 1.0) && (tp->roughness > EPSILON))
  216.             factor = color_add(factor, scolorproduct(pow(rdotv, 1 / tp->roughness), tp->specular));
  217.         else
  218.             factor = color_add(factor, scolorproduct(rdotv, tp->specular));
  219.     }
  220.     if (l->attenuation_exp > EPSILON)
  221.         factor = scolorproduct(pow(ldist, -1 * l->attenuation_exp), factor);
  222.  
  223.     col = color_add(col, color_mul(factor, light_color(l, shadow_ray.pos)));
  224.     }
  225.  
  226.     return col;
  227. }
  228.  
  229. PRIVATE color
  230. microfacet(struct intersect i, struct texture_data *tp, struct ray r, int n, double imp)
  231. {
  232.     assert(FALSE);
  233. }
  234.