Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r1097 - in trunk: Engine/Control Model/Primitives


Chronological Thread 
  • From: cgribble@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r1097 - in trunk: Engine/Control Model/Primitives
  • Date: Sun, 4 Jun 2006 14:14:26 -0600 (MDT)

Author: cgribble
Date: Sun Jun  4 14:14:24 2006
New Revision: 1097

Modified:
   trunk/Engine/Control/DynPLTWorker.cc
   trunk/Engine/Control/DynPLTWorker.h
   trunk/Model/Primitives/DynPLTGridSpheres.cc
   trunk/Model/Primitives/DynPLTGridSpheres.h
   trunk/Model/Primitives/GridSpheres.cc
   trunk/Model/Primitives/GridSpheres.h
Log:
Engine/Control/DynPLTWorker.cc
Engine/Control/DynPLTWorker.h
  Added render{Ambient,Global} functions to generate ambient occlusion or full
    global illumination textures based on DynPLTGridSphere's texture mode
  Lots of redundancy between the two functions that could be refactored

Model/Primitives/DynPLTGridSpheres.cc
Model/Primitives/DynPLTGridSpheres.h
  Added textureMode for controlling use of ambient occlusion vs. full global
    illumination textures
  Added accessors for textureMode
  Added vector<bool> allocated indicating whether or not the memory for a 
texture
    has been allocated; used to be vector<bool> valid, but will eventually 
need
    to invalidate textures (switching between ambient occlusion and global
    illumination or when lighting changes, etc.) without having to 
free/realloc
    them
  Added shade{Ambient,Global}(...) functions for using textures appropriately
    (either interpolating both ambient/direct component or just the ambient
    component)
  Added computeLuminance(...) function to remove some code redundancy

Model/Primitives/GridSpheres.cc
Model/Primitives/GridSpheres.h
  Added lambertianShade(...) function that takes an already computed ambient
    term as input
  Changed shade(...) call to reflect new lambertianShade(...) function
  Now facilitates ambient occlusion textures


