Blender  V2.59
ntl_ray.cpp
Go to the documentation of this file.
00001 
00004 /******************************************************************************
00005  *
00006  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
00007  * Copyright 2003-2006 Nils Thuerey
00008  *
00009  * main renderer class
00010  *
00011  *****************************************************************************/
00012 
00013 
00014 #include "utilities.h"
00015 #include "ntl_ray.h"
00016 #include "ntl_world.h"
00017 #include "ntl_geometryobject.h"
00018 #include "ntl_geometryshader.h"
00019 
00020 
00021 /* Minimum value for refl/refr to be traced */
00022 #define RAY_THRESHOLD 0.001
00023 
00024 #if GFX_PRECISION==1
00025 // float values
00027 #define RAY_MINCONTRIB (1e-04)
00028 
00029 #else 
00030 // double values
00032 #define RAY_MINCONTRIB (1e-05)
00033 
00034 #endif 
00035 
00036 
00037 
00038 
00039 
00040 /******************************************************************************
00041  * Constructor
00042  *****************************************************************************/
00043 ntlRay::ntlRay( void )
00044   : mOrigin(0.0)
00045   , mDirection(0.0)
00046   , mvNormal(0.0)
00047   , mDepth(0)
00048   , mpGlob(NULL)
00049   , mIsRefracted(0)
00050 {
00051   errFatal("ntlRay::ntlRay()","Don't use uninitialized rays !", SIMWORLD_GENERICERROR);
00052         return;
00053 }
00054 
00055 
00056 /******************************************************************************
00057  * Copy - Constructor
00058  *****************************************************************************/
00059 ntlRay::ntlRay( const ntlRay &r )
00060 {
00061   // copy it! initialization is not enough!
00062   mOrigin    = r.mOrigin;
00063   mDirection = r.mDirection;
00064   mvNormal   = r.mvNormal;
00065   mDepth     = r.mDepth;
00066   mIsRefracted  = r.mIsRefracted;
00067   mIsReflected  = r.mIsReflected;
00068         mContribution = r.mContribution;
00069   mpGlob        = r.mpGlob;
00070 
00071         // get new ID
00072         if(mpGlob) {
00073                 mID           = mpGlob->getCounterRays()+1;
00074                 mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
00075         } else {
00076                 mID = 0;
00077         }
00078 }
00079 
00080 
00081 /******************************************************************************
00082  * Constructor with explicit parameters and global render object
00083  *****************************************************************************/
00084 ntlRay::ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob)
00085   : mOrigin( o )
00086   , mDirection( d )
00087   , mvNormal(0.0)
00088   , mDepth( i )
00089         , mContribution( contrib )
00090   , mpGlob( glob )
00091   , mIsRefracted( 0 )
00092         , mIsReflected( 0 )
00093 {
00094         // get new ID
00095         if(mpGlob) {
00096                 mID           = mpGlob->getCounterRays()+1;
00097                 mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
00098         } else {
00099                 mID = 0;
00100         }
00101 }
00102 
00103 
00104 
00105 /******************************************************************************
00106  * Destructor
00107  *****************************************************************************/
00108 ntlRay::~ntlRay()
00109 {
00110   /* nothing to do... */
00111 }
00112 
00113 
00114 
00115 /******************************************************************************
00116  * AABB
00117  *****************************************************************************/
00118 /* for AABB intersect */
00119 #define NUMDIM 3
00120 #define RIGHT  0
00121 #define LEFT   1
00122 #define MIDDLE 2
00123 
00125 #ifndef ELBEEM_PLUGIN
00126 void ntlRay::intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
00127 {
00128   char   inside = true;   /* inside box? */
00129   char   hit    = false;  /* ray hits box? */
00130   int    whichPlane;      /* intersection plane */
00131   gfxReal candPlane[NUMDIM];  /* candidate plane */
00132   gfxReal quadrant[NUMDIM];   /* quadrants */
00133   gfxReal maxT[NUMDIM];       /* max intersection T for planes */
00134   ntlVec3Gfx  coord;           /* intersection point */
00135   ntlVec3Gfx  dir = mDirection;
00136   ntlVec3Gfx  origin = mOrigin;
00137   ntlVec3Gfx  normal(0.0, 0.0, 0.0);
00138 
00139   t = GFX_REAL_MAX;
00140 
00141   /* check intersection planes for AABB */
00142   for(int i=0;i<NUMDIM;i++) {
00143     if(origin[i] < mStart[i]) {
00144       quadrant[i] = LEFT;
00145       candPlane [i] = mStart[i];
00146       inside = false;
00147     } else if(origin[i] > mEnd[i]) {
00148       quadrant[i] = RIGHT;
00149       candPlane[i] = mEnd[i];
00150       inside = false;
00151     } else {
00152       quadrant[i] = MIDDLE;
00153     }
00154   }
00155 
00156   /* inside AABB? */
00157   if(!inside) {
00158     /* get t distances to planes */
00159     /* treat too small direction components as paralell */
00160     for(int i=0;i<NUMDIM;i++) {
00161       if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
00162                                 maxT[i] = (candPlane[i] - origin[i]) / dir[i];
00163       } else {
00164                                 maxT[i] = -1;
00165       }
00166     }
00167     
00168     /* largest max t */
00169     whichPlane = 0;
00170     for(int i=1;i<NUMDIM;i++) {
00171       if(maxT[whichPlane] < maxT[i]) whichPlane = i;
00172     }
00173     
00174     /* check final candidate */
00175     hit  = true;
00176     if(maxT[whichPlane] >= 0.0) {
00177 
00178       for(int i=0;i<NUMDIM;i++) {
00179                                 if(whichPlane != i) {
00180                                         coord[i] = origin[i] + maxT[whichPlane] * dir[i];
00181                                         if( (coord[i] < mStart[i]-getVecEpsilon() ) || 
00182                                                         (coord[i] > mEnd[i]  +getVecEpsilon() )  ) {
00183                                                 /* no hit... */
00184                                                 hit  = false;
00185                                         } 
00186                                 }
00187                                 else {
00188                                         coord[i] = candPlane[i];
00189                                 }      
00190       }
00191 
00192       /* AABB hit... */
00193       if( hit ) {
00194                                 t = maxT[whichPlane];   
00195                                 if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
00196                                 else normal[whichPlane] = -1.0;
00197       }
00198     }
00199     
00200 
00201   } else {
00202     /* inside AABB... */
00203     t  = 0.0;
00204     coord = origin;
00205     return;
00206   }
00207 
00208   if(t == GFX_REAL_MAX) t = -1.0;
00209   retnormal = normal;
00210   retcoord = coord;
00211 }
00212 
00214 void ntlRay::intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
00215 {
00216   char   hit    = false;  /* ray hits box? */
00217   int    whichPlane;      /* intersection plane */
00218   gfxReal candPlane[NUMDIM]; /* candidate plane */
00219   gfxReal quadrant[NUMDIM];  /* quadrants */
00220   gfxReal maxT[NUMDIM];    /* max intersection T for planes */
00221   ntlVec3Gfx  coord;           /* intersection point */
00222   ntlVec3Gfx  dir = mDirection;
00223   ntlVec3Gfx  origin = mOrigin;
00224   ntlVec3Gfx  normal(0.0, 0.0, 0.0);
00225 
00226   t = GFX_REAL_MAX;
00227   for(int i=0;i<NUMDIM;i++) {
00228     if(origin[i] < mStart[i]) {
00229       quadrant[i] = LEFT;
00230       candPlane [i] = mEnd[i];
00231     } else if(origin[i] > mEnd[i]) {
00232       quadrant[i] = RIGHT;
00233       candPlane[i] = mStart[i];
00234     } else {
00235       if(dir[i] > 0) {
00236                                 quadrant[i] = LEFT;
00237                                 candPlane [i] = mEnd[i];
00238       } else 
00239                                 if(dir[i] < 0) {
00240                                         quadrant[i] = RIGHT;
00241                                         candPlane[i] = mStart[i];
00242                                 } else {
00243                                         quadrant[i] = MIDDLE;
00244                                 }
00245     }
00246   }
00247 
00248 
00249         /* get t distances to planes */
00250         /* treat too small direction components as paralell */
00251         for(int i=0;i<NUMDIM;i++) {
00252                 if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
00253                         maxT[i] = (candPlane[i] - origin[i]) / dir[i];
00254                 } else {
00255                         maxT[i] = GFX_REAL_MAX;
00256                 }
00257         }
00258     
00259         /* largest max t */
00260         whichPlane = 0;
00261         for(int i=1;i<NUMDIM;i++) {
00262                 if(maxT[whichPlane] > maxT[i]) whichPlane = i;
00263         }
00264     
00265         /* check final candidate */
00266         hit  = true;
00267         if(maxT[whichPlane] != GFX_REAL_MAX) {
00268 
00269                 for(int i=0;i<NUMDIM;i++) {
00270                         if(whichPlane != i) {
00271                                 coord[i] = origin[i] + maxT[whichPlane] * dir[i];
00272                                 if( (coord[i] < mStart[i]-getVecEpsilon() ) || 
00273                                                 (coord[i] > mEnd[i]  +getVecEpsilon() )  ) {
00274                                         /* no hit... */
00275                                         hit  = false;
00276                                 } 
00277                         }
00278                         else {
00279                                 coord[i] = candPlane[i];
00280                         }      
00281                 }
00282 
00283                 /* AABB hit... */
00284                 if( hit ) {
00285                         t = maxT[whichPlane];
00286         
00287                         if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
00288                         else normal[whichPlane] = -1.0;
00289                 }
00290         }
00291     
00292 
00293   if(t == GFX_REAL_MAX) t = -1.0;
00294   retnormal = normal;
00295   retcoord = coord;
00296 }
00297 #endif // ELBEEM_PLUGIN
00298 
00300 void ntlRay::intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const
00301 {
00302   char   inside = true;   /* inside box? */
00303   char   hit    = false;  /* ray hits box? */
00304   int    whichPlane;      /* intersection plane */
00305   gfxReal candPlane[NUMDIM]; /* candidate plane */
00306   gfxReal quadrant[NUMDIM];  /* quadrants */
00307   gfxReal maxT[NUMDIM];    /* max intersection T for planes */
00308   ntlVec3Gfx  coord;           /* intersection point */
00309   ntlVec3Gfx  dir = mDirection;
00310   ntlVec3Gfx  origin = mOrigin;
00311   gfxReal t = GFX_REAL_MAX;
00312 
00313   /* check intersection planes for AABB */
00314   for(int i=0;i<NUMDIM;i++) {
00315     if(origin[i] < mStart[i]) {
00316       quadrant[i] = LEFT;
00317       candPlane [i] = mStart[i];
00318       inside = false;
00319     } else if(origin[i] > mEnd[i]) {
00320       quadrant[i] = RIGHT;
00321       candPlane[i] = mEnd[i];
00322       inside = false;
00323     } else {
00324       /* intersect with backside */
00325       if(dir[i] > 0) {
00326                                 quadrant[i] = LEFT;
00327                                 candPlane [i] = mStart[i];
00328       } else 
00329                                 if(dir[i] < 0) {
00330                                         quadrant[i] = RIGHT;
00331                                         candPlane[i] = mEnd[i];
00332                                 } else {
00333                                         quadrant[i] = MIDDLE;
00334                                 }
00335     }
00336   }
00337 
00338   /* get t distances to planes */
00339   for(int i=0;i<NUMDIM;i++) {
00340     if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
00341       maxT[i] = (candPlane[i] - origin[i]) / dir[i];
00342     } else {
00343       maxT[i] = GFX_REAL_MAX;
00344     }
00345   }
00346  
00347   /* largest max t */
00348   whichPlane = 0;
00349   for(int i=1;i<NUMDIM;i++) {
00350     if( ((maxT[whichPlane] < maxT[i])&&(maxT[i]!=GFX_REAL_MAX)) ||
00351                                 (maxT[whichPlane]==GFX_REAL_MAX) )
00352       whichPlane = i;
00353   }
00354     
00355   /* check final candidate */
00356   hit  = true;
00357   if(maxT[whichPlane]<GFX_REAL_MAX) {
00358     for(int i=0;i<NUMDIM;i++) {
00359       if(whichPlane != i) {
00360                                 coord[i] = origin[i] + maxT[whichPlane] * dir[i];
00361                                 if( (coord[i] < mStart[i]-getVecEpsilon() ) || 
00362                                                 (coord[i] > mEnd[i]  +getVecEpsilon() )  ) {
00363                                         /* no hit... */
00364                                         hit  = false;
00365                                 } 
00366       }
00367       else { coord[i] = candPlane[i];   }      
00368     }
00369 
00370     /* AABB hit... */
00371     if( hit ) {
00372       t = maxT[whichPlane];     
00373     }
00374   }
00375   tmin = t;
00376 
00377   /* now the backside */
00378   t = GFX_REAL_MAX;
00379   for(int i=0;i<NUMDIM;i++) {
00380     if(origin[i] < mStart[i]) {
00381       quadrant[i] = LEFT;
00382       candPlane [i] = mEnd[i];
00383     } else if(origin[i] > mEnd[i]) {
00384       quadrant[i] = RIGHT;
00385       candPlane[i] = mStart[i];
00386     } else {
00387       if(dir[i] > 0) {
00388                                 quadrant[i] = LEFT;
00389                                 candPlane [i] = mEnd[i];
00390       } else 
00391                                 if(dir[i] < 0) {
00392                                         quadrant[i] = RIGHT;
00393                                         candPlane[i] = mStart[i];
00394                                 } else {
00395                                         quadrant[i] = MIDDLE;
00396                                 }
00397     }
00398   }
00399 
00400 
00401   /* get t distances to planes */
00402   for(int i=0;i<NUMDIM;i++) {
00403     if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
00404       maxT[i] = (candPlane[i] - origin[i]) / dir[i];
00405     } else {
00406       maxT[i] = GFX_REAL_MAX;
00407     }
00408   }
00409     
00410   /* smallest max t */
00411   whichPlane = 0;
00412   for(int i=1;i<NUMDIM;i++) {
00413     if(maxT[whichPlane] > maxT[i]) whichPlane = i;
00414   }
00415     
00416   /* check final candidate */
00417   hit  = true;
00418   if(maxT[whichPlane] != GFX_REAL_MAX) {
00419 
00420     for(int i=0;i<NUMDIM;i++) {
00421       if(whichPlane != i) {
00422                                 coord[i] = origin[i] + maxT[whichPlane] * dir[i];
00423                                 if( (coord[i] < mStart[i]-getVecEpsilon() ) || 
00424                                                 (coord[i] > mEnd[i]  +getVecEpsilon() )  ) {
00425                                         /* no hit... */
00426                                         hit  = false;
00427                                 } 
00428       }
00429       else {
00430                                 coord[i] = candPlane[i];
00431       }      
00432     }
00433 
00434     /* AABB hit... */
00435     if( hit ) {
00436       t = maxT[whichPlane];
00437     }
00438   }
00439    
00440   tmax = t;
00441 }
00442 
00443 
00444 
00445 /******************************************************************************
00446  * Determine color of this ray by tracing through the scene
00447  *****************************************************************************/
00448 const ntlColor ntlRay::shade() //const
00449 {
00450 #ifndef ELBEEM_PLUGIN
00451   ntlGeometryObject           *closest = NULL;
00452   gfxReal                      minT = GFX_REAL_MAX;
00453   vector<ntlLightObject*>     *lightlist = mpGlob->getLightList();
00454   mpGlob->setCounterShades( mpGlob->getCounterShades()+1 );
00455         bool intersectionInside = 0;
00456         if(mpGlob->getDebugOut() > 5) errorOut(std::endl<<"New Ray: depth "<<mDepth<<", org "<<mOrigin<<", dir "<<mDirection );
00457 
00458         /* check if this ray contributes enough */
00459         if(mContribution <= RAY_MINCONTRIB) {
00460                 //return ntlColor(0.0);
00461         }
00462         
00463   /* find closes object that intersects */
00464         ntlTriangle *tri = NULL;
00465         ntlVec3Gfx normal;
00466         mpGlob->getRenderScene()->intersectScene(*this, minT, normal, tri, 0);
00467         if(minT>0) {
00468                 closest = mpGlob->getRenderScene()->getObject( tri->getObjectId() );
00469         }
00470 
00471   /* object hit... */
00472   if (closest != NULL) {
00473 
00474                 ntlVec3Gfx triangleNormal = tri->getNormal();
00475                 if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) errorOut("ntlRay warning: trinagle normal= 0 "); // DEBUG
00476                 /* intersection on inside faces? if yes invert normal afterwards */
00477                 gfxReal valDN; // = mDirection | normal;
00478                 valDN = dot(mDirection, triangleNormal);
00479                 if( valDN > 0.0) {
00480                         intersectionInside = 1;
00481                         normal = normal * -1.0;
00482                         triangleNormal = triangleNormal * -1.0;
00483                 } 
00484 
00485     /* ... -> do reflection */
00486     ntlVec3Gfx intersectionPosition(mOrigin + (mDirection * (minT)) );
00487     ntlMaterial *clossurf = closest->getMaterial();
00488                 /*if(mpGlob->getDebugOut() > 5) {
00489                         errorOut("Ray hit: at "<<intersectionPosition<<" n:"<<normal<<"    dn:"<<valDN<<" ins:"<<intersectionInside<<"  cl:"<<((unsigned int)closest) ); 
00490                         errorOut(" t1:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[0])<<" t2:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[1])<<" t3:"<<mpGlob->getScene()->getVertex(tri->getPoints()[2]) ); 
00491                         errorOut(" trin:"<<tri->getNormal() );
00492                 } // debug */
00493 
00494                 /* current transparence and reflectivity */
00495                 gfxReal currTrans = clossurf->getTransparence();
00496                 gfxReal currRefl = clossurf->getMirror();
00497 
00498     /* correct intersectopm position */
00499     intersectionPosition += ( triangleNormal*getVecEpsilon() );
00500                 /* reflection at normal */
00501                 ntlVec3Gfx reflectedDir = getNormalized( reflectVector(mDirection, normal) );
00502                 int badRefl = 0;
00503                 if(dot(reflectedDir, triangleNormal)<0.0 ) {
00504                         badRefl = 1;
00505                         if(mpGlob->getDebugOut() > 5) { errorOut("Ray Bad reflection...!"); }
00506                 }
00507 
00508                 /* refraction direction, depending on in/outside hit */
00509                 ntlVec3Gfx refractedDir;
00510                 int refRefl = 0;
00511                 /* refraction at normal is handled by inverting normal before */
00512                 gfxReal myRefIndex = 1.0;
00513                 if((currTrans>RAY_THRESHOLD)||(clossurf->getFresnel())) {
00514                         if(intersectionInside) {
00515                                 myRefIndex = 1.0/clossurf->getRefracIndex();
00516                         } else {
00517                                 myRefIndex = clossurf->getRefracIndex();
00518                         }
00519 
00520                         refractedDir = refractVector(mDirection, normal, myRefIndex , (gfxReal)(1.0) /* global ref index */, refRefl);
00521                 }
00522 
00523                 /* calculate fresnel? */
00524                 if(clossurf->getFresnel()) {
00525                         // for total reflection, just set trans to 0
00526                         if(refRefl) {
00527                                 currRefl = 1.0; currTrans = 0.0;
00528                         } else {
00529                                 // calculate fresnel coefficients
00530                                 clossurf->calculateFresnel( mDirection, normal, myRefIndex, currRefl,currTrans );
00531                         }
00532                 }
00533 
00534     ntlRay reflectedRay(intersectionPosition, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
00535                 reflectedRay.setNormal( normal );
00536     ntlColor currentColor(0.0);
00537     ntlColor highlightColor(0.0);
00538 
00539     /* first add reflected ambient color */
00540     currentColor += (clossurf->getAmbientRefl() * mpGlob->getAmbientLight() );
00541 
00542     /* calculate lighting, not on the insides of objects... */
00543                 if(!intersectionInside) {
00544                         for (vector<ntlLightObject*>::iterator iter = lightlist->begin();
00545                                          iter != lightlist->end();
00546                                          iter++) {
00547                                 
00548                                 /* let light illuminate point */
00549                                 currentColor += (*iter)->illuminatePoint( reflectedRay, closest, highlightColor );
00550                                 
00551                         } // for all lights
00552                 }
00553 
00554     // recurse ?
00555     if ((mDepth < mpGlob->getRayMaxDepth() )&&(currRefl>RAY_THRESHOLD)) {
00556 
00557                                 if(badRefl) {
00558                                         ntlVec3Gfx intersectionPosition2;
00559                                         ntlGeometryObject           *closest2 = NULL;
00560                                         gfxReal                      minT2 = GFX_REAL_MAX;
00561                                         ntlTriangle *tri2 = NULL;
00562                                         ntlVec3Gfx normal2;
00563 
00564                                         ntlVec3Gfx refractionPosition2(mOrigin + (mDirection * minT) );
00565                                         refractionPosition2 -= (triangleNormal*getVecEpsilon() );
00566 
00567                                         ntlRay reflectedRay2 = ntlRay(refractionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
00568                                         mpGlob->getRenderScene()->intersectScene(reflectedRay2, minT2, normal2, tri2, 0);
00569                                         if(minT2>0) {
00570                                                 closest2 = mpGlob->getRenderScene()->getObject( tri2->getObjectId() );
00571                                         }
00572 
00573                                         /* object hit... */
00574                                         if (closest2 != NULL) {
00575                                                 ntlVec3Gfx triangleNormal2 = tri2->getNormal();
00576                                                 gfxReal valDN2; 
00577                                                 valDN2 = dot(reflectedDir, triangleNormal2);
00578                                                 if( valDN2 > 0.0) {
00579                                                         triangleNormal2 = triangleNormal2 * -1.0;
00580                                                         intersectionPosition2 = ntlVec3Gfx(intersectionPosition + (reflectedDir * (minT2)) );
00581                                                         /* correct intersection position and create new reflected ray */
00582                                                         intersectionPosition2 += ( triangleNormal2*getVecEpsilon() );
00583                                                         reflectedRay = ntlRay(intersectionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
00584                                                 } else { 
00585                                                         // ray seems to work, continue normally ?
00586                                                 }
00587 
00588                                         }
00589 
00590                                 }
00591 
00592       // add mirror color multiplied by mirror factor of surface
00593                         if(mpGlob->getDebugOut() > 5) errorOut("Reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
00594                         ntlColor reflectedColor = reflectedRay.shade() * currRefl;
00595                         currentColor += reflectedColor;
00596     }
00597 
00598     /* Trace another ray on for transparent objects */
00599     if(currTrans > RAY_THRESHOLD) {
00600       /* position at the other side of the surface, along ray */
00601       ntlVec3Gfx refraction_position(mOrigin + (mDirection * minT) );
00602       refraction_position += (mDirection * getVecEpsilon());
00603                         refraction_position -= (triangleNormal*getVecEpsilon() );
00604       ntlColor refracCol(0.0);         /* refracted color */
00605 
00606       /* trace refracted ray */
00607       ntlRay transRay(refraction_position, refractedDir, mDepth+1, mContribution*currTrans, mpGlob);
00608       transRay.setRefracted(1);
00609                         transRay.setNormal( normal );
00610       if(mDepth < mpGlob->getRayMaxDepth() ) {
00611                                 // full reflection should make sure refracindex&fresnel are on...
00612                                 if((0)||(!refRefl)) {
00613                                         if(mpGlob->getDebugOut() > 5) errorOut("Refracted ray from depth "<<mDepth<<", dir "<<refractedDir );
00614                                         refracCol = transRay.shade();
00615                                 } else { 
00616                                         //we shouldnt reach this!
00617                                         if(mpGlob->getDebugOut() > 5) errorOut("Fully reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
00618                                         refracCol = reflectedRay.shade();
00619                                 }
00620       }
00621                         //errMsg("REFMIR","t"<<currTrans<<" thres"<<RAY_THRESHOLD<<" mirr"<<currRefl<<" refRefl"<<refRefl<<" md"<<mDepth);
00622 
00623       /* calculate color */
00624                         // use transadditive setting!?
00625       /* additive transparency "light amplification" */
00626       //? ntlColor add_col = currentColor + refracCol * currTrans;
00627       /* mix additive and subtractive */
00628                         //? add_col += sub_col;
00629                         //? currentColor += (refracCol * currTrans);
00630 
00631       /* subtractive transparency, more realistic */
00632       ntlColor sub_col = (refracCol * currTrans) + ( currentColor * (1.0-currTrans) );
00633                         currentColor = sub_col;
00634 
00635     }
00636 
00637                 /* add highlights (should not be affected by transparence as the diffuse reflections */
00638                 currentColor += highlightColor;
00639 
00640                 /* attentuate as a last step*/
00641                 /* check if we're on the inside or outside */
00642                 if(intersectionInside) {
00643                         gfxReal kr,kg,kb;    /* attentuation */
00644                         /* calculate attentuation */
00645                         ntlColor attCol = clossurf->getTransAttCol();
00646                         kr = exp( attCol[0] * minT );
00647                         kg = exp( attCol[1] * minT );
00648                         kb = exp( attCol[2] * minT );
00649                         currentColor = currentColor * ntlColor(kr,kg,kb);
00650                 }
00651 
00652     /* done... */
00653                 if(mpGlob->getDebugOut() > 5) { errorOut("Ray "<<mDepth<<" color "<<currentColor ); }
00654     return ntlColor(currentColor);
00655   }
00656 
00657 #endif // ELBEEM_PLUGIN
00658   /* no object hit -> ray goes to infinity */
00659   return mpGlob->getBackgroundCol(); 
00660 }
00661 
00662 
00663 
00664 /******************************************************************************
00665  ******************************************************************************
00666  ******************************************************************************
00667  * scene implementation
00668  ******************************************************************************
00669  ******************************************************************************
00670  *****************************************************************************/
00671 
00672 
00673 
00674 /******************************************************************************
00675  * Constructor
00676  *****************************************************************************/
00677 ntlScene::ntlScene( ntlRenderGlobals *glob, bool del ) :
00678         mpGlob( glob ), mSceneDel(del),
00679         mpTree( NULL ),
00680         mDisplayListId( -1 ), 
00681         mSceneBuilt( false ), mFirstInitDone( false )
00682 {
00683 }
00684 
00685 
00686 /******************************************************************************
00687  * Destructor
00688  *****************************************************************************/
00689 ntlScene::~ntlScene()
00690 {
00691         if(mpTree != NULL) delete mpTree;
00692 
00693         // cleanup lists, only if this is the rendering cleanup scene
00694         if(mSceneDel) 
00695         {
00696                 for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
00697                                 iter != mGeos.end(); iter++) {
00698                         //errMsg("ntlScene::~ntlScene","Deleting obj "<<(*iter)->getName() );
00699                         delete (*iter);
00700                 }
00701                 for (vector<ntlLightObject*>::iterator iter = mpGlob->getLightList()->begin();
00702                                  iter != mpGlob->getLightList()->end(); iter++) {
00703                         delete (*iter);
00704                 }
00705                 for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
00706                                  iter != mpGlob->getMaterials()->end(); iter++) {
00707                         delete (*iter);
00708                 }
00709         }
00710         errMsg("ntlScene::~ntlScene","Deleted, ObjFree:"<<mSceneDel);
00711 }
00712 
00713 
00714 /******************************************************************************
00715  * Build the scene arrays (obj, tris etc.)
00716  *****************************************************************************/
00717 void ntlScene::buildScene(double time,bool firstInit)
00718 {
00719         const bool buildInfo=true;
00720 
00721         if(firstInit) {
00722                 mObjects.clear();
00723                 /* init geometry array, first all standard objects */
00724                 for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
00725                                 iter != mGeos.end(); iter++) {
00726                         bool geoinit = false;
00727                         int tid = (*iter)->getTypeId();
00728                         if(tid & GEOCLASSTID_OBJECT) {
00729                                 ntlGeometryObject *geoobj = (ntlGeometryObject*)(*iter);
00730                                 geoinit = true;
00731                                 mObjects.push_back( geoobj );
00732                                 if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added GeoObj "<<geoobj->getName()<<" Id:"<<geoobj->getObjectId(), 5 );
00733                         }
00734                         //if(geoshad) {
00735                         if(tid & GEOCLASSTID_SHADER) {
00736                                 ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
00737                                 geoinit = true;
00738                                 if(!mFirstInitDone) {
00739                                         // only on first init
00740                                         geoshad->initializeShader();
00741                                 }
00742                                 for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
00743                                                 siter != geoshad->getObjectsEnd();
00744                                                 siter++) {
00745                                         if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName()<<" Id:"<<(*siter)->getObjectId(), 5 );
00746                                         mObjects.push_back( (*siter) );
00747                                 }
00748                         }
00749 
00750                         if(!geoinit) {
00751                                 errFatal("ntlScene::BuildScene","Invalid geometry class!", SIMWORLD_INITERROR);
00752                                 return;
00753                         }
00754                 }
00755         }
00756 
00757         // collect triangles
00758         mTriangles.clear();
00759         mVertices.clear();
00760         mVertNormals.clear();
00761 
00762         /* for test mode deactivate transparencies etc. */
00763         if( mpGlob->getTestMode() ) {
00764                 debugOut("ntlScene::buildScene : Test Mode activated!", 2);
00765                 // assign random colors to dark materials
00766                 int matCounter = 0;
00767                 ntlColor stdCols[] = { ntlColor(0,0,1.0), ntlColor(0,1.0,0), ntlColor(1.0,0.7,0) , ntlColor(0.7,0,0.6) };
00768                 int stdColNum = 4;
00769                 for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
00770                                          iter != mpGlob->getMaterials()->end(); iter++) {
00771                         (*iter)->setTransparence(0.0);
00772                         (*iter)->setMirror(0.0);
00773                         (*iter)->setFresnel(false);
00774                         // too dark?
00775                         if( norm((*iter)->getDiffuseRefl()) <0.01) {
00776                                 (*iter)->setDiffuseRefl( stdCols[matCounter] );
00777                                 matCounter ++;
00778                                 matCounter = matCounter%stdColNum;
00779                         }
00780                 }
00781 
00782                 // restrict output file size to 400
00783                 float downscale = 1.0;
00784                 if(mpGlob->getResX() > 400){ downscale = 400.0/(float)mpGlob->getResX(); }
00785                 if(mpGlob->getResY() > 400){ 
00786                         float downscale2 = 400.0/(float)mpGlob->getResY(); 
00787                         if(downscale2<downscale) downscale=downscale2;
00788                 }
00789                 mpGlob->setResX( (int)(mpGlob->getResX() * downscale) );
00790                 mpGlob->setResY( (int)(mpGlob->getResY() * downscale) );
00791 
00792         }
00793 
00794         /* collect triangles from objects */
00795         int idCnt = 0;          // give IDs to objects
00796         bool debugTriCollect = false;
00797         if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Start...",5);
00798   for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin();
00799        iter != mObjects.end();
00800        iter++) {
00801                 /* only add visible objects */
00802                 if(firstInit) {
00803                         if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collect init of "<<(*iter)->getName()<<" idCnt:"<<idCnt, 4 );
00804                         (*iter)->initialize( mpGlob ); }
00805                 if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collecting tris from "<<(*iter)->getName(), 4 );
00806 
00807                 int vstart = mVertNormals.size();
00808                 (*iter)->setObjectId(idCnt);
00809                 (*iter)->getTriangles(time, &mTriangles, &mVertices, &mVertNormals, idCnt);
00810                 (*iter)->applyTransformation(time, &mVertices, &mVertNormals, vstart, mVertices.size(), false );
00811 
00812                 if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Done with "<<(*iter)->getName()<<" totTris:"<<mTriangles.size()<<" totVerts:"<<mVertices.size()<<" totNorms:"<<mVertNormals.size(), 4 );
00813                 idCnt ++;
00814         }
00815         if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"End",5);
00816 
00817 
00818         /* calculate triangle normals, and initialize flags */
00819   for (vector<ntlTriangle>::iterator iter = mTriangles.begin();
00820        iter != mTriangles.end();
00821        iter++) {
00822 
00823                 // calculate normal from triangle points
00824                 ntlVec3Gfx normal = 
00825                         cross( (ntlVec3Gfx)( (mVertices[(*iter).getPoints()[2]] - mVertices[(*iter).getPoints()[0]]) *-1.0),  // BLITZ minus sign right??
00826                         (ntlVec3Gfx)(mVertices[(*iter).getPoints()[1]] - mVertices[(*iter).getPoints()[0]]) );
00827                 normalize(normal);
00828                 (*iter).setNormal( normal );
00829         }
00830 
00831 
00832 
00833         // scene geometry built 
00834         mSceneBuilt = true;
00835 
00836         // init shaders that require complete geometry
00837         if(!mFirstInitDone) {
00838                 // only on first init
00839                 for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
00840                                 iter != mGeos.end(); iter++) {
00841                         if( (*iter)->getTypeId() & GEOCLASSTID_SHADER ) {
00842                                 ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
00843                                 if(geoshad->postGeoConstrInit( mpGlob )) {
00844                                         errFatal("ntlScene::buildScene","Init failed for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
00845                                         return;
00846                                 }
00847                         }
00848                 }
00849                 mFirstInitDone = true;
00850         }
00851 
00852         // check unused attributes (for classes and objects!)
00853   for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin(); iter != mObjects.end(); iter++) {
00854                 if((*iter)->getAttributeList()->checkUnusedParams()) {
00855                         (*iter)->getAttributeList()->print(); // DEBUG
00856                         errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
00857                         return;
00858                 }
00859         }
00860         for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin(); iter != mGeos.end(); iter++) { 
00861                 if((*iter)->getAttributeList()->checkUnusedParams()) {
00862                         (*iter)->getAttributeList()->print(); // DEBUG
00863                         errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
00864                         return;
00865                 }
00866         }
00867 
00868 }
00869 
00870 /******************************************************************************
00871  * Prepare the scene triangles and maps for raytracing
00872  *****************************************************************************/
00873 void ntlScene::prepareScene(double time)
00874 {
00875         /* init triangles... */
00876         buildScene(time, false);
00877         // what for currently not used ???
00878         if(mpTree != NULL) delete mpTree;
00879         mpTree = new ntlTree( 
00880 #                       if FSGR_STRICT_DEBUG!=1
00881                         mpGlob->getTreeMaxDepth(), mpGlob->getTreeMaxTriangles(), 
00882 #                       else
00883                         mpGlob->getTreeMaxDepth()/3*2, mpGlob->getTreeMaxTriangles()*2, 
00884 #                       endif
00885                         this, TRI_GEOMETRY );
00886 
00887         //debMsgStd("ntlScene::prepareScene",DM_MSG,"Stats - tris:"<< (int)mTriangles.size()<<" verts:"<<mVertices.size()<<" vnorms:"<<mVertNormals.size(), 5 );
00888 }
00889 /******************************************************************************
00890  * Do some memory cleaning, when frame is finished
00891  *****************************************************************************/
00892 void ntlScene::cleanupScene( void )
00893 {
00894         mTriangles.clear();
00895         mVertices.clear();
00896         mVertNormals.clear();
00897 
00898         if(mpTree != NULL) delete mpTree;
00899         mpTree = NULL;
00900 }
00901 
00902 
00903 /******************************************************************************
00904  * Intersect a ray with the scene triangles
00905  *****************************************************************************/
00906 void ntlScene::intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri,int flags) const
00907 {
00908         distance = -1.0;
00909   mpGlob->setCounterSceneInter( mpGlob->getCounterSceneInter()+1 );
00910         mpTree->intersect(r, distance, normal, tri, flags, false);
00911 }
00912 
00913 
00914 
00915 
00916