blob: 201e51797869f964309e53a51d6032c4f0c84e72 [file] [log] [blame]
/*************************************************************************/
/* */
/* 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);
}
}
}
}