| /*************************************************************************/ |
| /* */ |
| /* Copyright (c) 1994 Stanford University */ |
| /* */ |
| /* All rights reserved. */ |
| /* */ |
| /* Permission is given to use, copy, and modify this software for any */ |
| /* non-commercial purpose as long as this copyright notice is not */ |
| /* removed. All other uses, including redistribution in whole or in */ |
| /* part, are forbidden without prior written permission. */ |
| /* */ |
| /* This software is provided with absolutely no warranty and no */ |
| /* support. */ |
| /* */ |
| /*************************************************************************/ |
| |
| |
| /* |
| * NAME |
| * shade.c |
| * |
| * DESCRIPTION |
| * This file contains routines that shade a ray, both nonshadowed and |
| * shadowed. |
| * |
| * Generated secondary reflection and refractions rays are pushed onto |
| * the raytree stack. |
| */ |
| |
| |
| #include <stdio.h> |
| #include <math.h> |
| #include "rt.h" |
| |
| |
| |
| /* |
| * NAME |
| * SpecularDirection - compute reflected ray |
| * |
| * SYNOPSIS |
| * VOID SpecularDirection(R, N, I) |
| * POINT R; // Reflected ray. |
| * POINT N; // Normal. |
| * POINT I; // Incident ray. |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| |
| VOID SpecularDirection(R, N, I) |
| POINT R; |
| POINT N; |
| POINT I; |
| { |
| REAL I_dot_N; /* I*N */ |
| POINT N2; /* 2N */ |
| POINT vprime; /* Scale of I */ |
| |
| /* Turner's calculation from first paper. */ |
| |
| I_dot_N = VecDot(I,N); |
| I_dot_N = ABS(I_dot_N); |
| I_dot_N = 1.0/I_dot_N; |
| |
| VecScale(vprime, I_dot_N, I); |
| VecScale(N2, 2.0, N); |
| |
| VecAdd(R, vprime, N2); |
| VecNorm(R); |
| } |
| |
| |
| |
| /* |
| * NAME |
| * TransmissionDirection - calculate refracted ray |
| * |
| * SYNOPSIS |
| * BOOL TransmissionDirection(T, N, I, kn) |
| * POINT T; // Transmitted ray. |
| * POINT N; // Normal. |
| * POINT I; // Incident ray. |
| * REAL kn; // Index of refraction. |
| * |
| * RETURNS |
| * TRUE if the ray was transmitted, FALSE if the ray was blocked. |
| */ |
| |
| BOOL TransmissionDirection(T, N, I, kn) |
| POINT T; |
| POINT N; |
| POINT I; |
| REAL kn; |
| { |
| POINT vprime; /* Parameters in calculation. */ |
| POINT vplusn; |
| REAL I_dot_N; |
| REAL kf; |
| REAL vprime_sq; |
| REAL vplusn_sq; |
| |
| /* Turner's calculation from first paper. */ |
| |
| I_dot_N = VecDot(I,N); |
| I_dot_N = ABS(I_dot_N); |
| I_dot_N = 1.0/I_dot_N; |
| |
| VecScale(vprime, I_dot_N, I); |
| VecAdd(vplusn, vprime, N); |
| |
| vprime_sq = VecDot(vprime, vprime); |
| vplusn_sq = VecDot(vplusn, vplusn); |
| |
| kf = kn*kn*vprime_sq - vplusn_sq; |
| |
| if (kf > RAYEPS) |
| { |
| kf = 1.0/sqrt(kf); |
| |
| VecScale(vplusn, kf, vplusn); |
| VecSub(T, vplusn, N); |
| VecNorm(T); |
| } |
| else |
| return (FALSE); |
| |
| return (TRUE); |
| } |
| |
| |
| |
| /* |
| * NAME |
| * Shade - shade a ray |
| * |
| * SYNOPSIS |
| * VOID Shade(iP, N, ray, hit, pid) |
| * VEC3 iP; // Intersection point. |
| * VEC3 N; // Normal at intersection. |
| * RAY *ray; // Incident ray. |
| * IRECORD *hit; // Intersect info. |
| * INT pid; // Process id number. |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| |
| VOID Shade(iP, N, ray, hit, pid) |
| VEC3 iP; |
| VEC3 N; |
| RAY *ray; |
| IRECORD *hit; |
| INT pid; |
| { |
| VEC3 Lvec; /* Light vector. */ |
| VEC3 Hvec; /* Highlight vector. */ |
| VEC3 Evec; /* Eye vector. */ |
| RAY shad_ray; /* Shadow ray. */ |
| RAY secondary_ray; /* Secondary ray. */ |
| COLOR surfcol; /* Primitive surface color. */ |
| COLOR col; /* Ray color contribution. */ |
| REAL NdotL; /* Diffuse conritbution. */ |
| REAL Diff; /* Diffuse variable. */ |
| REAL NdotH; /* Highlight contribution. */ |
| REAL spec; /* Highlight variable. */ |
| OBJECT *po; /* Ptr to object. */ |
| SURF *s; /* Surface pointer. */ |
| INT i, j; /* Index variables. */ |
| REAL lightlen; /* Length of light vector. */ |
| REAL shadtrans; /* Shadow transmission. */ |
| LIGHT *lptr; /* Light pointer. */ |
| |
| /* Initialize primitive info and ray color. */ |
| |
| po = hit->pelem->parent; |
| s = po->surf; |
| VecCopy(surfcol, s->fcolor); |
| |
| /* Initialize color to ambient. */ |
| |
| col[0] = View.ambient[0] * surfcol[0]; |
| col[1] = View.ambient[1] * surfcol[1]; |
| col[2] = View.ambient[2] * surfcol[2]; |
| |
| /* Set shadow ray origin. */ |
| |
| VecCopy(shad_ray.P, iP); |
| VecNegate(Evec, ray->D); |
| |
| /* Account for all lights. */ |
| |
| lptr = lights; |
| for (i = 0; i < nlights; i++) |
| { |
| VecSub(Lvec, lptr->pos, iP); |
| lightlen = VecLen(Lvec); |
| VecNorm(Lvec); |
| VecCopy(shad_ray.D, Lvec); |
| |
| LOCK(gm->ridlock); |
| shad_ray.id = gm->rid++; |
| UNLOCK(gm->ridlock); |
| |
| NdotL = VecDot(N, Lvec); |
| |
| if (NdotL > 0.0) |
| { |
| /* Test to see if point shadowed. */ |
| |
| if (View.shad && !lptr->shadow) |
| { |
| switch (TraversalType) |
| { |
| case TT_LIST: |
| shadtrans = ShadowIntersect(&shad_ray, lightlen, hit->pelem); |
| break; |
| |
| case TT_HUG: |
| shadtrans = HuniformShadowIntersect(&shad_ray, lightlen, hit->pelem, pid); |
| break; |
| } |
| } |
| else |
| shadtrans = 1.0; |
| |
| /* Compute non-shadowed shades. */ |
| |
| if (shadtrans > 0.0) |
| { |
| Diff = po->surf->kdiff * NdotL * shadtrans; |
| |
| col[0] += surfcol[0] * lptr->col[0] * Diff; |
| col[1] += surfcol[1] * lptr->col[1] * Diff; |
| col[2] += surfcol[2] * lptr->col[2] * Diff; |
| |
| /* Add specular. */ |
| |
| if (s->kspec > 0.0) |
| { |
| VecAdd(Hvec,Lvec,Evec); |
| VecNorm(Hvec); |
| NdotH = VecDot(N,Hvec); |
| |
| if (NdotH > 0.0) |
| { |
| spec = pow(NdotH, s->kspecn); |
| spec *= s->kspec; |
| |
| col[0] += lptr->col[0]*spec; |
| col[1] += lptr->col[1]*spec; |
| col[2] += lptr->col[2]*spec; |
| } |
| } |
| } |
| } |
| |
| lptr = lptr->next; |
| } |
| |
| /* Add color to pixel frame buffer. */ |
| |
| VecScale(col, ray->weight, col); |
| AddPixelColor(col, ray->x, ray->y); |
| |
| /* Recurse if not at maximum level. */ |
| |
| if ((ray->level) + 1 < Display.maxlevel) |
| { |
| VecCopy(secondary_ray.P, iP); |
| |
| /* Specular. */ |
| secondary_ray.weight = po->surf->kspec * ray->weight; |
| |
| if (secondary_ray.weight > Display.minweight) |
| { |
| SpecularDirection(secondary_ray.D, N, ray->D); |
| secondary_ray.level = ray->level + 1; |
| |
| LOCK(gm->ridlock); |
| secondary_ray.id = gm->rid++; |
| UNLOCK(gm->ridlock); |
| |
| secondary_ray.x = ray->x; |
| secondary_ray.y = ray->y; |
| |
| PushRayTreeStack(&secondary_ray, pid); |
| |
| } |
| |
| /* Transmission. */ |
| secondary_ray.weight = po->surf->ktran * ray->weight; |
| |
| if (secondary_ray.weight > Display.minweight) |
| { |
| if (TransmissionDirection(secondary_ray.D, N, ray->D, po->surf->refrindex)) |
| { |
| secondary_ray.level = ray->level + 1; |
| |
| LOCK(gm->ridlock); |
| secondary_ray.id = gm->rid++; |
| UNLOCK(gm->ridlock); |
| |
| secondary_ray.x = ray->x; |
| secondary_ray.y = ray->y; |
| |
| PushRayTreeStack(&secondary_ray, pid); |
| |
| } |
| } |
| } |
| } |
| |