/************* * DESCRIPTION: Calculate direction of refracted ray using Heckbert's formula. * Returns TRUE if a total internal reflection occurs. * INPUT: dir direction vector * index index of refraction * norm surface normal * OUTPUT: TRUE if TIR occurs, else FALSE *************/ static BOOL Refract(VECTOR *newdir, float index, VECTOR *norm, float cos1) { float cos2, k; VECTOR nrm, dir; if (cos1 < 0.f) { // Hit the 'backside' of a surface -- flip the normal. nrm.x = -norm->x; nrm.y = -norm->y; nrm.z = -norm->z; cos1 = -cos1; } else { nrm = *norm; } cos2 = 1.f - index*index*(1. - cos1*cos1); if (cos2 < 0.f) return TRUE; // Total internal reflection k = - sqrt((double)cos2) + index * cos1; SetVector(&dir, 0.f, 0.f, 1.f); VecComb(index, &dir, k, &nrm, newdir); return FALSE; }
/************* * DESCRIPTION: Adjust the initial ray to account for an aperture and a focal * distance. The ray argument is assumed to be an initial ray, and * always reset to the eye point. It is assumed to be unit length. * INPUT: ray pointer to ray structure * world pointer to world structure * OUTPUT: none *************/ void CAMERA::FocusBlurRay(RAY *ray, WORLD *world) { VECTOR circle_point, aperture_inc; /* * Find a point on a unit circle and scale by aperture size. * This simulates rays passing thru different parts of the aperture. * Treat the point as a vector and rotate it so the circle lies * in the plane of the screen. Add the aperture increment to the * starting position of the ray. Stretch the ray to be focaldist * in length. Subtract the aperture increment from the end of the * long ray. This insures that the ray heads toward a point at * the specified focus distance, so that point will be in focus. * Normalize the ray, and that's it. Really. */ world->UnitCirclePoint(&circle_point, ray->sample); VecComb(aperture * circle_point.x, &scrni, aperture * circle_point.y, &scrnj, &aperture_inc); VecAdd(&aperture_inc, &pos, &(ray->start)); VecScale(focaldist, &ray->dir, &(ray->dir)); VecSub(&ray->dir, &aperture_inc, &(ray->dir)); VecNormalizeNoRet(&ray->dir); }
/************* * DESCRIPTION: Calculate direction of refracted ray using Heckbert's formula. * Returns TRUE if a total internal reflection occurs. * INPUT: dir direction vector * index index of refraction * I * N * cos1 angle between ray and normal * OUTPUT: TRUE if TIR occurs, else FALSE *************/ BOOL Refract(VECTOR *dir, float index, const VECTOR *I, VECTOR *N, float cos1) { float cos2, k; VECTOR nrm; if (cos1 < 0.f) { // Hit the 'backside' of a surface -- flip the normal. nrm.x = -N->x; nrm.y = -N->y; nrm.z = -N->z; cos1 = -cos1; } else { nrm = *N; } cos2 = (float)(1.f - index*index*(1.f - cos1*cos1)); if (cos2 < 0.f) return TRUE; // Total internal reflection k = (float)(-sqrt((double)cos2) + index * cos1); VecComb(index, I, k, &nrm, dir); return FALSE; }
/* * Compute intensity ('color') of extended light source 'lp' from 'pos'. */ static int ExtendedIntens( LightRef lr, Color *lcolor, ShadowCache *cache, Ray *ray, Float /*dist*/, int noshadow, Color *color) { Extended *lp = (Extended*)lr; Float jit, vpos, upos, lightdist; Ray newray; Vector Uaxis, Vaxis, ldir; if (noshadow) { *color = *lcolor; return TRUE; } newray = *ray; /* * Determinte two orthoganal vectors that lay in the plane * whose normal is defined by the vector from the center * of the light source to the point of intersection and * passes through the center of the light source. */ VecSub(lp->pos, ray->pos, &ldir); VecCoordSys(&ldir, &Uaxis, &Vaxis); jit = 2. * lp->radius * Sampling.spacing; /* * Sample a single point, determined by SampleNumber, * on the extended source. */ vpos = -lp->radius + (ray->sample % Sampling.sidesamples)*jit; upos = -lp->radius + (ray->sample / Sampling.sidesamples)*jit; vpos += nrand() * jit; upos += nrand() * jit; VecComb(upos, Uaxis, vpos, Vaxis, &newray.dir); VecAdd(ldir, newray.dir, &newray.dir); lightdist = VecNormalize(&newray.dir); return !Shadowed(color, lcolor, cache, &newray, lightdist, noshadow); }