home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Archive Magazine 1996
/
ARCHIVE_96.iso
/
discs
/
shareware
/
share_43
/
source
/
c
/
LIGHTING
< prev
next >
Wrap
Text File
|
1991-08-22
|
20KB
|
597 lines
/*****************************************************************************
*
* lighting.c
*
* from DKBTrace (c) 1990 David Buck
*
* This module calculates lighting properties like ambient, diffuse, specular,
* reflection, refraction, etc.
*
*
* This software is freely distributable. The source and/or object code may be
* copied or uploaded to communications services so long as this notice remains
* at the top of each file. If any changes are made to the program, you must
* clearly indicate in the documentation and in the programs startup message
* who it was who made the changes. The documentation should also describe what
* those changes were. This software may not be included in whole or in
* part into any commercial package without the express written consent of the
* author. It may, however, be included in other public domain or freely
* distributed software so long as the proper credit for the software is given.
*
* This software is provided as is without any guarantees or warranty. Although
* the author has attempted to find and correct any bugs in the software, he
* is not responsible for any damage caused by the use of the software. The
* author is under no obligation to provide service, corrections, or upgrades
* to this package.
*
* Despite all the legal stuff above, if you do find bugs, I would like to hear
* about them. Also, if you have any comments or questions, you may contact me
* at the following address:
*
* David Buck
* 22C Sonnet Cres.
* Nepean Ontario
* Canada, K2H 8W7
*
* I can also be reached on the following bulleton boards:
*
* ATX (613) 526-4141
* OMX (613) 731-3419
* Mystic (613) 731-0088 or (613) 731-6698
*
* Fidonet: 1:163/109.9
* Internet: David_Buck@Carleton.CA
*
* IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
*
* Lattice BBS (708) 916-1200
* The Information Exchange BBS (708) 945-5575
* Stillwaters BBS (708) 403-2826
*
*****************************************************************************/
#include "frame.h"
#include "vector.h"
#include "dkbproto.h"
extern int Trace_Level;
extern FRAME Frame;
extern unsigned long Options;
extern int Quality;
extern long Shadow_Ray_Tests, Shadow_Rays_Succeeded;
extern long Reflected_Rays_Traced, Refracted_Rays_Traced;
extern long Transmitted_Rays_Traced;
#define Small_Tolerance 0.001
void Colour_At (Colour, Object, Intersection_Point)
COLOUR *Colour;
OBJECT *Object;
VECTOR *Intersection_Point;
{
register DBL x, y, z;
VECTOR Transformed_Point;
if (Object -> Object_Texture->Texture_Transformation) {
MInverseTransformVector (&Transformed_Point,
Intersection_Point,
Object -> Object_Texture->Texture_Transformation);
}
else
Transformed_Point = *Intersection_Point;
x = Transformed_Point.x;
y = Transformed_Point.y;
z = Transformed_Point.z;
switch (Object -> Object_Texture->Texture_Number) {
case BOZO_TEXTURE:
Bozo (x, y, z, Object, Colour);
break;
case MARBLE_TEXTURE:
marble (x, y, z, Object, Colour);
break;
case WOOD_TEXTURE:
wood (x, y, z, Object, Colour);
break;
case CHECKER_TEXTURE:
checker (x, y, z, Object, Colour);
break;
case SPOTTED_TEXTURE:
spotted (x, y, z, Object, Colour);
break;
case AGATE_TEXTURE:
agate (x, y, z, Object, Colour);
break;
case GRANITE_TEXTURE:
granite (x, y, z, Object, Colour);
break;
case GRADIENT_TEXTURE:
gradient (x, y, z, Object, Colour);
break;
case IMAGEMAP_TEXTURE:
texture_map (x, y, z, Object, Colour);
break;
default:
*Colour = Object -> Object_Colour;
break;
}
}
void Perturb_Normal(New_Normal, Object, Intersection_Point, Surface_Normal)
VECTOR *New_Normal, *Intersection_Point, *Surface_Normal;
OBJECT *Object;
{
VECTOR Transformed_Point;
register DBL x, y, z;
if (Object -> Object_Texture->Bump_Number == NO_BUMPS) {
*New_Normal = *Surface_Normal;
return;
}
if (Object -> Object_Texture->Texture_Transformation)
MInverseTransformVector (&Transformed_Point,
Intersection_Point,
Object -> Object_Texture->Texture_Transformation);
else
Transformed_Point = *Intersection_Point;
x = Transformed_Point.x;
y = Transformed_Point.y;
z = Transformed_Point.z;
switch (Object -> Object_Texture->Bump_Number) {
case NO_BUMPS: break;
case WAVES: waves (x, y, z, Object, New_Normal);
break;
case RIPPLES: ripples (x, y, z, Object, New_Normal);
break;
case WRINKLES: wrinkles (x, y, z, Object, New_Normal);
break;
case BUMPS: bumps (x, y, z, Object, New_Normal);
break;
case DENTS: dents (x, y, z, Object, New_Normal);
break;
}
return;
}
void Ambient (Object, Intersection_Point, Surface_Colour, Colour)
OBJECT *Object;
VECTOR *Intersection_Point;
COLOUR *Surface_Colour;
COLOUR *Colour;
{
DBL t;
if (Object -> Object_Texture -> Object_Ambient == 0.0)
return;
t = 1.0 - Surface_Colour->Alpha;
Colour->Red += Surface_Colour->Red * t * Object->Object_Texture->Object_Ambient;
Colour->Green += Surface_Colour->Green * t * Object->Object_Texture->Object_Ambient;
Colour->Blue += Surface_Colour->Blue * t * Object->Object_Texture->Object_Ambient;
return;
}
void Diffuse (Object, Intersection_Point, Eye, Surface_Normal, Surface_Colour, Colour)
OBJECT *Object;
VECTOR *Intersection_Point, *Surface_Normal;
COLOUR *Surface_Colour;
COLOUR *Colour;
RAY *Eye;
{
DBL Light_Source_Depth;
RAY Light_Source_Ray;
OBJECT *Light_Source, *Blocking_Object;
int Intersection_Found;
INTERSECTION *Local_Intersection;
VECTOR REye;
COLOUR Light_Colour, Blocking_Colour;
PRIOQ *Local_Queue;
if ((Object -> Object_Texture -> Object_Diffuse == 0.0) &&
(Object -> Object_Texture -> Object_Specular == 0.0) &&
(Object -> Object_Texture -> Object_Phong == 0.0))
return;
if (Object -> Object_Texture -> Object_Specular != 0.0)
{
REye.x = -Eye->Direction.x;
REye.y = -Eye->Direction.y;
REye.z = -Eye->Direction.z;
}
Local_Queue = pq_new (128);
for (Light_Source = Frame.Light_Sources ;
Light_Source != NULL;
Light_Source = Light_Source -> Next_Light_Source)
{
Light_Colour = Light_Source->Object_Colour;
Intersection_Found = FALSE;
do_light(Light_Source, &Light_Source_Depth, &Light_Source_Ray, Intersection_Point);
/* What objects does this ray intersect? */
if (Quality > 3)
for (Blocking_Object = Frame.Objects ;
Blocking_Object != NULL ;
Blocking_Object = Blocking_Object -> Next_Object) {
Shadow_Ray_Tests++;
if (Blocking_Object == Light_Source)
continue;
for (All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Queue) ;
(Local_Intersection = pq_get_highest(Local_Queue)) != NULL ;
pq_delete_highest(Local_Queue)) {
if ((Local_Intersection -> Depth < Light_Source_Depth-Small_Tolerance)
&& (Local_Intersection -> Depth > Small_Tolerance))
{
Shadow_Rays_Succeeded++;
if (Blocking_Object->Transparency)
do_blocking(Blocking_Object, &Blocking_Colour, Local_Intersection, &Light_Colour);
else {
Intersection_Found = TRUE;
break;
}
}
}
if (Intersection_Found) {
while (pq_get_highest(Local_Queue))
pq_delete_highest(Local_Queue);
break;
}
}
if (!Intersection_Found)
{
if (Object->Object_Texture->Object_Phong >0.0) /*Phong Spec. Hilite*/
do_phong(Object, &Light_Source_Ray, Eye, Surface_Normal, Colour, &Light_Colour);
if (Object->Object_Texture->Object_Specular >0.0) /*specular hilite*/
do_specular(Object,&Light_Source_Ray,&REye,Surface_Normal,Colour, &Light_Colour);
if (Object->Object_Texture->Object_Diffuse > 0.0) /*normal diffuse */
do_diffuse(Object, &Light_Source_Ray, Surface_Normal, Colour, &Light_Colour, Surface_Colour);
}
}
pq_free (Local_Queue);
return;
}
void do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Intersection_Point)
OBJECT *Light_Source;
DBL *Light_Source_Depth;
RAY *Light_Source_Ray;
VECTOR *Intersection_Point;
{
Light_Source_Ray->Initial = *Intersection_Point;
Light_Source_Ray->Quadric_Constants_Cached = FALSE;
VSub (Light_Source_Ray->Direction,
Light_Source->Object_Center,
*Intersection_Point);
VLength (*Light_Source_Depth, Light_Source_Ray->Direction);
VScale (Light_Source_Ray->Direction, Light_Source_Ray->Direction,
1.0/(*Light_Source_Depth));
return;
}
void do_blocking(Blocking_Object, Blocking_Colour, Local_Intersection, Light_Colour)
OBJECT *Blocking_Object;
COLOUR *Blocking_Colour, *Light_Colour;
INTERSECTION *Local_Intersection;
{
Make_Colour(Blocking_Colour, 0.0, 0.0, 0.0);
Colour_At(Blocking_Colour,Blocking_Object,&Local_Intersection->Point);
Light_Colour->Red *=
Blocking_Colour->Red * Blocking_Colour->Alpha;
Light_Colour->Green *=
Blocking_Colour->Green * Blocking_Colour->Alpha;
Light_Colour->Blue *=
Blocking_Colour->Blue * Blocking_Colour->Alpha;
return;
}
void do_phong(Object, Light_Source_Ray, Eye, Surface_Normal, Colour, Light_Colour)
OBJECT *Object;
RAY *Light_Source_Ray, *Eye;
VECTOR *Surface_Normal;
COLOUR *Colour, *Light_Colour;
{
DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity;
VECTOR Local_Normal, Normal_Projection, Reflect_Direction;
VDot(Cos_Angle_Of_Incidence, Eye->Direction, *Surface_Normal);
if (Cos_Angle_Of_Incidence < 0.0)
{
Local_Normal = *Surface_Normal;
Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
}
else
VScale (Local_Normal, *Surface_Normal, -1.0);
VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
VScale (Normal_Projection, Normal_Projection, 2.0);
VAdd (Reflect_Direction, Eye->Direction, Normal_Projection);
VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
VLength (Normal_Length, Light_Source_Ray->Direction);
Cos_Angle_Of_Incidence /= Normal_Length;
if (Cos_Angle_Of_Incidence < 0.0)
Cos_Angle_Of_Incidence = 0;
if (Object -> Object_Texture -> Object_PhongSize != 1.0)
Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_PhongSize);
else
Intensity = Cos_Angle_Of_Incidence;
Intensity *= Object -> Object_Texture -> Object_Phong;
Colour->Red+=Intensity*(Light_Colour->Red);
Colour->Green+=Intensity*(Light_Colour->Green);
Colour->Blue+=Intensity*(Light_Colour->Blue);
return;
}
void do_specular(Object, Light_Source_Ray, REye, Surface_Normal, Colour, Light_Colour)
OBJECT *Object;
RAY *Light_Source_Ray;
VECTOR *Surface_Normal, *REye;
COLOUR *Colour, *Light_Colour;
{
DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity, Halfway_Length;
VECTOR Halfway;
VHalf (Halfway, *REye, Light_Source_Ray->Direction);
VLength (Normal_Length, *Surface_Normal);
VLength (Halfway_Length, Halfway);
VDot (Cos_Angle_Of_Incidence, Halfway, *Surface_Normal);
Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
if (Cos_Angle_Of_Incidence < 0.0)
Cos_Angle_Of_Incidence = 0;
if (Object -> Object_Texture -> Object_Roughness != 1.0)
Intensity = pow(Cos_Angle_Of_Incidence, 1 / Object->Object_Texture->Object_Roughness);
else
Intensity = Cos_Angle_Of_Incidence;
Intensity *= Object->Object_Texture->Object_Specular;
Colour->Red+=Intensity* (Light_Colour->Red);
Colour->Green+=Intensity* (Light_Colour->Green);
Colour->Blue+=Intensity* (Light_Colour->Blue);
return;
}
void do_diffuse(Object, Light_Source_Ray, Surface_Normal, Colour, Light_Colour, Surface_Colour)
OBJECT *Object;
RAY *Light_Source_Ray;
VECTOR *Surface_Normal;
COLOUR *Colour, *Light_Colour, *Surface_Colour;
{
DBL Cos_Angle_Of_Incidence, Intensity, RandomNumber;
VDot (Cos_Angle_Of_Incidence, *Surface_Normal, Light_Source_Ray->Direction);
if (Cos_Angle_Of_Incidence < 0.0)
Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
if (Object -> Object_Texture -> Object_Brilliance != 1.0)
Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_Brilliance);
else
Intensity = Cos_Angle_Of_Incidence;
Intensity *= Object -> Object_Texture -> Object_Diffuse;
RandomNumber = (rand()&0x7FFF)/(DBL) 0x7FFF;
Intensity -= RandomNumber * Object->Object_Texture->Texture_Randomness;
Intensity *= 1.0 - Surface_Colour->Alpha;
Colour->Red += Intensity * (Surface_Colour->Red) * (Light_Colour->Red);
Colour->Green += Intensity * (Surface_Colour->Green) * (Light_Colour->Green);
Colour->Blue += Intensity * (Surface_Colour->Blue) * (Light_Colour->Blue);
return;
}
void Transmit (Object, Intersection_Point, Ray, Surface_Normal, Surface_Colour, Colour)
OBJECT *Object;
VECTOR *Intersection_Point;
RAY *Ray;
VECTOR *Surface_Normal;
COLOUR *Surface_Colour;
COLOUR *Colour;
{
RAY New_Ray;
COLOUR Temp_Colour;
if (Surface_Colour->Alpha == 0.0)
return;
New_Ray.Initial = *Intersection_Point;
New_Ray.Direction = Ray->Direction;
Copy_Ray_Containers (&New_Ray, Ray);
Trace_Level++;
Transmitted_Rays_Traced++;
Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
New_Ray.Quadric_Constants_Cached = FALSE;
Trace (&New_Ray, &Temp_Colour);
Trace_Level--;
(Colour -> Red) += Temp_Colour.Red * Surface_Colour->Red * Surface_Colour->Alpha;
(Colour -> Green) += Temp_Colour.Green * Surface_Colour->Green * Surface_Colour->Alpha;
(Colour -> Blue) += Temp_Colour.Blue * Surface_Colour->Blue * Surface_Colour->Alpha;
}
void Reflect (Object, Intersection_Point, Ray, Surface_Normal, Colour)
OBJECT *Object;
VECTOR *Intersection_Point;
RAY *Ray;
VECTOR *Surface_Normal;
COLOUR *Colour;
{
RAY New_Ray;
COLOUR Temp_Colour;
VECTOR Local_Normal;
VECTOR Normal_Projection;
register DBL Normal_Component;
if (Object -> Object_Texture -> Object_Reflection != 0.0)
{
Reflected_Rays_Traced++;
VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
if (Normal_Component < 0.0) {
Local_Normal = *Surface_Normal;
Normal_Component *= -1.0;
}
else
VScale (Local_Normal, *Surface_Normal, -1.0);
VScale (Normal_Projection, Local_Normal, Normal_Component);
VScale (Normal_Projection, Normal_Projection, 2.0);
VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
New_Ray.Initial = *Intersection_Point;
Copy_Ray_Containers (&New_Ray, Ray);
Trace_Level++;
Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
New_Ray.Quadric_Constants_Cached = FALSE;
Trace (&New_Ray, &Temp_Colour);
Trace_Level--;
(Colour -> Red) += (Temp_Colour.Red)
* (Object -> Object_Texture -> Object_Reflection);
(Colour -> Green) += (Temp_Colour.Green)
* (Object -> Object_Texture -> Object_Reflection);
(Colour -> Blue) += (Temp_Colour.Blue)
* (Object -> Object_Texture -> Object_Reflection);
}
}
void Refract (Object, Intersection_Point, Ray, Surface_Normal, Colour)
OBJECT *Object;
VECTOR *Intersection_Point;
RAY *Ray;
VECTOR *Surface_Normal;
COLOUR *Colour;
{
RAY New_Ray;
COLOUR Temp_Colour;
VECTOR Local_Normal;
VECTOR Normal_Projection;
register DBL Normal_Component, Temp_IOR;
if (Object -> Object_Texture -> Object_Refraction != 0.0)
{
Refracted_Rays_Traced++;
VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
if (Normal_Component >= 0.0)
{
VScale (Local_Normal, *Surface_Normal, -1.0);
}
else
{
Local_Normal.x = Surface_Normal -> x;
Local_Normal.y = Surface_Normal -> y;
Local_Normal.z = Surface_Normal -> z;
Normal_Component *= -1.0;
}
VScale (Normal_Projection, Local_Normal, Normal_Component);
VAdd (Normal_Projection, Normal_Projection, Ray -> Direction);
Copy_Ray_Containers (&New_Ray, Ray);
if (Ray -> Containing_Index == -1)
{
/* The ray is entering from the atmosphere */
Ray_Enter (&New_Ray, Object);
VScale (Normal_Projection, Normal_Projection,
(Frame.Atmosphere_IOR)/(Object -> Object_Texture -> Object_Index_Of_Refraction));
}
else
{
/* The ray is currently inside an object */
if (New_Ray.Containing_Objects [New_Ray.Containing_Index] == Object)
{
/* The ray is leaving the current object */
Ray_Exit (&New_Ray);
if (New_Ray.Containing_Index == -1)
/* The ray is leaving into the atmosphere */
Temp_IOR = Frame.Atmosphere_IOR;
else
/* The ray is leaving into another object */
Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
VScale (Normal_Projection, Normal_Projection,
(Object -> Object_Texture -> Object_Index_Of_Refraction) / Temp_IOR);
}
else
{
/* The ray is entering a new object */
Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
Ray_Enter (&New_Ray, Object);
VScale (Normal_Projection, Normal_Projection,
Temp_IOR/(Object -> Object_Texture -> Object_Index_Of_Refraction));
}
}
VScale (Local_Normal, Local_Normal, -1.0);
VAdd (New_Ray.Direction, Local_Normal, Normal_Projection);
VNormalize (New_Ray.Direction, New_Ray.Direction);
New_Ray.Initial = *Intersection_Point;
Trace_Level++;
Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
New_Ray.Quadric_Constants_Cached = FALSE;
Trace (&New_Ray, &Temp_Colour);
Trace_Level--;
(Colour -> Red) += (Temp_Colour.Red)
* (Object -> Object_Texture -> Object_Refraction);
(Colour -> Green) += (Temp_Colour.Green)
* (Object -> Object_Texture -> Object_Refraction);
(Colour -> Blue) += (Temp_Colour.Blue)
* (Object -> Object_Texture -> Object_Refraction);
}
}
void Fog (Distance, Fog_Colour, Fog_Distance, Colour)
DBL Distance, Fog_Distance;
COLOUR *Fog_Colour, *Colour;
{
DBL Fog_Factor, Fog_Factor_Inverse;
Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
Fog_Factor_Inverse = 1.0 - Fog_Factor;
Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
}