Modified: trunk/Engine/Control/DynPLTWorker.cc
==============================================================================
--- trunk/Engine/Control/DynPLTWorker.cc        (original)
+++ trunk/Engine/Control/DynPLTWorker.cc        Sun Jun  4 14:14:24 2006
@@ -83,275 +83,459 @@
 
 void DynPLTWorker::run(void)
 {
-  // Grab useful information from the DynPLT context
-  unsigned int ngroups=context->ngroups;
-  unsigned int nsamples=context->nsamples;
-  unsigned int max_depth=context->max_depth;
-  Real inv_nsamples=1/static_cast<Real>(nsamples);
-
-  // Create a render context for direct lighting computations
-  Scene* scene=context->scene;
+  // Create a render context for computing ray intersections
   vector<string> args;
-  HardShadows shadowAlgorithm(args);
+  HardShadows shadows(args);
   // RenderContext(MantaInterface*, int, int, int, const FrameState*,
   //               LoadBalancer*, PixelSampler*, Renderer*, ShadowAlgorithm*,
   //               const Camera*, const Scene*, ThreadStorage*);
-  RenderContext rctx(0, 0, 0, 0, 0, 0, 0, 0, &shadowAlgorithm, 0, scene, 0);
+  RenderContext rctx(0, 0, 0, 0, 0, 0, 0, 0, &shadows, 0, context->scene, 0);
 
   DynPLTMessage msg=context->queue->receive();
   while (msg.particle>=0) {
     // Grab message data
     int particle=msg.particle;
     const DynPLTGridSpheres* grid=msg.grid;
-    
-    // Allocate new texture, if necessary
-    if (grid->plts[particle])
+
+    // Skip valid textures
+    if (grid->valid[particle])
       continue;
 
-    grid->plts[particle]=new DynPLT();
+    // Allocate new texture, if necessary
+    if (!grid->allocated[particle]) {
+      grid->plts[particle]=new DynPLT();
+      grid->allocated[particle]=true;
+    }
 
-    // Determine texture resolution
-    DynPLT* dynplt=grid->plts[particle];
-    unsigned int xres=dynplt->getXRes();
-    unsigned int yres=dynplt->getYRes();
-    // Real inv_width=1/static_cast<Real>(xres - 1);
-    // Real inv_height=1/static_cast<Real>(yres - 1);
-    Real inv_width=1/static_cast<Real>(xres);
-    Real inv_height=1/static_cast<Real>(yres);
-
-    // Intialize the textures
-    bzero(dynplt->texture, xres*yres*sizeof(float));
-    bzero(dynplt->inside, xres*yres*sizeof(float));
     bool dilateTexture=false;
 
-    // Generate particle's texture
-    Vector center=grid->getCenter(particle);
-    Real radius=grid->getRadius(particle);
-
-    for (unsigned int v=0; v<yres; ++v) {
-      for (unsigned int u=0; u<xres; ++u) {
-        // Pick a random sample group for surface points
-        unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
-
-        // Pick random sample group for points on the hemisphere at each 
depth
-        for (int d=0; d<=max_depth; ++d)
-          hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
-
-        for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
-          Real diffuse=0;
-          Real ambient=0;
-          Packet<Real> atten;
-
-          // Initialize a ray packet
-          int size=RayPacket::MaxSize;
-          if (size >= nsamples - s) {
-            // Remaining number of samples isn't large enough to fill a ray
-            // packet, so set the size of the ray packet to the number of 
samples
-            // that remain
-            size=nsamples - s;
-          }
+    // Render the texture
+    switch (grid->getTextureMode()) {
+    case DynPLTGridSpheres::AmbientOcclusion:
+      dilateTexture=renderAmbient(context, rctx, grid, particle);
+      break;
+    case DynPLTGridSpheres::GlobalIllumination:
+    default:
+      dilateTexture=renderGlobal(context, rctx, grid, particle);
+      break;
+    }
+
+    if (context->dilate && dilateTexture)
+      grid->plts[particle]->dilate(context);
+  
+    // XXX:  maybe use a transaction to mark the texture as valid and prevent
+    //       tearing in the middle of a frame
+    grid->valid[particle]=true;
 
-          RayPacketData raydata;
-          RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+    // Receive next message
+    msg=context->queue->receive();
+  }
 
-          // Fill in the hit positions and surface normals at sample points
-          for (int i=rays.begin(); i<rays.end(); ++i) {
-            // Project surface sample point onto particle's surface
-            Vector2D sample=sample_groups[sidx][s + i];
+  if (exitSem)
+    exitSem->up();
+}
+
+bool DynPLTWorker::renderAmbient(const DynPLTContext* context,
+                                 const RenderContext& rctx,
+                                 const DynPLTGridSpheres* grid,
+                                 unsigned int particle)
+{
+  // Grab useful information from the DynPLT context
+  unsigned int ngroups=context->ngroups;
+  unsigned int nsamples=context->nsamples;
+  unsigned int max_depth=context->max_depth;
+  Real inv_nsamples=1/static_cast<Real>(nsamples);
+
+  // Determine texture resolution
+  DynPLT* dynplt=grid->plts[particle];
+  unsigned int xres=dynplt->getXRes();
+  unsigned int yres=dynplt->getYRes();
+  // Real inv_width=1/static_cast<Real>(xres - 1);
+  // Real inv_height=1/static_cast<Real>(yres - 1);
+  Real inv_width=1/static_cast<Real>(xres);
+  Real inv_height=1/static_cast<Real>(yres);
+
+  // Intialize the textures
+  bzero(dynplt->texture, xres*yres*sizeof(float));
+  bzero(dynplt->inside, xres*yres*sizeof(float));
+
+  // Generate texture
+  const Vector center=grid->getCenter(particle);
+  Real radius=grid->getRadius(particle);
+  bool dilateTexture=false;
+
+  for (unsigned int v=0; v<yres; ++v) {
+    for (unsigned int u=0; u<xres; ++u) {
+      // Pick a random sample group for surface points
+      unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      // Pick random sample group for points on the hemisphere at each depth
+      for (int d=0; d<=max_depth; ++d)
+        hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      Real ambient=0;
+      for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
+        // Initialize a ray packet
+        int size=RayPacket::MaxSize;
+        if (size >= nsamples - s) {
+          // Remaining number of samples isn't large enough to fill a ray
+          // packet, so set the size of the ray packet to the number of 
samples
+          // that remain
+          size=nsamples - s;
+        }
+
+        RayPacketData raydata;
+        RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+
+        // Fill in the ray origins and directions at sample points
+        for (int i=rays.begin(); i<rays.end(); ++i) {
+          // Project surface sample point onto particle's surface
+          Vector2D sample=sample_groups[sidx][s + i];
             
-            // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
-            // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
-            Real phi=2*M_PI*(u + sample.x())*inv_width;
-            Real theta=M_PI*(v + sample.y())*inv_height;
-
-            Real x=cos(phi)*sin(theta);
-            Real y=sin(phi)*sin(theta);
-            Real z=cos(theta);
-
-            Vector normal(x, y, z);
-            Vector surface=center + radius*normal;
-
-            rays.setHitPosition(i, surface);
-            rays.setNormal(i, normal);
-            atten.set(i, 1);
+          // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
+          // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
+          Real phi=2*M_PI*(u + sample.x())*inv_width;
+          Real theta=M_PI*(v + sample.y())*inv_height;
+
+          Real x=cos(phi)*sin(theta);
+          Real y=sin(phi)*sin(theta);
+          Real z=cos(theta);
+
+          Vector normal(x, y, z);
+          Vector origin=center + radius*normal;
+
+          // Compute an ONB at the surface point
+          Vector v0(Cross(normal, Vector(1,0,0)));
+          if (v0.length2()==0)
+            v0=Cross(normal, Vector(0,1,0));
+          Vector v1=Cross(normal, v0);
+          v0.normalize();
+          v1.normalize();
+
+          // Generate a random direction in the hemisphere
+          Vector2D hemi=sample_groups[hidx[0]][i];
+          Real hphi=2.0*M_PI*hemi.x();
+          Real hr=SCIRun::Sqrt(hemi.y());
+          Real hx=hr*cos(hphi);
+          Real hy=hr*sin(hphi);
+          Real hz=1 - hx*hx - hy*hy;
+          hz=(hz>0?SCIRun::Sqrt(hz):0);
+
+          Vector out=Vector(hx, hy, hz).normal();
+          Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
+          dir.normalize();
+
+          // Set ray origin and direction
+          rays.setOrigin(i, origin);
+          rays.setDirection(i, dir);
+        }
+
+        // Reset ray packet
+        rays.setAllFlags(0);
+        rays.setFlag(RayPacket::NormalizedDirections);
+        rays.resetHits();
+
+        // Intersect rays with the geometry
+        context->scene->getObject()->intersect(rctx, rays);
+
+        for (unsigned int i=rays.begin(); i<rays.end();) {
+          if (rays.wasHit(i)) {
+            // Find a run of rays that hit an object
+            unsigned int end=i + 1;
+            while (end < rays.end() && rays.wasHit(end))
+              ++end;
+
+            // Rays that intersect other objects do not contribute, but 
check for
+            // invalid hits (if necessary)
+            if (context->dilate) {
+              // Compute hit positions and normals
+              RayPacket sub(rays, i, end);
+              sub.computeHitPositions();
+              sub.computeNormals(rctx);
+
+              for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
+                Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
+                if (dotprod<=0) {
+                  // An invalid hit, resulting from:
+                  //
+                  //   1.  Intersecting spheres---Ray origin is inside of one
+                  //       sphere and it hits the inside surface of the other
+                  //
+                  //   2.  Ray origin is coincident with the surface of a
+                  //       neighboring sphere---May result in some crazy
+                  //       math, and thus a negative dot product
+                  //
+                  // Either way, ignore the hit and mark the texel for
+                  // dilation
+                  dynplt->inside[u][v] += 1;
+                  dilateTexture=true;
+                }
+              }
+            }
+
+            i=end;
+          } else {
+            // Find a run of rays that didn't hit anything
+            unsigned int end=i + 1;
+            while (end < rays.end() && !rays.wasHit(end))
+              ++end;
+
+            ambient += end - i;
+
+            i=end;
           }
+        }
+      }
 
-          // Iteratively trace the ray packet
-          for (unsigned int d=0; d<max_depth; ++d) {
-            // Reset ray packet flags
-            rays.setAllFlags(0);
-            rays.setFlag(RayPacket::HaveHitPositions | 
RayPacket::HaveNormals |
-                         RayPacket::HaveUnitNormals);
-
-            // Compute direct lighting at current hit positions
-            const LightSet* activeLights=grid->getActiveLights();
-            ShadowAlgorithm::StateBuffer stateBuffer;
-            bool firstTime=true;
-            bool done;
-            do {
-              RayPacketData shadowData;
-              RayPacket shadowRays(shadowData, RayPacket::UnknownShape, 0, 0,
-                                   rays.getDepth(), 0);
-              
-              // Call the shadow algorithm (SA) to generate shadow rays.  We
-              // may not be able to compute all of them, so we pass along a
-              // buffer for the SA object to store it's state.  The firstTime
-              // flag tells the SA to fill in the state rather than using
-              // anything in the state buffer.  Most SAs will only need to
-              // store an int or two in the statebuffer.
-              done=rctx.shadowAlgorithm->computeShadows(rctx, activeLights,
-                                                        rays, shadowRays,
-                                                        firstTime,
-                                                        stateBuffer);
+      // Store the normalized result
+      dynplt->texture[u][v]=context->Ka*ambient*inv_nsamples;
+    }
+  }
+
+  return dilateTexture;
+}
+
+bool DynPLTWorker::renderGlobal(const DynPLTContext* context,
+                                const RenderContext& rctx,
+                                const DynPLTGridSpheres* grid,
+                                unsigned int particle)
+{
+  // Grab useful information from the DynPLT context
+  unsigned int ngroups=context->ngroups;
+  unsigned int nsamples=context->nsamples;
+  unsigned int max_depth=context->max_depth;
+  Real inv_nsamples=1/static_cast<Real>(nsamples);
+
+  // Determine texture resolution
+  DynPLT* dynplt=grid->plts[particle];
+  unsigned int xres=dynplt->getXRes();
+  unsigned int yres=dynplt->getYRes();
+  // Real inv_width=1/static_cast<Real>(xres - 1);
+  // Real inv_height=1/static_cast<Real>(yres - 1);
+  Real inv_width=1/static_cast<Real>(xres);
+  Real inv_height=1/static_cast<Real>(yres);
+
+  // Intialize the textures
+  bzero(dynplt->texture, xres*yres*sizeof(float));
+  bzero(dynplt->inside, xres*yres*sizeof(float));
+
+  // Generate texture
+  const Vector center=grid->getCenter(particle);
+  Real radius=grid->getRadius(particle);
+  bool dilateTexture=false;
+
+  for (unsigned int v=0; v<yres; ++v) {
+    for (unsigned int u=0; u<xres; ++u) {
+      // Pick a random sample group for surface points
+      unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      // Pick random sample group for points on the hemisphere at each depth
+      for (int d=0; d<=max_depth; ++d)
+        hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
+        Real diffuse=0;
+        Real ambient=0;
+        Packet<Real> atten;
+
+        // Initialize a ray packet
+        int size=RayPacket::MaxSize;
+        if (size >= nsamples - s) {
+          // Remaining number of samples isn't large enough to fill a ray
+          // packet, so set the size of the ray packet to the number of 
samples
+          // that remain
+          size=nsamples - s;
+        }
+
+        RayPacketData raydata;
+        RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+
+        // Fill in the hit positions and surface normals at sample points
+        for (int i=rays.begin(); i<rays.end(); ++i) {
+          // Project surface sample point onto particle's surface
+          Vector2D sample=sample_groups[sidx][s + i];
+            
+          // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
+          // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
+          Real phi=2*M_PI*(u + sample.x())*inv_width;
+          Real theta=M_PI*(v + sample.y())*inv_height;
+
+          Real x=cos(phi)*sin(theta);
+          Real y=sin(phi)*sin(theta);
+          Real z=cos(theta);
+
+          Vector normal(x, y, z);
+          Vector surface=center + radius*normal;
+
+          rays.setHitPosition(i, surface);
+          rays.setNormal(i, normal);
+          atten.set(i, 1);
+        }
+
+        // Iteratively trace the ray packet
+        for (unsigned int d=0; d<max_depth; ++d) {
+          // Reset ray packet flags
+          rays.setAllFlags(0);
+          rays.setFlag(RayPacket::HaveHitPositions | RayPacket::HaveNormals |
+                       RayPacket::HaveUnitNormals);
+
+          // Compute direct lighting at current hit positions
+          const LightSet* activeLights=grid->getActiveLights();
+          ShadowAlgorithm::StateBuffer stateBuffer;
+          bool firstTime=true;
+          bool done;
+          do {
+            RayPacketData shadowData;
+            RayPacket shadowRays(shadowData, RayPacket::UnknownShape, 0, 0,
+                                 rays.getDepth(), 0);
+
+            // Call the shadow algorithm (SA) to generate shadow rays.  We
+            // may not be able to compute all of them, so we pass along a
+            // buffer for the SA object to store it's state.  The firstTime
+            // flag tells the SA to fill in the state rather than using
+            // anything in the state buffer.  Most SAs will only need to
+            // store an int or two in the statebuffer.
+            done=rctx.shadowAlgorithm->computeShadows(rctx, activeLights,
+                                                      rays, shadowRays,
+                                                      firstTime,
+                                                      stateBuffer);
               
-              // Normalize directions for proper dot product computation
-              shadowRays.normalizeDirections();
+            // Normalize directions for proper dot product computation
+            shadowRays.normalizeDirections();
 
-              for (int i=shadowRays.begin(); i<shadowRays.end(); ++i) {
-                if (!shadowRays.wasHit(i)) {
-                  // Not in shadow, so compute the direct contribution
-                  Vector normal=rays.getNormal(i);
-                  Vector shadowdir=shadowRays.getDirection(i);
-                  Real cos_theta=Dot(shadowdir, normal);
-                  Color light=shadowRays.getColor(i);
-                  diffuse += atten.get(i)*light.luminance()*cos_theta;
-                }
+            for (int i=shadowRays.begin(); i<shadowRays.end(); ++i) {
+              if (!shadowRays.wasHit(i)) {
+                // Not in shadow, so compute the direct contribution
+                Vector normal=rays.getNormal(i);
+                Vector shadowdir=shadowRays.getDirection(i);
+                Real cos_theta=Dot(shadowdir, normal);
+                Color light=shadowRays.getColor(i);
+                diffuse += atten.get(i)*light.luminance()*cos_theta;
               }
+            }
               
-              firstTime=false;
-            } while(!done);
+            firstTime=false;
+          } while(!done);
+
+          // Don't fill/trace ray packet if it's not going to contribute
+          if (d >= max_depth - 1)
+            break;
 
-            // Don't fill/trace ray packet if it's not going to contribute
-            if (d >= max_depth - 1)
-              break;
-
-            for (int i=rays.begin(); i<rays.end(); ++i) {
-              // Compute an ONB at the surface point
-              Vector normal=rays.getNormal(i);
-              Vector v0(Cross(normal, Vector(1,0,0)));
-              if (v0.length2()==0)
-                v0=Cross(normal, Vector(0,1,0));
-              Vector v1=Cross(normal, v0);
-              v0.normalize();
-              v1.normalize();
-
-              // Generate a random direction in the hemisphere
-              Vector2D hemi=sample_groups[hidx[d]][i];
-              Real hphi=2.0*M_PI*hemi.x();
-              Real hr=SCIRun::Sqrt(hemi.y());
-              Real hx=hr*cos(hphi);
-              Real hy=hr*sin(hphi);
-              Real hz=1 - hx*hx - hy*hy;
-              hz=(hz>0?SCIRun::Sqrt(hz):0);
-
-              Vector out=Vector(hx, hy, hz).normal();
-              Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
-              dir.normalize();
-
-              // Set ray origin and direction
-              rays.setOrigin(i, rays.getHitPosition(i));
-              rays.setDirection(i, dir);
+          for (int i=rays.begin(); i<rays.end(); ++i) {
+            // Compute an ONB at the surface point
+            Vector normal=rays.getNormal(i);
+            Vector v0(Cross(normal, Vector(1,0,0)));
+            if (v0.length2()==0)
+              v0=Cross(normal, Vector(0,1,0));
+            Vector v1=Cross(normal, v0);
+            v0.normalize();
+            v1.normalize();
+
+            // Generate a random direction in the hemisphere
+            Vector2D hemi=sample_groups[hidx[d]][i];
+            Real hphi=2.0*M_PI*hemi.x();
+            Real hr=SCIRun::Sqrt(hemi.y());
+            Real hx=hr*cos(hphi);
+            Real hy=hr*sin(hphi);
+            Real hz=1 - hx*hx - hy*hy;
+            hz=(hz>0?SCIRun::Sqrt(hz):0);
+
+            Vector out=Vector(hx, hy, hz).normal();
+            Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
+            dir.normalize();
+
+            // Set ray origin and direction
+            rays.setOrigin(i, rays.getHitPosition(i));
+            rays.setDirection(i, dir);
               
-              // Update attenutation
-              atten.set(i, atten.get(i)*Dot(normal, dir));
-            }
+            // Update attenutation
+            atten.set(i, atten.get(i)*Dot(normal, dir));
+          }
 
-            // Reset ray packet
-            rays.setAllFlags(0);
-            rays.setFlag(RayPacket::NormalizedDirections);
-            rays.resetHits();
-
-            // Intersect rays with the geometry
-            scene->getObject()->intersect(rctx, rays);
-
-            // Prepare ray packet for next iteration
-            unsigned int validRays=0;
-            for (unsigned int i=rays.begin(); i<rays.end();) {
-              if (rays.wasHit(i)) {
-                // Find a run of rays that hit an object
-                unsigned int end=i + 1;
-                while (end < rays.end() && rays.wasHit(end))
-                  ++end;
-
-                // Compute hit positions and normals
-                RayPacket sub(rays, i, end);
-                sub.computeHitPositions();
-                sub.computeNormals(rctx);
-
-                // Store hit positions, normals for valid hits
-                for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
-                  Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
-                  if (dotprod>0) {
-                    rays.setHitPosition(validRays, sub.getHitPosition(j));
-                    rays.setNormal(validRays, sub.getNormal(j));
-                    atten.set(validRays, atten.get(j));
-                    ++validRays;
-                  } else {
-                    // An invalid hit, resulting from:
-                    //
-                    //   1.  Intersecting spheres---Ray origin is inside of 
one
-                    //       sphere and it hits the inside surface of the 
other
-                    //
-                    //   2.  Ray origin is coincident with the surface of a
-                    //       neighboring sphere---May result in some crazy
-                    //       math, and thus a negative dot product
-                    //
-                    // Either way, ignore the hit and mark the texel for
-                    // dilation
-                    dynplt->inside[u][v] += 1;
-                    dilateTexture=true;
-                  }
+          // Reset ray packet
+          rays.setAllFlags(0);
+          rays.setFlag(RayPacket::NormalizedDirections);
+          rays.resetHits();
+
+          // Intersect rays with the geometry
+          context->scene->getObject()->intersect(rctx, rays);
+
+          // Prepare ray packet for next iteration
+          unsigned int validRays=0;
+          for (unsigned int i=rays.begin(); i<rays.end();) {
+            if (rays.wasHit(i)) {
+              // Find a run of rays that hit an object
+              unsigned int end=i + 1;
+              while (end < rays.end() && rays.wasHit(end))
+                ++end;
+
+              // Compute hit positions and normals
+              RayPacket sub(rays, i, end);
+              sub.computeHitPositions();
+              sub.computeNormals(rctx);
+
+              // Store hit positions, normals for valid hits
+              for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
+                Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
+                if (dotprod>0) {
+                  rays.setHitPosition(validRays, sub.getHitPosition(j));
+                  rays.setNormal(validRays, sub.getNormal(j));
+                  atten.set(validRays, atten.get(j));
+                  ++validRays;
+                } else {
+                  // An invalid hit, resulting from:
+                  //
+                  //   1.  Intersecting spheres---Ray origin is inside of one
+                  //       sphere and it hits the inside surface of the other
+                  //
+                  //   2.  Ray origin is coincident with the surface of a
+                  //       neighboring sphere---May result in some crazy
+                  //       math, and thus a negative dot product
+                  //
+                  // Either way, ignore the hit and mark the texel for
+                  // dilation
+                  dynplt->inside[u][v] += 1;
+                  dilateTexture=true;
                 }
+              }
 
-                i=end;
-              } else {
-                // Find a run of rays that didn't hit anything
-                unsigned int end=i + 1;
-                while (end < rays.end() && !rays.wasHit(end))
-                  ++end;
-
-                // Shade the rays, and accumulate background color
-                RayPacket sub(rays, i, end);
-                scene->getBackground()->shade(rctx, sub);
+              i=end;
+            } else {
+              // Find a run of rays that didn't hit anything
+              unsigned int end=i + 1;
+              while (end < rays.end() && !rays.wasHit(end))
+                ++end;
+
+              // Shade the rays, and accumulate background color
+              RayPacket sub(rays, i, end);
+              context->scene->getBackground()->shade(rctx, sub);
 
-                for (unsigned int j=sub.begin(); j<sub.end(); ++j)
-                  ambient += sub.getColor(j).luminance();
+              for (unsigned int j=sub.begin(); j<sub.end(); ++j)
+                ambient += sub.getColor(j).luminance();
 
-                i=end;
-              }
+              i=end;
             }
-
-            // Terminate at current depth, if necessary
-            if (validRays==0)
-              break;
-
-            // Update the ray packet configuration, loop to next depth
-            rays.setDepth(rays.getDepth() + 1);
-            rays.resize(validRays);
           }
 
-          // Store the result
-          dynplt->texture[u][v] += context->Ka*ambient + context->Kd*diffuse;
+          // Terminate at current depth, if necessary
+          if (validRays==0)
+            break;
+
+          // Update the ray packet configuration, loop to next depth
+          rays.setDepth(rays.getDepth() + 1);
+          rays.resize(validRays);
         }
 
-        // Normalize the texel
-        dynplt->texture[u][v] *= inv_nsamples;
+        // Store the result
+        dynplt->texture[u][v] += context->Ka*ambient + context->Kd*diffuse;
       }
-    }
-
-    if (context->dilate && dilateTexture)
-      dynplt->dilate(context);
-
-    // XXX:  maybe use a transaction to mark the texture as valid and prevent
-    //       tearing in the middle of a frame
-    grid->valid[particle]=true;
 
-    // Receive next message
-    msg=context->queue->receive();
+      // Normalize the texel
+      dynplt->texture[u][v] *= inv_nsamples;
+    }
   }
 
-  if (exitSem)
-    exitSem->up();
+  return dilateTexture;
 }
 
 void DynPLTWorker::terminate(MantaInterface*)

Modified: trunk/Engine/Control/DynPLTWorker.h
==============================================================================
--- trunk/Engine/Control/DynPLTWorker.h (original)
+++ trunk/Engine/Control/DynPLTWorker.h Sun Jun  4 14:14:24 2006
@@ -59,6 +59,11 @@
     void terminate(MantaInterface*);
 
   private:
+    bool renderAmbient(const DynPLTContext* context, const RenderContext& 
rctx,
+                       const DynPLTGridSpheres* grid, unsigned int particle);
+    bool renderGlobal(const DynPLTContext* context, const RenderContext& 
rctx,
+                      const DynPLTGridSpheres* grid, unsigned int particle);
+
     const DynPLTContext* context;
     unsigned int id;
     MT_RNG rng;

Modified: trunk/Model/Primitives/DynPLTGridSpheres.cc
==============================================================================
--- trunk/Model/Primitives/DynPLTGridSpheres.cc (original)
+++ trunk/Model/Primitives/DynPLTGridSpheres.cc Sun Jun  4 14:14:24 2006
@@ -1,5 +1,7 @@
 
 #include <Core/Color/RegularColorMap.h>
+#include <Interface/AmbientLight.h>
+#include <Interface/LightSet.h>
 #include <Interface/RayPacket.h>
 #include <Engine/Control/DynPLTWorker.h>
 #include <Model/Primitives/DynPLTGridSpheres.h>
@@ -20,12 +22,18 @@
   cerr<<"Initializing DynPLTGridSpheres\n";
   plts.resize(nspheres);
   valid.resize(nspheres);
+  allocated.resize(nspheres);
   requested.resize(nspheres);
   for (unsigned int i=0; i<nspheres; ++i) {
     plts[i]=0;
-    valid[i]=false;
     requested[i]=false;
+    allocated[i]=false;
+    valid[i]=false;
   }
+
+  // XXX:  hard coded for now
+  // textureMode=AmbientOcclusion;
+  textureMode=GlobalIllumination;
 }
 
 DynPLTGridSpheres::~DynPLTGridSpheres(void)
