Incorporating Proportional Light Scattering

[ LiB ]

Incorporating Proportional Light Scattering

A better technique for light scattering utilizes a smarter method of distributing photons from a diffuse point light. The algorithm shoots a fixed number of photons in a spiral fashion from a light source towards each object in the scene. This means that instead of releasing 1000 photons from a light source, 1000 photons would be shot towards each object in the scene.

The light source wattage is found by the following formula:

Emitted Photons = Targeted Photons Number of objects in Scene

As you can see, you are going to be selective about how you release photons from the light sources. I choose not to calculate random photons that go into space and do nothing. This way each object is targeted a baseline number of photons. Targeting photons towards objects is a better method of distributing photonsit saves time and memory.

Upgrading the PhotonMap Class

A variable is required to count the number of photons that are targeted towards each object in the scene. You need to add this variable to the PhotonMap class.

 long      lMaxPhotonPerObject; 

You also need to implement an algorithm to scatter photons in a proportional manner. The notion of releasing individual photons from a light source is the same as in the simple scattering technique but changes because these photons are unequally distributed and proportionally targeted towards objects in the scene. See Figure 11.4 for an example.

Figure 11.4. An example of shooting photons proportionally at the objects in the scene from a light source.

graphic/11fig04.gif


One problem with this is that the equal emission concept of energy being released from a light source just went out the window. This is because the light source doesn't give off equal energy (1/emitted) for each emitted pho-ton anymore. This means that wasted photons that go into space and do nothing are not calculated anymore. You calculate only the energy that is proportional to the surface. This requires a new method of giving each pho-ton a portion of the light source wattage.

In order to simulate photons being released from a light source and proportionally target them towards objects in the scene, you need a local coordinate system. The local coordinate system guides the photons to their destinations from the light sources in the scene. The local coordinate system is very similar to the camera coordinate system developed earlier in the book. The process of shooting rays from the camera towards objects in the scene can be adapted to shootings rays from a light source to the objects in the scene. This means that same local X, Y, and Z axes must be evaluated. Consider a simple example first.

Pretend a polygon is sitting 30 units into the screen and is lying flat on the X and Y world axes. The light is located at (0,0,-5) and the observer is at (0,0,-10). See Figure 11.5 for an example.

Figure 11.5. This polygon example involves a polygon sitting in front of the light and the observer.

graphic/11fig05.gif


You now need to create a local coordinate system to scatter photons from the light source to the polygon. You need to find the LOOK and UP vectors. You don't have to search for the RIGHT vector because you can easily find it using the LOOK and UP vectors.

To find the LOOK vector between the light and the polygon, you simply subtract the center point of the polygon from the light source position. This creates the local Z axis for the local coordinate system. See Figure 11.6 for an example.

Figure 11.6. The Z axis of the local coordinate system is computed by subtracting the center point of the object from the light source position.

graphic/11fig06.gif


Adding the UP vector to the local coordinate system is not as easy as aligning it to the world Y axis. Remember this is a local coordinate system relative to the world coordinate system and can change dynamically if required. For example, the X and Y axes of the local coordinate system can be aligned with the world X and Z axes. Sometimes the UP vector can be rotated in a way where it's parallel to the world's X axes, like you learned in Chapter 8.

By looking at the individual X, Y, and Z components of the LOOK vector, you can determine where the UP vector is pointing.

If the absolute value of the X component is more or equal to 1.0 (which dictates the LOOK vector is parallel to the world X axis), the UP vector is parallel to the world's Y axis. See Figure 11.7 for an example.

Figure 11.7. The UP vector is set to the world Y axis (0,1,0) because the LOOK vec- tor's X component is more than or equal to 1.0.The LOOK vector is therefore parallel to the world X axis (1,0,0).

graphic/11fig07.gif


If the absolute value of the Z component is more than or equal to 1.0 (which dictates that the LOOK vector is parallel with the world Z axis), the UP vector is still parallel to the world's Y axis. If the X and Z components are not 1.0, on the other hand, the UP vector is parallel to the world X axis.

By having the LOOK and UP vectors, you can easily find the local X, Y, and Z axes of the local coordinate system, as follows :

  • You can find the Z axis (or LOOK vector) of the local coordinate system by subtracting the center point of an object from light source position.

  • You can find the X axis (or RIGHT vector) by crossing the LOOK vector with the UP vector.

  • To find the Y axis, you simply cross the X axis with the LOOK vector.

This creates a local coordinate system that is orthogonal; these local X, Y, and Z axes vectors are 90 degrees apart. Let's write a method that creates the local coordinate system between the light source and the center point of an object. See Figure 11.8 for an example of the local coordinate system.

