Página principal | Jerarquía de la clase | Lista alfabética | Lista de componentes | Lista de archivos | Miembros de las clases | Archivos de los miembros | Páginas relacionadas

raytrace.C

Ir a la documentación de este archivo.
00001 //===========================================================================
00002 //= raytrace.cc                                               Marzo de 1999 =
00003 //=-------------------------------------------------------------------------=
00004 //= Especifica el raytracer "criollo" que genera IMAGENes de una manera     =
00005 //= generica (independiente del disenno de la aplicacion), basandose en los =
00006 //= elementos basicos GEOMETRIA, LUZ y MATERIAL del framework AQUYNZA.      =
00007 //=-------------------------------------------------------------------------=
00008 //= ADVERTENCIA: ESTE SOFTWARE NO ESTA CONCEBIDO NI DISENNADO PARA EL USO   =
00009 //= EN EQUIPO DE CONTROL EN LINEA EN ENTORNOS PELIGROSOS QUE REQUIERAN UN   =
00010 //= DESEMPENNO LIBRE DE FALLAS, COMO LA OPERACION DE PLANTAS NUCLEARES,     = 
00011 //= SISTEMAS DE NAVEGACION O COMUNICACION EN AVIONES, TRAFICO AEREO,        =
00012 //= EQUIPO MEDICO DEL CUAL DEPENDAN VIDAS HUMANAS O SISTEMAS DE ARMAMENTO,  =
00013 //= EN LOS CUALES UNA FALLA EN EL SOFTWARE PUEDA IMPLICAR DIRECTAMENTE LA   =
00014 //= MUERTE, DANNOS PERSONALES O DANNOS FISICOS Y/O AMBIENTALES GRAVES       =
00015 //= ("ACTIVIDADES DE ALGO RIESGO").                                         =
00016 //=-------------------------------------------------------------------------=
00017 //= Autor original: Oscar J. Chavarro G.  A.K.A. JEDILINK. Copyright (c),   =
00018 //= 1997 - 2003, oscarchavarro@hotmail.com                                  =
00019 //= AQUYNZA es software libre, y se rige bajo los terminos de la licencia   =
00020 //= LGPL de GNU (http://www.gnu.org). Para mayor informacion respecto a la  =
00021 //= licencia de uso, consulte el archivo ./doc/LICENCIA en la distribucion. =
00022 //===========================================================================
00023 
00024 #include "framework/visual/raytrace.h"
00025 #include "arreglo.cc"
00026 
00027 //===========================================================================
00028 //= CLASE RAYTRACER_CRIOLLO                                                 =
00029 //===========================================================================
00030 
00031 RAYTRACER_CRIOLLO::RAYTRACER_CRIOLLO()
00032 {
00033     ;
00034 }
00035 
00036 RAYTRACER_CRIOLLO::~RAYTRACER_CRIOLLO()
00037 {
00038     ;
00039 }
00040 
00041 void
00042 RAYTRACER_CRIOLLO::ejecutar(IMAGEN_RGB *Resultado,
00043                        ARREGLO <OBJETO_RAYABLE *> &arr_objetos, 
00044                        LUZ **LUces, CAMARA *Camara)
00058 {
00059     //-----------------------------------------------------------------------
00060 //#define DEBUG_RAYTRACER
00061 #ifdef DEBUG_RAYTRACER
00062     static BOOLEAN primiparo = TRUE;
00063     int i;
00064 
00065     if ( primiparo ) {
00066         printf("<RAYTRACER> Tengo estos objetos:\n");
00067         for ( i = 0; i < arr_objetos.tam(); i++ ) {
00068             printf("[%d]:%p\n", i, arr_objetos[i]->Geometria);
00069         }
00070         fflush(stdout);;
00071         primiparo = FALSE;
00072     }
00073 #endif
00074 
00075     //-----------------------------------------------------------------------
00076     int x, y;
00077     RAYO rayo;
00078     // No queremos que se llame mucho la constructora, por eso "static"...
00079     static COLOR color; 
00080 
00081     printf("[");
00082     nivel_de_recursion = 0;
00083     Camara->preprocesar_vista();
00084     for ( y = 0; y < Resultado->ytam(); y++ ) {
00085         if ( (y % 10) == 0 ) {  printf("."); fflush(stdout);  }
00086         for ( x = 0; x < Resultado->xtam(); x++ ) {
00087             //- Trazado individual de un rayo ------------------------------
00088             rayo = Camara->generar_rayo(x, y);
00089             color = seguimiento_rayo(&rayo, arr_objetos, LUces);
00090 
00091             //- Proceso de control de la saturacion de energia luminica ----
00092             // OJO: Esto deberia mejorarse para lograr efectos de camara...
00093             if ( color.r > 1 ) color.r = 1.0;
00094             if ( color.g > 1 ) color.g = 1.0;
00095             if ( color.b > 1 ) color.b = 1.0;
00096 
00097             //- Exporto el resultado de color del pixel --------------------
00098             Resultado->putpixel(x, y, (BYTE)(255 * color.r),
00099                                       (BYTE)(255 * color.g),
00100                                       (BYTE)(255 * color.b));
00101         }
00102     }
00103     printf("]");
00104     fflush(stdout);
00105 }
00106 
00107 COLOR
00108 RAYTRACER_CRIOLLO::modelo_de_iluminacion(const OBJETO_RAYABLE *Objeto,
00109     ARREGLO <OBJETO_RAYABLE *> &objetos, RAYO *Rayo, const VECTOR &punto,
00110     VECTOR &normal, LUZ **LUces)
00132 {
00133     COLOR color; // OJO: Depende del valor por defecto!
00134     double K;
00135     RAYO rayo_reflejado;
00136 
00137     /*----------------------------------------------------------------------
00138     Notese que respecto a la figura 16.12 de [FOLE92], `*Rayo` (que es
00139     un rayo que va de la camara al objeto) es equivalente a -V (un rayo
00140     con la direccion inversa a V).
00141 
00142     Se calcula el rayo reflejado R con la normal N y el rayo incidente V.
00143     La formula para el rayo reflejado es generalmente :
00144                                                    R = 2(V dot N)N - V
00145     Asumiendo que V apunta hacia afuera del punto de interseccion,
00146     cosa que no es cierta en este modelo ya que el rayo se origina
00147     en el ojo. Por lo tanto se debe invertir V para que cuadre en el
00148     modelo. Para lograrlo escalamos V por -1.0. El resultado es:
00149                                                   R = -2N(V dot N) + V
00150     que es la formula que usaremos aqui.
00151     El rayo reflejado es aquel que sera rastreado para encontrar las
00152     contribuciones de color para el punto que sera iluminado si la
00153     superficie que sera iluminada es reflectiva. El rayo reflejado comienza
00154     en el punto `punto` y tiene direccion fuera de la superficie.
00155     ----------------------------------------------------------------------*/
00156 
00157     // Notese que no es necesario normalizar la direccion del rayo reflejado 
00158     // debido a que V y N son vectores unitarios...
00159     K = Rayo->direccion.producto_punto(normal);
00160     K *= -2.0;
00161     rayo_reflejado.origen = punto;
00162     rayo_reflejado.direccion = normal * K + Rayo->direccion;
00163 
00164     /*- 1. -----------------------------------------------------------------
00165     Comienza el calculo del color con la contribucion del ambiente.
00166     Esta luz es la que esta en todas partes en la escena.
00167     ----------------------------------------------------------------------*/
00168     double Ia = 0.3; // OJO: Deberia ser configurable!
00169 
00170     color.r = (FLOAT32)(Objeto->ambiente.r * Ia);
00171     color.g = (FLOAT32)(Objeto->ambiente.g * Ia);
00172     color.b = (FLOAT32)(Objeto->ambiente.b * Ia);
00173 
00174     /*- 2. -----------------------------------------------------------------
00175     Aqui se calcula la sumatoria de las contribuciones de todas las fuentes
00176     de luz.
00177     ----------------------------------------------------------------------*/
00178     int i;
00179     LUZ *Luz;
00180     double NpuntoL, Ks; //, DistanceT;
00181     // No queremos que se llame mucho la constructora, por eso "static"...
00182     static COLOR color_de_la_luz;
00183     RAYO L; // El rayo unitario con direccion del punto de l objeto a a
00184             // la luz, como se muestra en la figura 16.1 de [FOLE92]
00185 
00186     for ( i = 0; LUces[i]; i++ ) {
00187         Luz = LUces[i];
00188 
00189         /* 2.1. Generamos un rayo desde el punto `punto` a la luz de interes.
00190         DistanceT es la longitud del rayo desde punto a la fuente de luz.
00191         Se llama GetLightColor para ver si hay objetos que bloquean a
00192         lo largo de este rayo. */
00193 
00194         L.origen = punto;
00195         L.direccion = Luz->posicion() - punto;
00196         //DistanceT = MAGNITUD(L.direccion);
00197         L.direccion.normalizar();
00198 
00199         // OJO: Sin esto no saldran sombras!
00200        //color_de_la_luz = GetLightColor(Luz, Objeto, 
00201        //&L, DistanceT);
00202         color_de_la_luz.r = color_de_la_luz.g = color_de_la_luz.b = 1.0;
00203 
00204         /* 2.2. Acumulacion de la contribucion de reflexion difusa 
00205                 (Lambertiana) */
00206 
00207         // Se chequea para ver si el objeto da la cara a la luz
00208         NpuntoL = normal.producto_punto(L.direccion);
00209 
00210         // OJO: En el modelo de iluminacion de referencia elaborado en 
00211         //      Pixar / Renderman, se considera una operacion "faceforward"
00212         //      que hace que se muestren los dos lados de un objeto...
00213         if ( NpuntoL > 0.0 ) {
00214             // Respecto a la ecuacion (16.4) de [FOLE92], color_de_la_luz.p
00215             // corresponde a Ip (para p en `r`, `g` o `b`), y 
00216             // Objeto->difusa.* por cada canal RGB corresponde a Kd.
00217             // La contribucion de reflexion difusa color.* corresponde a I
00218             color.r += (FLOAT32)(color_de_la_luz.r*Objeto->difusa.r*NpuntoL);
00219             color.g += (FLOAT32)(color_de_la_luz.g*Objeto->difusa.g*NpuntoL);
00220             color.b += (FLOAT32)(color_de_la_luz.b*Objeto->difusa.b*NpuntoL);
00221         }
00222         else {
00223             // Caso de normal invertida ...
00224             color.r -= (FLOAT32)(color_de_la_luz.r*Objeto->difusa.r*NpuntoL);
00225             color.g -= (FLOAT32)(color_de_la_luz.g*Objeto->difusa.g*NpuntoL);
00226             color.b -= (FLOAT32)(color_de_la_luz.b*Objeto->difusa.b*NpuntoL);
00227         }
00228 
00229         /* Usualmente el componente especular observando como el rayo inci-
00230         dente V se alinea con el rayo reflejado. Entre mas cercanos,
00231         mayor la contribucion hecha al color del objeto en punto.
00232         En este caso haremos la misma cosa comparando como el rayo
00233         incidente reflejado calulado antes y llamado rayo_reflejado
00234         se alinea con L. Esto requiere menos trabajo ya que
00235         rayo_reflejado y L apuntan en la misma direccion. Esto
00236         funciona por que el angulo entre los dos conjuntos de rayos
00237         es el mismo.       */
00238         double afinidad;
00239         afinidad = rayo_reflejado.direccion.producto_punto(L.direccion);
00240         if ( afinidad > 0.001 ) { // OJO: 0.001 porque hay lios de presicion
00241             Ks = Objeto->phong_coef * pow(afinidad, Objeto->phong_exp);
00242             color.r += (FLOAT32)(color_de_la_luz.r * Objeto->especular.r * Ks);
00243             color.g += (FLOAT32)(color_de_la_luz.g * Objeto->especular.g * Ks);
00244             color.b += (FLOAT32)(color_de_la_luz.b * Objeto->especular.b * Ks);
00245         }
00246     }
00247 
00248     /*- 3. Ahora se considera reflexion ---------------------------------*/
00249     // No queremos que se llame mucho la constructora, por eso "static"...
00250     static COLOR color_recursion;
00251     double Krl;
00252 
00253     Krl = Objeto->coeficiente_de_reflexion;
00254     if ( K > 0.0 )  {
00255         nivel_de_recursion++;
00256         // Recordar de mas arriba que rayo_reflejado es unitario, loego se
00257         // cumple la precondicion de `seguimiento_rayo`
00258         color_recursion = seguimiento_rayo(&rayo_reflejado, objetos, LUces);
00259         color.r += (FLOAT32)(color_recursion.r * Krl);
00260         color.g += (FLOAT32)(color_recursion.g * Krl);
00261         color.b += (FLOAT32)(color_recursion.b * Krl);
00262         nivel_de_recursion--;
00263     }
00264 
00265     return color;
00266 }
00267 
00268 COLOR
00269 RAYTRACER_CRIOLLO::seguimiento_rayo(RAYO *Rayo,
00270                                     ARREGLO <OBJETO_RAYABLE *> &objetos, 
00271                                     LUZ **LUces)
00302 {
00303     VECTOR punto, normal, p, n;
00304     // No queremos que se llame mucho la constructora, por eso "static"...
00305     static COLOR color;
00306 
00307     //- Caso 1: limite de la recursion (Fuerza Bruta) ----------------------
00308     if ( nivel_de_recursion > MAXRECURSELEVEL ) {
00309         color.r = color.g = color.b = 0; // Notese que "negro" significa que
00310         return color;                    // "no hay contribucion de color".
00311     }
00312 
00313     //- Busqueda de el objeto mas cercano que intersecte el rayo -----------
00314     //- NOTA: Si T == 0 significa que no lo intersecto.                    -
00315     OBJETO_RAYABLE *Objeto_mas_cercano = NULL;
00316     double T, distancia_minima = INFINITO;
00317     int i;
00318     VECTOR po;
00319     RAYO mi_rayo;
00320 
00321     // OJO: No ayudaria usar QUATERNIONs?
00322 
00323     for ( i = 0; i < objetos.tam(); i++ ) {
00324         po = objetos[i]->posicion;
00325         mi_rayo.origen = Rayo->origen - po;
00326         mi_rayo.origen = objetos[i]->R_i * mi_rayo.origen;
00327         mi_rayo.direccion = objetos[i]->R_i * Rayo->direccion;
00328         // Notese mi_rayo.direccion es unitario si Rayo->direccion es
00329         // unitario (y lo es pues ese vector no cambia dentro de este ciclo y
00330         // es unitario dada la precondicion) y si R_i es una matriz ortogonal
00331         // juiciosa (debe venir normalizada!)
00332 
00333     // OJO: Las operaciones de interseccion deben calcular normales 
00334         //      unitarias!
00335         T = objetos[i]->Geometria->interseccion(&mi_rayo, p, n);
00336         if ( (T > EPSILON) && (T < distancia_minima) ) {
00337             Objeto_mas_cercano = objetos[i];
00338             distancia_minima = T;
00339             punto = objetos[i]->R * p;
00340             punto = punto + po;
00341             normal = objetos[i]->R * n;
00342             // OJO: La normal debe ser unitaria para poder evitar esta linea!
00343             //normal.normalizar();
00344         }
00345     }
00346 
00347     //- Caso 2: Si nada fue intersectado retorna el color del fondo ---------
00348     if ( !Objeto_mas_cercano )  {
00349         // OJO: Deberia mejorarse para enmascarar otra imagen, que contiene 
00350         //      un fondo complejo preprocesado... (tal vez con depth-buffer?)
00351         color.r = 0;  // Tenga en cuenta que este color sera reflejado por
00352         color.g = 0;  // los objetos, alterando la apariencia de los mismos.
00353         color.b = 0;
00354         return color;
00355     }
00356 
00357     //- Caso 3: Se intersecto un objeto -------------------------------------
00358     double direccion_normal;
00359 
00360     //- Chequeamos para ver si la normal apunta hacia el Rayo. Si no, se ---
00361     //- invierte la direccion de la normal para hacer a las superficies    -
00362     //- visibles por sus dos caras.                                        -
00363     direccion_normal = normal.producto_punto(Rayo->direccion);
00364     if ( direccion_normal > EPSILON ) normal = normal * -1;
00365 
00366     // OJO: Este proceso se aislo por claridad, y llama a este metodo,
00367     //      haciendo el proceso recursivo
00368     return modelo_de_iluminacion(Objeto_mas_cercano, objetos,
00369                                  Rayo, punto, normal, LUces);
00370 }
00371 
00372 //===========================================================================
00373 //= EOF                                                                     =
00374 //===========================================================================
00375 

Este archivo HTML ha sido generado automáticamente a partir del código fuente AQUYNZA. NO LO EDITE. Para mayor información contacte al autor.