@@ -36,6 +44,69 @@
 void DynPLTGridSpheres::shade(const RenderContext& context,
                               RayPacket& rays) const
 {
+  switch (textureMode) {
+  case AmbientOcclusion:
+    shadeAmbient(context, rays);
+    break;
+  case GlobalIllumination:
+  default:
+    shadeGlobal(context, rays);
+    break;
+  }
+}
+
+void DynPLTGridSpheres::shadeAmbient(const RenderContext& context,
+                                     RayPacket& rays) const
+{
+  ColorArray ambient;
+
+  for (unsigned int i=rays.begin(); i<rays.end(); ) {
+    // Find a run of rays that hit the same particle
+    int offset=rays.scratchpad<int>(i);
+    unsigned int end=i + 1;
+    while (end < rays.end() && rays.scratchpad<int>(end)==offset)
+      ++end;
+
+    int particle=offset/nvars;
+
+    // Compute ambient light for the rays
+    RayPacket sub(rays, i, end);
+    if (valid[particle]) {
+      // Compute diffuse colors
+      Packet<Color> diffuse;
+      mapDiffuseColors(diffuse, sub);
+
+      // Compute textured ambient luminance
+      sub.computeTextureCoordinates2(context);
+
+      for (unsigned int i=sub.begin(); i<sub.end(); ++i) {
+        Real luminance=computeLuminance(i, sub, particle);
+        for (int j=0; j < Color::NumComponents; ++j)
+          ambient[j][i]=luminance;
+      }
+    } else {
+      // Request texture generation, if necessary
+      if (!requested[particle]) {
+        // Create and post message
+        DynPLTMessage msg(particle, this);
+        if (queue->trySend(msg))
+          requested[particle]=true;
+      }
+
+      // Use default ambient light while texture is invalid
+      activeLights->getAmbientLight()->computeAmbient(context, sub, ambient);
+    }
+
+    i=end;
+  }
+
+  // Shade the rays
+  GridSpheres::lambertianShade(context, rays, ambient);
+}
+
+void DynPLTGridSpheres::shadeGlobal(const RenderContext& context,
+                                    RayPacket& rays) const
+{
   for (unsigned int i=rays.begin(); i<rays.end(); ) {
     // Find a run of rays that hit the same particle
     int offset=rays.scratchpad<int>(i);
@@ -55,40 +126,8 @@
       // Compute textured luminance
       sub.computeTextureCoordinates2(context);
 
-      for (unsigned int i=sub.begin(); i < sub.end(); ++i) {
-        // Wrap in x (assumes xres is a power of two)
-        Real x=sub.getTexCoords2(i, 0)*XRES;
-        int lx=static_cast<int>(x) & (XRES - 1);
-        int hx=(lx + 1) & (XRES - 1);
-        Real wx=x - lx;
-      
-        // Clamp in y
-        Real y=sub.getTexCoords2(i, 1);
-        int ly;
-        Real wy;
-        if (y < 0) {
-          ly=0;
-          wy=0;
-        } else {
-          y *= YRES - 1;
-          ly=static_cast<int>(y);
-          if (ly > YRES - 1) {
-            ly=YRES - 1;
-            wy=0;
-          } else {
-            wy=y - ly;
-          }
-        }
-
-        int hy=ly + 1;
-
-        // Interpolate
-        Real a=(plts[particle]->texture[lx][ly]*(1 - wx) +
-                plts[particle]->texture[hx][ly]*wx);
-        Real b=(plts[particle]->texture[lx][hy]*(1 - wx) +
-                plts[particle]->texture[hx][hy]*wx);
-        Real luminance=a*(1 - wy) + b*wy;
-
+      for (unsigned int i=sub.begin(); i<sub.end(); ++i) {
+        Real luminance=computeLuminance(i, rays, particle);
         sub.setColor(i, diffuse.get(i)*luminance);
       }
     } else {
@@ -106,6 +145,44 @@
 
     i=end;
   }
+}
+
+Real DynPLTGridSpheres::computeLuminance(unsigned int ray_idx, RayPacket& 
rays,
+                                         unsigned int particle) const
+{
+  // Wrap in x (assumes xres is a power of two)
+  Real x=rays.getTexCoords2(ray_idx, 0)*XRES;
+  int lx=static_cast<int>(x) & (XRES - 1);
+  int hx=(lx + 1) & (XRES - 1);
+  Real wx=x - lx;
+
+  // Clamp in y
+  Real y=rays.getTexCoords2(ray_idx, 1);
+  int ly;
+  Real wy;
+  if (y < 0) {
+    ly=0;
+    wy=0;
+  } else {
+    y *= YRES - 1;
+    ly=static_cast<int>(y);
+    if (ly > YRES - 1) {
+      ly=YRES - 1;
+      wy=0;
+    } else {
+      wy=y - ly;
+    }
+  }
+
+  int hy=ly + 1;
+
+  // Bi-linearly interpolate
+  Real a=(plts[particle]->texture[lx][ly]*(1 - wx) +
+          plts[particle]->texture[hx][ly]*wx);
+  Real b=(plts[particle]->texture[lx][hy]*(1 - wx) +
+          plts[particle]->texture[hx][hy]*wx);
+
+  return a*(1 - wy) + b*wy;
 }
 
 void DynPLT::dilate(const DynPLTContext* context)

Modified: trunk/Model/Primitives/DynPLTGridSpheres.h
==============================================================================
--- trunk/Model/Primitives/DynPLTGridSpheres.h  (original)
+++ trunk/Model/Primitives/DynPLTGridSpheres.h  Sun Jun  4 14:14:24 2006
@@ -50,6 +50,11 @@
   class DynPLTGridSpheres : public GridSpheres
   {
   public:
+    enum {
+      AmbientOcclusion,
+      GlobalIllumination
+    } TextureMode;
+
     DynPLTGridSpheres(SCIRun::Mailbox<DynPLTMessage>* queue, float* spheres,
                       int nspheres, int nvars, int ncells, int depth,
                       Real radius, int ridx, RegularColorMap* cmap, int 
cidx);
@@ -59,6 +64,15 @@
 
     const LightSet* getActiveLights(void) const { return activeLights; }
 
+    unsigned int getTextureMode(void) const { return textureMode; }
+    void setTextureMode(unsigned int mode)
+    {
+      if (textureMode != mode) {
+        invalidateTextures();
+        textureMode=mode;
+      }
+    }
+
     Vector getCenter(int particle) const
     {
       float* data=spheres + particle*nvars;
@@ -78,12 +92,28 @@
       return radius;
     }
 
-    mutable vector<bool> valid;
     mutable vector<DynPLT*> plts;
+    mutable vector<bool> allocated;
+    mutable vector<bool> valid;
 
   private:
+    void shadeAmbient(const RenderContext& context, RayPacket& rays) const;
+    void shadeGlobal(const RenderContext& context, RayPacket& rays) const;
+    Real computeLuminance(unsigned int ray_idx, RayPacket& rays,
+                          unsigned int particle) const;
+
+    void invalidateTextures(void)
+    {
+      for (unsigned int i=0; i<nspheres; ++i) {
+        requested[i]=false;
+        valid[i]=false;
+      }
+    }
+
     SCIRun::Mailbox<DynPLTMessage>* queue;
     mutable vector<bool> requested;
+
+    unsigned int textureMode;
   };
 }
 

