Example #1
0
//------------------------------------------------------------------------------
void InfiniteLight::Calc(const bs::Normal & outDir,const Intersection & inter,const Material & mat,
                         const class RenderableDB & db,bs::ColourRGB & out) const
{
 out = bs::ColourRGB(0.0,0.0,0.0);

 // Check the first step the ray takes - if we are going into the object 
 // we are lighting up or not. If so we have to adjust the loss according to its
 // transparency details, or give up if its solid.
  bs::ColourRGB loss(1.0,1.0,1.0);
  bs::Ray ray;
   ray.s = inter.point;
   ray.n = toLight;
   
  bs::Normal fromLight = toLight; 
  fromLight.Neg();

  ds::List<const Material*> inside; // Linked list of materials it is currently inside of. (Should really be optimised out. A todo I guess.)
  if ((toLight * inter.norm)<0.0)
  {
   // The ray is fired back into the material, makes the next code lump handle
   // this, or break if its solid.
    if (mat.Transparency()==false) return;
    inside.AddFront(&mat);
  }
 
 // Fire a ray from the point of intersection towards the light source, 
 // and see if it hits anything. If we bump into transparent objects extract 
 // there multipliers and keep track of the transmission rate. Give up if
 // too little light is transmitted, or we hit a solid object...
 // (This of course ignores refraction, but not much too be done about that.)  
  while (true)
  {
   // Find the next intersection point, break if it does not exist...
    Intersection inter;
    Renderable * obj;
    if (db.Intercept(ray,obj,inter)==false) break;

   // Update the loss for the materials we are within...
    bs::FiniteLine line;
     line.s = ray.s;
     line.e = inter.point;
    
    ds::List<const Material*>::Cursor targ = inside.FrontPtr();
    while (!targ.Bad())
    {
     bs::ColourRGB temp;    
      (*targ)->TransparencyLoss(line,temp);
     loss *= temp;

     ++targ;
    }

   // Update the material list and loss for the material surface we just hit....
    Renderable::MatSpec & ms = obj->mat[inter.coord.material];
    if (ms.mat->Transparency()==false) return;
    
    bs::ColourRGB temp; 
    if (ms.im) ms.im->Modify(inter);
    ms.mat->BDRF(fromLight,toLight,inter,temp); 
    loss *= temp;
    
    if ((toLight * inter.norm)<0.0)
    {
     // We are entering the object...
      inside.AddFront(ms.mat);
    }
    else
    {
     // We are exitting the object...
      ds::List<const Material*>::Cursor targ = inside.FrontPtr();
      while (!targ.Bad())
      {
       if (*targ==ms.mat) {targ.RemKillNext(); break;}    
       ++targ;
      }
    }  
   
   // Update the ray for the next casting...
    ray.s = inter.point;
  }
  
 // If we are still inside any object at this point the object must be infinite,
 // and therefore no light can get through - give up...
 // (More likelly something has gone wrong, in which case making dodgy artifacts is good to.)
  if (inside.Size()!=0) return;
  
 // If we reach this point then some light reaches and affects the object - the 
 // output is simply the strength of the light, multiplied by the tranmissive 
 // factors of the objects intersected en-route multiplied by the BDRF of the 
 // material at intersection...
  mat.BDRF(outDir,toLight,inter,out);
  out *= loss;
  out *= col;
}