Figure 11.8. The local coordinate system is used to shoot pho- tons from the light source to an object in the scene.

graphic/11fig08.gif


NOTE

NOTE

The MakeXY() method uses the LOOK and UP vectors to create a local coordinate system.The ray travels from a light source to a surface in the scene.

Calculating the X and Y Axes

The MakeXY() method is used to calculate the remaining two axes of the local coordinate system. The Z axis ( LOOK vector) is already calculated by subtracting the center point of the object from the light source position. The LOOK vector is passed as V . The other two pointers ( vX and vY ) will be the local X and Y axes after the method calculates them.

 #define TINY (1.0e-10) // 1.0000000000 void PhotonMap::MakeXY( cVector3 *vX, cVector3 *vY, cVector3 V ) {  cVector3 U; // UP Vector  V.Normalize();  if( fabs(V.x) > TINY  fabs(V.z) > TINY )  {    U.x = 0.0;     U.y = 1.0;     U.z = 0.0;   }   else   {     U.x = 1.0;     U.y = 0.0;     U.z = 0.0;   }   *vX = (V   ^ U); // local X Axis   vX->Normalize();   *vY = (*vX ^ V); // local Y Axis   vY->Normalize(); } 

The previous method enables you to begin spawning photons from the light source towards objects in the scene. The origin of each ray travels along the local Z axis, intersecting points on the local X and Y axes where the object sits. This is wonderful because you need to randomly shoot photons and calculate intersections on the object of interest along the local X and Y axes.

The scattering algorithm utilizes the center point and the bounding sphere of an object to create random photons along a disk. The photons will leave the light source, targeting random points around the center point of the object. Consider an example of spiraling photons towards a disk. The pho-tons will originate from the local Z axis (light source to center point), targeting random (x, y) locations on the X and Y axes of the local coordinate system. The spiral fashion of photons being targeted towards objects results in a higher number of intersections. This in turn limits the work to only where photons intersect objects.

This process is like shining a flashlight on an object. The greater the distance between you and the object, the dimmer the illumination on the object. If you shine the flashlight very close to the object, you can see the object lit up more brightly with greater detail. More photons are gathered on a surface, thus generating a more detailed image. Because a scene can have n amount of lights that emit n amount of photons per object, you need to somehow scale each photon down to the light source wattage.

The incoming illumination towards an object is what you'll use to scale a photon. Each photon will carry a portion of the total incoming illumination for the object. The formula for doing this is straightforward:

Photon Power = Area of the Object / Incoming Photons per Object

NOTE

TIP

Scattering photons proportionally towards objects in the scene increases efficiency for photon mapping because it guarantees that each object receives a minimum amount of incoming illumination.

The logic of proportionally shooting photons towards objects involves choosing each light source and then cycling through each object in the scene. The next step is to shoot n amount of photons towards each object from the light source. The photons will be shot in a spiral fashion towards each object's center point. This is where the local coordinate system will be utilized. For each targeted photon, its power is scaled by the area of the object divided by the number of shot photons to the object. Now if an intersection has occurred the behavior of the photon must be handled. Of course, this will be handled in ProcessPhotonHit() . Now, let's take a look at the algorithmic description of proportional scattering:

  1. For each light source in the scene.

  2. For each object in the scene.

  3. For n amount of photons to shoot at object.

  4. Shoot Spiral Photon towards Object Center.

  5. Scale Photon Power by (Object Area / n amount of photons shot).

  6. Shoot Photon in Scene.

  7. Find the closest intersection.

  8. Process the photon at the point of intersection. This logic for the point of intersection is done by calling a special method called ProcessPhotonHit() .

