home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 2 / LSD and 17bit Compendium Deluxe - Volume II.iso / a / prog / cprog / illum.lha / illum_mod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-10-21  |  23.0 KB  |  683 lines

  1. /* ****************************************************************
  2.  *                         illum_mod.c
  3.  * ****************************************************************
  4.  *  MODULE PURPOSE:
  5.  *      This module contains the source code for the illumination
  6.  *      models discussed for in Section 4.2, Incremental Shading,
  7.  *      Empirical Models, and in Section 4.3, Ray Tracing,
  8.  *      Transitional Models.
  9.  *
  10.  *  MODULE CONTENTS:
  11.  *      IM_init         - initialize the illumination models
  12.  *      IM_bouknight    - Bouknight (1970) illumination model
  13.  *      IM_phong        - Phong (1975) illumination model
  14.  *      IM_blinn        - Blinn (1976) illumination model
  15.  *      IM_whitted      - Whitted (1980) illumination model
  16.  *      IM_hall         - Hall (1983) illumination model
  17.  *      IM_exit         - finish with the illumination models
  18.  *
  19.  *  NOTES:
  20.  *      > The illumination model is called once a
  21.  *          point on a surface has been identified and the list
  22.  *          of illuminating light sources has been generated.
  23.  *
  24.  *      > There exists a routine that the illumination models can
  25.  *          call to get a color from any direction.  Specifically
  26.  *          this is used for inquiring about the reflected or
  27.  *          transmitted directions in the ray tracing models.
  28.  *          This routine is passed the view vector for which the
  29.  *          color is required.
  30.  *
  31.  *      > a common calling convention is used for ease in
  32.  *          interchanging the illumination model routines.  Each
  33.  *          routine is passed the location and orientation of the
  34.  *          surface, a view vector, an interface material, a
  35.  *          description of the lighting, and an array to receive
  36.  *          the computed color.
  37.  *
  38.  *          The orientation of the surface is given by the surface
  39.  *          normal which is ALWAYS directed to the 'outside' or
  40.  *          reflected side of the material.
  41.  *
  42.  *          The view vector is specified by start position and
  43.  *          direction vector.  During visibility computations the
  44.  *          view vector is typically directed towards the surface.
  45.  *          The direction cosines MUST be negated prior to calling
  46.  *          the illumination model for consistency with the vector
  47.  *          conventions used.
  48.  *
  49.  *          See 'illum_mod.h' for material details.
  50.  *
  51.  *          The light vector is a list of pointers to ILLUM_LGT
  52.  *          structures terminated by a NULL pointer.  The first
  53.  *          entry is taken as the ambient illumination.  Only
  54.  *          light that is incident from the air side of a material
  55.  *          can provide illumination.
  56.  *
  57.  *      > These models assume that the material structure is
  58.  *          correctly loaded and that the surface is facing the
  59.  *          viewer (N.V > 0) for illumination models that do not
  60.  *          consider transparency.
  61.  */
  62. #include <stdio.h>
  63. #include <math.h>
  64. #include "illum_mod.h"
  65. #include "F.h"
  66.  
  67. static int      num_samples = 0;
  68. static int      (*get_color)() = NULL;
  69. static double   *Fr_buffer = NULL;
  70. static double   *Ft_buffer = NULL;
  71.  
  72. /* ****************************************************************
  73.  * int IM_init (num_clr_samples, get_clr_routine)
  74.  *  int     num_clr_samples         (in) - number of color samples
  75.  *  int     (*get_clr_routine)()    (in) - routine to call to get
  76.  *                                    the color from some direction
  77.  *
  78.  * Initializes the illumination model routine set, returns TRUE
  79.  *  if successful and FALSE upon failure.
  80.  */
  81. IM_init (num_clr_samples, get_clr_routine)
  82. int     num_clr_samples, (*get_clr_routine)();
  83. {   char    *malloc();
  84.     if (((num_samples = num_clr_samples) <= 0) ||
  85.       ((Fr_buffer = (double *)malloc((unsigned)(num_samples *
  86.         sizeof(double)))) == NULL) ||
  87.       ((Ft_buffer = (double *)malloc((unsigned)(num_samples *
  88.         sizeof(double)))) == NULL)) {
  89.     (void)IM_exit();
  90.     return FALSE;
  91.     }
  92.     get_color = get_clr_routine;
  93.     return TRUE;
  94. }
  95.  
  96. /* ****************************************************************
  97.  * double *IM_bouknight (surface, V, matl, lgts, color)
  98.  *  LINE        *surface    (in)  - surface for color computation
  99.  *  LINE        *V          (in)  - view vector
  100.  *  ILLUM_MATL  *matl       (in)  - material properties
  101.  *  ILLUM_LGT   **lgts      (in)  - illuminating sources
  102.  *  double      *color      (mod) - array to receive the color
  103.  *
  104.  * Evaluates the color using the Bouknight (1970) illumination
  105.  *  model as described in Eq.(\*(sE).  Returns 'color' upon
  106.  *  success and NULL upon failure.
  107.  */
  108. double *IM_bouknight (surface, V, matl, lgts, color)
  109. LINE        *surface, *V;
  110. ILLUM_MATL  *matl;
  111. ILLUM_LGT   **lgts;
  112. double      *color;
  113. {   int         ct;
  114.     double      N_dot_L;
  115.     LINE        L;
  116.  
  117.     /* load the ambient illumination */
  118.     for (ct=0; ct<num_samples; ct++) {
  119.       color[ct] = matl->Ka_scale * matl->Ka_spectral[ct] *
  120.     (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  121.     }
  122.     lgts++;
  123.  
  124.     /* load the diffuse component of the illumination.  Loop
  125.      *  through the lights and compute (N.L).  If it is positive
  126.      *  then the surface is illuminated.
  127.      */
  128.     while (*lgts != NULL) {
  129.       if ((geo_line(&(surface->start),&((*lgts)->center),&L) > 0)
  130.       && ((N_dot_L=geo_dot(&(surface->dir),&(L.dir))) > 0)) {
  131.  
  132.     /* The surface is illuminated by this light.  Loop through
  133.      *  the color samples and sum the diffuse contribution for
  134.      *  this light to the the color.
  135.      */
  136.     for (ct=0; ct<num_samples; ct++) {
  137.       color[ct] += matl->Kd_scale * matl->Kd_spectral[ct]
  138.         * N_dot_L * (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  139.     }
  140.       }
  141.       lgts++;
  142.     }
  143.  
  144.     return color;
  145. }
  146.  
  147. /* ****************************************************************
  148.  * double *IM_phong (surface, V, matl, lgts, color)
  149.  *  LINE        *surface    (in)  - surface for color computation
  150.  *  LINE        *V          (in)  - view vector
  151.  *  ILLUM_MATL  *matl       (in)  - material properties
  152.  *  ILLUM_LGT   **lgts      (in)  - illuminating sources
  153.  *  double      *color      (mod) - array to receive the color
  154.  *
  155.  * Evaluates the color using the Phong (1975) illumination
  156.  *  model as described in Eq.(\*(rU).  Returns 'color' upon
  157.  *  success and NULL upon failure.
  158.  *
  159.  * The actual Phong model results when the microfacet distribution
  160.  *  D_phong() is used, and matl->Ks_spectral is the identity
  161.  *  material.
  162.  *
  163.  * Using the microfacet distribution D_blinn() gives Blinn's
  164.  *  interpretation of the Phong model per Eq.(\*(rI).
  165.  */
  166. double *IM_phong (surface, V, matl, lgts, color)
  167. LINE        *surface, *V;
  168. ILLUM_MATL  *matl;
  169. ILLUM_LGT   **lgts;
  170. double      *color;
  171. {   int         ct;
  172.     double      N_dot_L, D;
  173.     LINE        L;
  174.  
  175.     /* load the ambient illumination */
  176.     for (ct=0; ct<num_samples; ct++) {
  177.       color[ct] = matl->Ka_scale * matl->Ka_spectral[ct] *
  178.     (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  179.     }
  180.     lgts++;
  181.  
  182.     /* load the diffuse and specular illumination components.
  183.      *  Loop through the lights and compute (N.L).  If it is
  184.      *  positive then the surface is illuminated.
  185.      */
  186.     while (*lgts != NULL) {
  187.       if ((geo_line(&(surface->start),&((*lgts)->center),&L) > 0)
  188.       && ((N_dot_L=geo_dot(&(surface->dir),&(L.dir))) > 0)) {
  189.  
  190.     /* The surface is illuminated.  Compute the microfacet
  191.      *  distribution function.
  192.      */
  193.     D = (*(matl->D))(&(surface->dir), &(L.dir), &(V->dir),
  194.       matl->D_coeff);
  195.  
  196.     /* Loop through the color samples and sum the diffuse
  197.      *  and specular contribution for this light to the the
  198.      *  color.
  199.      */
  200.     for (ct=0; ct<num_samples; ct++) {
  201.       color[ct] +=
  202.         ((N_dot_L * matl->Kd_scale * matl->Kd_spectral[ct])
  203.         + (D * matl->Ks_scale * matl->Ks_spectral[ct]))
  204.         * (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  205.     }
  206.       }
  207.       lgts++;
  208.     }
  209.  
  210.     return color;
  211. }
  212.  
  213. /* ****************************************************************
  214.  * double *IM_blinn (surface, V, matl, lgts, color)
  215.  *  LINE        *surface    (in)  - surface for color computation
  216.  *  LINE        *V          (in)  - view vector
  217.  *  ILLUM_MATL  *matl       (in)  - material properties
  218.  *  ILLUM_LGT   **lgts      (in)  - illuminating sources
  219.  *  double      *color      (mod) - array to receive the color
  220.  *
  221.  * Evaluates the color using the Blinn (1977) illumination
  222.  *  model as described in Eq.(\*(rV).  Returns 'color' upon
  223.  *  success and NULL upon failure.  The microfacet distribution
  224.  *  functions D_blinn(), D_gaussian(), and D_reitz are the three
  225.  *  functions presented by Blinn.  The geometric attenuation
  226.  *  function G_torrance() is the attenuation function used by Blinn.
  227.  *  If matl->G is NULL then the geometric attenuation is omitted.
  228.  *  The Fresnel reflectance is approximated using the Cook (1983)
  229.  *  technique.
  230.  */
  231. double *IM_blinn (surface, V, matl, lgts, color)
  232. LINE        *surface, *V;
  233. ILLUM_MATL  *matl;
  234. ILLUM_LGT   **lgts;
  235. double      *color;
  236. {   int         ct;
  237.     double      N_dot_L, N_dot_V, D, G, *Fr;
  238.     LINE        L;
  239.     DIR_VECT    *T, *H;
  240.  
  241.     /* load the ambient illumination */
  242.     for (ct=0; ct<num_samples; ct++) {
  243.       color[ct] = matl->Ka_scale * matl->Ka_spectral[ct] *
  244.     (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  245.     }
  246.     lgts++;
  247.  
  248.     /* load the diffuse and specular illumination components.
  249.      *  Loop through the lights and compute (N.L).  If it is
  250.      *  positive then the surface is illuminated.
  251.      */
  252.     while (*lgts != NULL) {
  253.       if ((geo_line(&(surface->start),&((*lgts)->center),&L) > 0)
  254.       && ((N_dot_L=geo_dot(&(surface->dir),&(L.dir))) > 0)) {
  255.  
  256.     /* The surface is illuminated.  Compute the microfacet
  257.      *  distribution, geometric attenuation, Fresnel
  258.      *  reflectance and (N.V) for the specular function.
  259.      */
  260.     D = (*(matl->D))(&(surface->dir), &(L.dir), &(V->dir),
  261.       matl->D_coeff);
  262.     if (matl->G == NULL)
  263.       G = 1.0;
  264.     else
  265.       G = (*(matl->G))(&(surface->dir), &(L.dir),
  266.         &(V->dir), matl->G_coeff);
  267.     H = geo_H(&(L.dir), &(V->dir));
  268.     if (matl->conductor) {
  269.       Fr = F_approx_Fr(H, &(L.dir), matl->Ro, matl->nt,
  270.        matl->k, num_samples, matl->Ks_spectral, Fr_buffer);
  271.     }
  272.     else {
  273.       T = geo_rfr(&(V->dir),H, matl->nr, matl->nt);
  274.       Fr = F_approx_Fr_Ft(H, &(L.dir), T,
  275.         matl->Ro, matl->nr, matl->nt, num_samples,
  276.         matl->Ks_spectral, Fr_buffer, Ft_buffer);
  277.     }
  278.  
  279.     /* Loop through the color samples and sum the diffuse
  280.      *  and specular contribution for this light to the the
  281.      *  color. Note the threshold on N_dot_V to prevent
  282.      *  divide by zero at grazing.
  283.      */
  284.     if ((N_dot_V=geo_dot(&(surface->dir),&(V->dir))) > 0.0001){
  285.         for (ct=0; ct<num_samples; ct++) {
  286.           color[ct] +=
  287.         ((N_dot_L * matl->Kd_scale * matl->Kd_spectral[ct])
  288.         + ((D * G * matl->Ks_scale * Fr[ct]) / N_dot_V))
  289.         * (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  290.         }
  291.     }
  292.       }
  293.       lgts++;
  294.     }
  295.  
  296.     return color;
  297. }
  298.  
  299. /* ****************************************************************
  300.  * double *IM_whitted (surface, V, matl, lgts, color)
  301.  *  LINE        *surface    (in)  - surface for color computation
  302.  *  LINE        *V          (in)  - view vector
  303.  *  ILLUM_MATL  *matl       (in)  - material properties
  304.  *  ILLUM_LGT   *lgts       (in)  - illuminating sources
  305.  *  double      *color      (mod) - array to receive the color
  306.  *
  307.  * Evaluates the color using the Whitted (1980) illumination
  308.  *  model as described in Eq.(\*(e6).  Returns 'color' upon
  309.  *  success and NULL upon failure.
  310.  *
  311.  * The actual Whitted model results when the microfacet
  312.  *  distribution D_blinn() is used, and when both matl->Ks_spectral
  313.  *  and matl->Kt_spectral are the identity material.
  314.  *
  315.  * The matl->Kt_scale and matl->Kt_spectral are required for this
  316.  *  illumination model only.
  317.  */
  318. double *IM_whitted (surface, V, matl, lgts, color)
  319. LINE        *surface, *V;
  320. ILLUM_MATL  *matl;
  321. ILLUM_LGT   **lgts;
  322. double      *color;
  323. {   int         inside = FALSE;
  324.     int         ct;
  325.     double      N_dot_L, D;
  326.     LINE        L;
  327.  
  328.     /* figure out whether we are on the reflected or transmitted
  329.      *  side of the material interface (outside or inside).  If
  330.      *  we are inside a material, then there is no illumination
  331.      *  from lights and such - skip directly to reflection and
  332.      *  refraction contribution.
  333.      */
  334.     if ((geo_dot(&(surface->dir),&(V->dir)) < 0) ||
  335.     (!matl->r_is_air)) {
  336.     for (ct=0; ct<num_samples; ct++) color[ct] = 0.0;
  337.     inside = TRUE;
  338.     goto rfl_rfr;
  339.     }
  340.  
  341.     /* If we are at interface between materials, neither of which
  342.      *  is air, then skip directly to reflection and refraction
  343.      */
  344.     if (!matl->r_is_air) goto rfl_rfr;
  345.  
  346.     /* load the ambient illumination */
  347.     for (ct=0; ct<num_samples; ct++) {
  348.       color[ct] = matl->Ka_scale * matl->Ka_spectral[ct] *
  349.     (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  350.     }
  351.     lgts++;
  352.  
  353.     /* load the diffuse and specular illumination components.
  354.      *  Loop through the lights and compute (N.L).  If it is
  355.      *  positive then the surface is illuminated.
  356.      */
  357.     while (*lgts != NULL) {
  358.       if ((geo_line(&(surface->start),&((*lgts)->center),&L) > 0)
  359.       && ((N_dot_L=geo_dot(&(surface->dir),&(L.dir))) > 0)) {
  360.  
  361.     /* The surface is illuminated.  Compute the microfacet
  362.      *  distribution function.
  363.      */
  364.     D = (*(matl->D))(&(surface->dir), &(L.dir), &(V->dir),
  365.       matl->D_coeff);
  366.  
  367.     /* Loop through the color samples and sum the diffuse
  368.      *  and specular contribution for this light to the the
  369.      *  color.
  370.      */
  371.     for (ct=0; ct<num_samples; ct++) {
  372.       color[ct] +=
  373.         ((N_dot_L * matl->Kd_scale * matl->Kd_spectral[ct])
  374.         + (D * matl->Ks_scale * matl->Ks_spectral[ct]))
  375.         * (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  376.     }
  377.       }
  378.       lgts++;
  379.     }
  380.  
  381.     /* compute the contribution from the reflection and
  382.      *  refraction directions.  Get a buffer to hold the
  383.      *  computed colors, then process the reflected direction
  384.      *  and the refracted direction.
  385.      */
  386. rfl_rfr:
  387.     if (get_color != NULL) {
  388.       char      *malloc();
  389.       double    *Ir_or_It;
  390.       LINE      V_new;
  391.       DIR_VECT  *T;
  392.  
  393.       if ((Ir_or_It = (double *)malloc((unsigned)(num_samples *
  394.     sizeof(double)))) == NULL) return color;
  395.  
  396.       /* get the reflected vector then ask for the color from
  397.        *  the reflected direction.  If there is a color, then
  398.        *  sum it with the current color
  399.        */
  400.       V_new.start = surface->start;
  401.       V_new.dir = *(geo_rfl(&(V->dir),&(surface->dir)));
  402.       if ((*get_color)(&V_new, Ir_or_It) != NULL)
  403.     for (ct=0; ct<num_samples; ct++) color[ct] +=
  404.       Ir_or_It[ct] * matl->Ks_scale * matl->Ks_spectral[ct];
  405.  
  406.       /* if the material is transparent then get the refracted
  407.        *  vector and ask for the color from the refracted
  408.        *  direction.  If there is a color, then sum it with
  409.        *  the current color
  410.        */
  411.       if (matl->transparent) {
  412.     V_new.start = surface->start;
  413.     if (inside)
  414.       T = geo_rfr(&(V->dir),&(surface->dir),
  415.         matl->nt, matl->nr);
  416.     else
  417.       T = geo_rfr(&(V->dir),&(surface->dir),
  418.         matl->nr, matl->nt);
  419.     if (T != NULL) {
  420.       V_new.dir = *T;
  421.       if ((*get_color)(&V_new, Ir_or_It) != NULL)
  422.         for (ct=0; ct<num_samples; ct++) color[ct] +=
  423.           Ir_or_It[ct] * matl->Kt_scale *
  424.           matl->Kt_spectral[ct];
  425.     }
  426.       }
  427.       (void)free((char *)Ir_or_It);
  428.     }
  429.  
  430.     return color;
  431. }
  432.  
  433. /* ****************************************************************
  434.  * double *IM_hall (surface, V, matl, lgts, color)
  435.  *  LINE        *surface    (in)  - surface for color computation
  436.  *  LINE        *V          (in)  - view vector
  437.  *  ILLUM_MATL  *matl       (in)  - material properties
  438.  *  ILLUM_LGT   *lgts       (in)  - illuminating sources
  439.  *  double      *color      (mod) - array to receive the color
  440.  *
  441.  * Evaluates the color using the Hall (1983) illumination
  442.  *  model as described in Eq.(\*(sF).  Returns 'color' upon
  443.  *  success and NULL upon failure.
  444.  *
  445.  * The actual Hall model results when the microfacet
  446.  *  distribution D_blinn() is used, and matl->D = NULL.
  447.  *
  448.  * The transmittance is computed from the reflectance, so
  449.  *  matl->Kt_scale and matl->Kt_spectral are not used in the model.
  450.  */
  451. double *IM_hall (surface, V, matl, lgts, color)
  452. LINE        *surface, *V;
  453. ILLUM_MATL  *matl;
  454. ILLUM_LGT   **lgts;
  455. double      *color;
  456. {   int         inside = FALSE;
  457.     int         ct;
  458.     double      N_dot_L, D, G, *Fr;
  459.     LINE        L;
  460.     DIR_VECT    *T, *H, *Ht, pseudo_V;
  461.  
  462.     /* figure out whether we are on the reflected or transmitted
  463.      *  side of the material interface (outside or inside).  If
  464.      *  we are inside a material, then there may be illumination
  465.      *  from outside.
  466.      */
  467.     if (geo_dot(&(surface->dir),&(V->dir)) < 0) {
  468.     for (ct=0; ct<num_samples; ct++) color[ct] = 0.0;
  469.     inside = TRUE;
  470.     }
  471.  
  472.     /* If we are at interface between materials, neither of which
  473.      *  is air, then skip directly to reflection and refraction
  474.      */
  475.     if (!matl->r_is_air) goto rfl_rfr;
  476.  
  477.     /* load the ambient illumination if we are not inside
  478.      *  inside the material
  479.      */
  480.     if (!inside) {
  481.       for (ct=0; ct<num_samples; ct++) {
  482.     color[ct] = matl->Ka_scale * matl->Ka_spectral[ct] *
  483.       (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  484.       }
  485.     }
  486.     lgts++;
  487.  
  488.     /* load the diffuse and specular illumination components.
  489.      *  Loop through the lights and compute (N.L).  If it is
  490.      *  positive then the surface is illuminated.  If it is
  491.      *  negative, then there may be transmitted illumination.
  492.      */
  493.     while (*lgts != NULL) {
  494.       if ((geo_line(&(surface->start),&((*lgts)->center),&L) > 0)
  495.       && ((N_dot_L=geo_dot(&(surface->dir),&(L.dir))) > 0)
  496.       && !inside) {
  497.  
  498.     /* The surface is illuminated.  Compute the microfacet
  499.      *  distribution, geometric attenuation, Fresnel
  500.      *  reflectance and (N.V) for the specular function.
  501.      */
  502.     D = (*(matl->D))(&(surface->dir), &(L.dir), &(V->dir),
  503.       matl->D_coeff);
  504.     if (matl->G == NULL)
  505.       G = 1.0;
  506.     else
  507.       G = (*(matl->G))(&(surface->dir), &(L.dir),
  508.         &(V->dir), matl->G_coeff);
  509.     H = geo_H(&(L.dir), &(V->dir));
  510.     if (matl->conductor) {
  511.       Fr = F_approx_Fr(H, &(L.dir), matl->Ro, matl->nt,
  512.         matl->k, num_samples, matl->Ks_spectral, Fr_buffer);
  513.     }
  514.     else {
  515.       T = geo_rfr(&(L.dir), H, matl->nr, matl->nt);
  516.       Fr = F_approx_Fr_Ft(H, &(L.dir), T,
  517.         matl->Ro, matl->nr, matl->nt, num_samples,
  518.         matl->Ks_spectral, Fr_buffer, Ft_buffer);
  519.     }
  520.  
  521.  
  522.     /* Loop through the color samples and sum the diffuse
  523.      *  and specular contribution for this light to the the
  524.      *  color.
  525.      */
  526.     for (ct=0; ct<num_samples; ct++) {
  527.       color[ct] +=
  528.         ((N_dot_L * matl->Kd_scale * matl->Kd_spectral[ct])
  529.         + (D * G * matl->Ks_scale * Fr[ct]))
  530.         * (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  531.     }
  532.       }
  533.       else if ((N_dot_L > 0) && inside) {
  534.     /* We are inside and the light is outside.  Compute
  535.      *  the transmitted contribution from the light
  536.      */
  537.     if ((Ht = geo_Ht(&(L.dir),&(V->dir),matl->nr,
  538.         matl->nt)) != NULL) {
  539.       /* The microfacet distribution functions could
  540.        *  only be equated when cast in terms of the primary
  541.        *  vectors L, V, and N.  A pseudo_V vector is required
  542.        *  so that any of the distribution functions can be
  543.        *  applied.  Ht is the vector bisector between of the
  544.        *  angle between L and pseudo_V, thus pseudo_V can be
  545.        *  computed by reflecting L about Ht. Refer to the
  546.        *  text for details.
  547.        */
  548.       pseudo_V = *(geo_rfl(&(L.dir), Ht));
  549.       D = (*(matl->D))(&(surface->dir), &(L.dir),
  550.         &pseudo_V, matl->D_coeff);
  551.       Fr = F_approx_Fr_Ft(Ht, &(L.dir), &(V->dir),
  552.         matl->Ro, matl->nr, matl->nt, num_samples,
  553.         matl->Ks_spectral, Fr_buffer, Ft_buffer);
  554.       if (matl->G == NULL)
  555.         G = 1.0;
  556.       else {
  557.         /* To include the geometric attenuation, the view
  558.          *  vector direction must be reversed so that it
  559.          *  is to the same side of the surface as the
  560.          *  normal, see text for details.
  561.          */
  562.         pseudo_V.i = -V->dir.i;
  563.         pseudo_V.j = -V->dir.j;
  564.         pseudo_V.k = -V->dir.k;
  565.         G = (*(matl->G))(&(surface->dir), &(L.dir),
  566.           &pseudo_V, matl->G_coeff);
  567.       }
  568.       for (ct=0; ct<num_samples; ct++) {
  569.         color[ct] += (D * G * matl->Ks_scale * Ft_buffer[ct])
  570.           * (*lgts)->I_scale * (*lgts)->I_spectral[ct];
  571.       }
  572.     }
  573.       }
  574.       lgts++;
  575.     }
  576.  
  577.     /* compute the contribution from the reflection and
  578.      *  refraction directions.  Get a buffer to hold the
  579.      *  computed colors, then process the reflected direction
  580.      *  and the refracted direction.
  581.      */
  582. rfl_rfr:
  583.     if (get_color != NULL) {
  584.       char      *malloc();
  585.       double    *Ir_or_It;
  586.       LINE      V_new;
  587.       DIR_VECT  pseudo_N;
  588.  
  589.       if ((Ir_or_It = (double *)malloc((unsigned)(num_samples *
  590.     sizeof(double)))) == NULL) return color;
  591.  
  592.       /* Determine the Fresnel reflectance and transmittance.
  593.        *  If we are inside the material, then a pseudo normal
  594.        *  is required that faces to the same side of the
  595.        *  interface as the view vector.
  596.        */
  597.       if (matl->conductor) {
  598.     Fr = F_approx_Fr(&(surface->dir), &(V->dir), matl->Ro,
  599.       matl->nt, matl->k, num_samples, matl->Ks_spectral,
  600.       Fr_buffer);
  601.       }
  602.       else if (inside) {
  603.     T = geo_rfr(&(V->dir),&(surface->dir),
  604.         matl->nt, matl->nr);
  605.     pseudo_N.i = -surface->dir.i;
  606.     pseudo_N.j = -surface->dir.j;
  607.     pseudo_N.k = -surface->dir.k;
  608.     Fr = F_approx_Fr_Ft(&pseudo_N, &(V->dir), T,
  609.         matl->Ro, matl->nt, matl->nr, num_samples,
  610.         matl->Ks_spectral, Fr_buffer, Ft_buffer);
  611.       }
  612.       else {
  613.     T = geo_rfr(&(V->dir),&(surface->dir),
  614.         matl->nr, matl->nt);
  615.     Fr = F_approx_Fr_Ft(&(surface->dir), &(V->dir),
  616.         T, matl->Ro, matl->nr, matl->nt, num_samples,
  617.         matl->Ks_spectral, Fr_buffer, Ft_buffer);
  618.       }
  619.  
  620.       /* get the reflected vector then ask for the color from
  621.        *  the reflected direction.  If there is a color, then
  622.        *  sum it with the current color
  623.        */
  624.       V_new.start = surface->start;
  625.       V_new.dir = *(geo_rfl(&(V->dir),&(surface->dir)));
  626.       if ((*get_color)(&V_new, Ir_or_It) != NULL) {
  627.     for (ct=0; ct<num_samples; ct++) color[ct] +=
  628.       Ir_or_It[ct] * matl->Ks_scale * Fr[ct];
  629.       }
  630.  
  631.       /* if the material is transparent then get the refracted
  632.        *  vector and ask for the color from the refracted
  633.        *  direction.  If there is a color, then sum it with
  634.        *  the current color
  635.        */
  636.       if (matl->transparent && (T != NULL)) {
  637.     V_new.start = surface->start;
  638.     V_new.dir = *T;
  639.     if ((*get_color)(&V_new, Ir_or_It) != NULL)
  640.       for (ct=0; ct<num_samples; ct++) color[ct] +=
  641.         Ir_or_It[ct] * matl->Kt_scale * Ft_buffer[ct];
  642.       }
  643.       (void)free((char *)Ir_or_It);
  644.     }
  645.  
  646.     /* If we are inside a material that has a filter attenuation
  647.      *  then apply the attenuation to the color.
  648.      */
  649.     if ( ((!inside) && ((Fr = matl->Ar_spectral) != NULL)) ||
  650.      ((inside) && ((Fr = matl->At_spectral) != NULL)) ) {
  651.     double      dist;
  652.     dist = sqrt ( ((surface->start.x - V->start.x) *
  653.                (surface->start.x - V->start.x)) +
  654.               ((surface->start.y - V->start.y) *
  655.                (surface->start.y - V->start.y)) +
  656.               ((surface->start.z - V->start.z) *
  657.                (surface->start.z - V->start.z)) );
  658.     for (ct=0; ct<num_samples; ct++)
  659.         color[ct] *= pow (Fr[ct], dist);
  660.     }
  661.  
  662.     return color;
  663. }
  664.  
  665. /* ****************************************************************
  666.  * int IM_exit ()
  667.  *
  668.  * Finishes use of the illumination models routines.
  669.  */
  670. IM_exit()
  671. {
  672.     if (Fr_buffer != NULL) {
  673.     (void)free((char *)Fr_buffer); Fr_buffer = NULL;
  674.     }
  675.     if (Ft_buffer != NULL) {
  676.     (void)free((char *)Ft_buffer); Ft_buffer = NULL;
  677.     }
  678.     num_samples = 0;
  679.     get_color = NULL;
  680.     return TRUE;
  681. }
  682. /* ************************************************************* */
  683.