home *** CD-ROM | disk | FTP | other *** search
- /*
- * Shade.c -- the shading function
- *
- * (c) 1994 by Shawn McHorse <Zaphod@fcircus.sat.tx.us>
- *
- * Based on code by George Kyriazis and Han-Wen Nienhuys.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <math.h>
- #include "ray.h"
- #include "proto.h"
- #include "extern.h"
-
- PRIVATE color phong(struct intersect i, struct texture_data *tp, struct ray r, int n, double imp);
- PRIVATE color microfacet(struct intersect i, struct texture_data *tp, struct ray r, int n, double imp);
-
- PUBLIC color
- shade(struct intersect i, struct ray r, int recurse, double imp)
- {
- color col,
- tmpcol;
- object *op;
- vector refl;
- double c1 = 0.0,
- importance,
- nu,
- discr;
- struct texture_data t;
- struct ray reflected;
-
- /* Find the first object in the hierarchy with a texture. */
- for (op = i.q_ent.obj; op->text == NULL; op = op->daddy);
-
- /* Find texture at intersection point. */
- fill_texture(&t, op->text, i);
-
- /* Apply the local shading model. */
- switch (t.shadingtype) {
- case PHONG_SHADING:
- col = phong(i, &t, r, recurse, imp);
- break;
- #ifdef UNDEFINED
- case COOK:
- col = microfacet(i, &t, r, recurse, imp);
- break;
- #endif
- }
-
- /*
- * Don't bother with reflected and refracted rays if we're already as
- * deep as we can go.
- */
- if (recurse >= max_trace_level)
- return col;
-
- reflected.pos = i.x;
- reflected.mint = INFTY;
-
- importance = imp * color_length(t.refr_color);
- if (importance > depth_cutoff) {
- ior_depth++;
- if (i.q_ent.entering)
- global_ior[ior_depth] = t.index;
- else
- global_ior[ior_depth] = global_ior[ior_depth - 2];
-
- /* Calculate refracted vector. */
- c1 = -1 * vdot(r.dir, i.n);
- nu = global_ior[ior_depth] / global_ior[ior_depth - 1];
- discr = nu * nu - 1 + c1 * c1;
-
- /* Total Internal Reflection */
- if (discr < -EPSILON) {
- /* Calculate reflected vector. */
- svproduct(refl, 2 * c1, i.n);
- vadd(refl, r.dir, refl);
-
- /* Set up reflected ray. */
- ior_depth--;
- reflected.dir = refl;
- reflected.type = R_REFLECT;
-
- /*
- * we're reflecting and diffusing at the same time, so take
- * means
- */
- tmpdouble = (t.refl_diffuse + t.refr_diffuse) / 2.0;
- if (tmpdouble > EPSILON)
- reflected = sample_ray(reflected, tmpdouble);
-
- tmpcol = trace(reflected, recurse + 1, importance + imp * color_length(t.refl_color));
- return color_add(col, color_mul(tmpcol, color_add(t.refr_color, t.refl_color)));
- }
- if (discr < EPSILON)
- svproduct(refl, c1, i.n);
- else
- svproduct(refl, c1 - sqrt(discr), i.n);
- vadd(refl, r.dir, refl);
- svproduct(refl, 1 / nu, refl);
-
- /* Set up the refracted ray. */
- reflected.dir = refl;
- reflected.type = R_REFRACT;
- if (t.refr_diffuse > EPSILON)
- reflected = sample_ray(reflected, t.refr_diffuse);
- col = color_add(col, color_mul(t.refr_color, trace(reflected, recurse + 1, importance)));
- ior_depth--;
- }
- importance = imp * color_length(t.refl_color);
- if (importance > depth_cutoff) {
- /* Calculate reflected vector. */
- if (c1 == 0.0)
- c1 = -1 * vdot(r.dir, i.n);
- svproduct(refl, 2 * c1, i.n);
- vadd(refl, r.dir, refl);
-
- /* Set up the reflected ray. */
- reflected.dir = refl;
- reflected.type = R_REFLECT;
- reflected.mint = INFTY;
- if (t.refl_diffuse > EPSILON)
- reflected = sample_ray(reflected, t.refl_diffuse);
- col = color_add(col, color_mul(t.refl_color, trace(reflected, recurse + 1, importance)));
- }
- return col;
- }
-
- PRIVATE color
- phong(struct intersect i, struct texture_data *tp, struct ray r, int recursion, double imp)
- {
-
- object *op;
- color col,
- factor; /* factor to put influences of distance,
- * brilliance, etc. in */
- vector ldir,
- refl,
- normal;
- double ldist,
- ldotn,
- rdotv;
- struct light_data *l;
- struct ray shadow_ray;
-
- /* Start off with ambient light. */
- col = color_mul(ambient_light, tp->ambient);
-
- /* Set up the shadow ray data. */
- shadow_ray.type = R_SHADOW;
- shadow_ray.pos = i.x;
-
- /* the normal should be looking at us */
- if (vdot(i.n, r.dir) > 0)
- vneg(normal, i.n); /* flip it */
- else
- normal = i.n;
-
- /* Walk the light list. */
- for (op = first_light; op != NULL; op = op->next) {
- l = op->data.light;
-
- /* Construct a normalized vector from object to light source. */
- vsub(ldir, l->org, i.x);
- ldist = veclen(ldir);
- if (ldist < EPSILON)
- continue;
- svproduct(ldir, 1 / ldist, ldir);
-
- shadow_ray.dir = ldir;
- if (l->radius != 0.0)
- shadow_ray = sample_ray(shadow_ray, l->radius / ldist);
-
- /* Check if the light source is behind the object. */
- ldotn = vdot(shadow_ray.dir, normal);
- if (ldotn < EPSILON)
- continue;
-
- if (shadow_test(shadow_ray, ldist, op, recursion))
- continue;
-
-
- /* Initialize factor. */
- setcolor(factor, 0, 0, 0);
-
- /* Diffuse shading. */
- if (color_length(tp->diffuse) > EPSILON)
- if (tp->brilliance != 1.0)
- factor = scolorproduct(pow(ldotn, tp->brilliance), tp->diffuse);
- else
- factor = scolorproduct(ldotn, tp->diffuse);
-
- /* Specular shading. */
- if (color_length(tp->specular) > EPSILON) {
-
- /* Calculate the reflected vector. */
- svproduct(refl, 2 * ldotn, normal);
- vneg(tmpvector, shadow_ray.dir);
- vadd(refl, tmpvector, refl);
-
- rdotv = -1 * vdot(refl, r.dir);
- if (rdotv > EPSILON)
- if ((tp->roughness != 1.0) && (tp->roughness > EPSILON))
- factor = color_add(factor, scolorproduct(pow(rdotv, 1 / tp->roughness), tp->specular));
- else
- factor = color_add(factor, scolorproduct(rdotv, tp->specular));
- }
- if (l->attenuation_exp > EPSILON)
- factor = scolorproduct(pow(ldist, -1 * l->attenuation_exp), factor);
-
- col = color_add(col, color_mul(factor, light_color(l, shadow_ray.pos)));
- }
-
- return col;
- }
-
- PRIVATE color
- microfacet(struct intersect i, struct texture_data *tp, struct ray r, int n, double imp)
- {
- assert(FALSE);
- }
-