As you can see the algorithm is not very complicated. However, the algorithm is a bit cumbersome, which means it might be a bit slow. The method you'll use to create photons that proportionally scatter towards objects in the scene will be located in the cScene class. You need to utilize the intersection method in the cScene class. The method's purpose is to distribute photons in a proportional manner towards objects in the scene. It will use less time and memory as compared to the simple scattering algorithm. The method will cycle through each light object in the cScene array and shoot n amount of photons towards each object in the scene in a spiral fashion. The result of using a smarter way to scatter photons is more intersections encountered with less processing time.

 void cScene::CreatePhotons() { 

Using the Many Local Variables

The following function utilizes a variety of local variables. The local variables are going to be used for the scattering algorithm. A few counter variables are created for array loops . Variables are created to hold a photon's power, its direction, and its destination points. A series of small variables construct a disk that will be created on the surface of the object of interest. A few statistic variables are used to inform the user of what's going on in the scattering process. These are variables used to fire, count, translate, and scale photons. A for loop begins looping through each light in the scene; another loop then cycles through each object in the scene for each light.

 int      i,j,k; cLight   tLight; cVector3 tObjCenter; float    dObjRadius; cVector3 tToCenter; cVector3 tX, tY; float    Power, x, y, dx, dy; int       ix, iy, nx, ny; cVector3 tDisk; cVector3 tPhotonDest, tPhotonDir; cVector3 tInter; int iHitIndex; long lFired, lHits; photon_t tPhoton; for (i = 0; i <  this->nLightCount;  i++) {    tLight = pLightList [i];    for (j = 0; j < this->nObjectCount; j++)    { 

Referencing the Object Radius

A few variables are used to count the amount of shot photons from the amount of intersected photons. The object center and radius are referenced as well as the distance from the object to the light source.

 lFired = lHits = 0; tObjCenter = pObjectList[j].ObjectCenter(); dObjRadius = pObjectList[j].ObjectRadius(tObjCenter) * 1.1f; tToCenter  = tObjCenter - tLight.vPosition; 

Calculating the X and Y Axes

The LOOK vector is passed into the MakeXY() method. The method will now calculate the orthogonal X and Y axes vectors and save them to the passed pointers.

 MakeXY(&tX,&tY,  (tLight.vPosition - tObjCenter)   ); 

Scaling Each Photon's Power

The power of a photon has changed from 1/number of emitted photons to the Area of the Object / Incoming Photons per Object. The area of the object is found by PI * Radius * Radius. The power of each photon (or the irradiance) is the area of the object divided by the emitted photons from the light source towards the object. This is the amount of incoming flux targeted towards the object where each photon carries a portion.

 Power = (3.1415926f * dObjRadius * dObjRadius)                                   / lMaxPhotonPerObject; 

The Spiral Distribution Algorithm

The spiral distribution algorithm is an elegant method used to shoot photons in a spiral pattern around the center point of the object. See Figure 11.9 for an example of targeting photons. A simple geometric disk is used. After an intersection is found on the disk, the ray's destination subtracted from the ray origin (light source) yields the ray's direction.

Figure 11.9. The generated random photons are stored around a center point by using the spiral dis tribution algorithm.

graphic/11fig09.gif


 nx = ny = (int) sqrt(lMaxPhotonPerObject);       ix = iy = 0; dx = (2.0f * dObjRadius) / (float) nx; dy = (2.0f * dObjRadius) / (float) ny; x  = - dObjRadius; y  = - dObjRadius;  for (k = 0; k < lMaxPhotonPerObject; k++)  {      tDisk = ( (tX* (float) x) + (tY* (float) y) );    x += dx;    ix ++;    if (ix > nx)    {       ix = 0;       x = - dObjRadius;       y += dy;       iy ++;       if (iy >= ny)          break;    }    tPhotonDest = tObjCenter + tDisk;    tPhotonDir = tPhotonDest - tLight.vPosition;    tPhotonDir.Normalize(); 

Setting the Photon's Direction

The photon is set up and is ready to be cast into the scene. The photon's origin begins from the light source and its direction is targeted towards the object.

 cRay Bullet; Bullet.origin   = tLight.vPosition; Bullet.direction = tPhotonDir; 

Finding the Closest Intersection

If the photon intersected an object in the scene, the intersection point and the object index are returned. If an object was found during the intersection process, the power of the photon is set to scaled power using the previous formula. The scaled power is not the only component applied to the power of the photon because some light sources emit a specific color (ever been to a dance club?). Surely you don't think all light sources emit only white light, so coloring each emitted photon based on the light source color is a great idea which I also incorporated into the photon power. The photon is now ready to be processed . (The ProcessPhotonHit() method hasn't been explained yet so don't worry about it just yet.)

 iHitIndex = Find_Closest_Object(Bullet, &tInter );          lFired++;          if (iHitIndex > -1 && (iHitIndex == j))          {               lHits++;              // scale photon by light source times power              tPhoton.tPower = tLight.Color                         *   (float) Power;             // process photon             ProcessPhotonHit (                        iHitIndex,                        tPhotonDir,                        tInter,                        tPhoton,                        MAX_TRACE_DEPTH,                        false);          } // end if hit       } // end n photons per object          fprintf(stderr,"To Object %d: %d fired,                   %d hit\n",j,lFired,lHits);       } // end for each object      } // end for ea } // end of  method 

Finally, you can scatter photons and test for point intersections on objects using your local coordinate system. The next step is to store the photon in the photon map based on the object's material properties. Determining a photon's behavior is the next subject at hand.

[ LiB ]


Focus On Photon Mapping
Focus On Photon Mapping (Premier Press Game Development)
ISBN: 1592000088
EAN: 2147483647
Year: 2005
Pages: 128
Authors: Marlon John

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net