Modified: trunk/Model/Primitives/GridSpheres.cc
==============================================================================
--- trunk/Model/Primitives/GridSpheres.cc       (original)
+++ trunk/Model/Primitives/GridSpheres.cc       Sun Jun  4 14:14:24 2006
@@ -542,18 +542,23 @@
 
 void GridSpheres::shade(const RenderContext& context, RayPacket& rays) const
 {
+  // Compute ambient light
+  ColorArray ambient;
+  activeLights->getAmbientLight()->computeAmbient(context, rays, ambient);
+
   // Shade a bunch of rays that have intersected the same particle
+  lambertianShade(context, rays, ambient);
+}
 
+void GridSpheres::lambertianShade(const RenderContext& context, RayPacket& 
rays,
+                                  ColorArray& totalLight) const
+{
   // Compute normals
   rays.computeNormals(context);
 
   // Compute colors
   Packet<Color> diffuse;
   mapDiffuseColors(diffuse, rays);
-
-  // Compute ambient contributions for all rays
-  ColorArray totalLight;
-  activeLights->getAmbientLight()->computeAmbient(context, rays, totalLight);
 
   // Normalize directions for proper dot product computation
   rays.normalizeDirections();

Modified: trunk/Model/Primitives/GridSpheres.h
==============================================================================
--- trunk/Model/Primitives/GridSpheres.h        (original)
+++ trunk/Model/Primitives/GridSpheres.h        Sun Jun  4 14:14:24 2006
@@ -4,6 +4,7 @@
 
 #include <Core/Color/Color.h>
 #include <Core/Geometry/BBox.h>
+#include <Interface/RayPacket.h>
 #include <Interface/TexCoordMapper.h>
 #include <Interface/Texture.h>
 #include <Model/Primitives/PrimitiveCommon.h>
@@ -80,6 +81,9 @@
 #endif // USE_OPTIMIZED_FCNS
     void intersectSphereDefault(RayPacket& rays, int ray_idx, int idx,
                                 const Vector& center, float radius2) const;
+
+    void lambertianShade(const RenderContext& context, RayPacket& rays,
+                         ColorArray& totalLight) const;
 
     float* spheres;
     int nspheres;




  • [MANTA] r1097 - in trunk: Engine/Control Model/Primitives, cgribble, 06/04/2006

Archive powered by MHonArc 2.6.16.

Top of page