Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r400 - in branches/itanium2: Core/Math Engine/PixelSamplers Interface


Chronological Thread 
  • From: boulos@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r400 - in branches/itanium2: Core/Math Engine/PixelSamplers Interface
  • Date: Tue, 21 Jun 2005 02:09:40 -0600 (MDT)

Author: boulos
Date: Tue Jun 21 02:09:37 2005
New Revision: 400

Added:
   branches/itanium2/Core/Math/CheapRNG.h
Modified:
   branches/itanium2/Engine/PixelSamplers/JitterSampler.cc
   branches/itanium2/Engine/PixelSamplers/JitterSampler.h
   branches/itanium2/Interface/RayPacket.h
Log:
Fixes for the JitterSampler (resetting the
raypacket flags so they can be reused with
a fresh slate after intersecting things in
the scene).

Tested on my laptop only.


Added: branches/itanium2/Core/Math/CheapRNG.h
==============================================================================
--- (empty file)
+++ branches/itanium2/Core/Math/CheapRNG.h      Tue Jun 21 02:09:37 2005
@@ -0,0 +1,72 @@
+/*
+ * CheapRNG
+ *
+ * Cheap refers to the cost to store and to seed the random number.
+ * The speed is about twice as slow as the Mersenne Twister, however
+ * seeding is several orders of magnitude faster.  This is useful if
+ * you want to reseed for only a relatively few samples and you just
+ * want a reasonably random sequence.
+ *
+ * The period for this RNG is 2^32 with ranges of [0..4294967295] (or
+ * [0..2^32-1]).  Consequently the floating point results are
+ * [0..1].  If you want an exclusive interval [0..1) divide genuint()
+ * by 4294967296.0.
+ *
+ * The algorithms are taken from chapter 7 of Numerical Recipies in C:
+ * The Art of Scientific Computing.
+ *
+ * Author: James Bigler
+ * Date: June 16, 2005
+ *
+ */
+
+// All these values are u_int32_t to make sure we have an unsigned 32
+// bit integer, because the computation relies on the overflow
+// properties of integer multiplication.
+
+// For the Real type
+#include <MantaTypes.h> 
+
+namespace Manta {
+
+  class CheapRNG {
+  public:
+    // You need to make sure that this is 32 bits or you are in
+    // trouble.  It also needs to be public to initialize the static
+    // members.
+    typedef unsigned int uint32;
+  protected:
+    
+    uint32 val;
+    
+  public:
+    // Your seed value is upto the fates.  You should call seed.
+    CheapRNG() {}
+      
+    inline void seed(uint32 seed_val) {
+      val = seed_val;
+    }
+
+    inline uint32 randInt() {
+      val = 1664525*val + 1013904223;
+      return val;
+    }
+
+    // [0..1]
+    inline Real rand() {
+      return Real(randInt())*Real(1./4294967295.);
+    }
+
+    // real number in [0,1)
+    inline Real randExc() {
+      return Real(randInt())*Real(1./4294967296.);
+    }
+
+    // real number in (0,1)
+    inline Real randDblExc() {
+      return ( Real(randInt()) + Real(0.5) ) * Real(1./4294967296.);
+    }
+    
+  }; // end class CheapRNG
+
+}

Modified: branches/itanium2/Engine/PixelSamplers/JitterSampler.cc
==============================================================================
--- branches/itanium2/Engine/PixelSamplers/JitterSampler.cc     (original)
+++ branches/itanium2/Engine/PixelSamplers/JitterSampler.cc     Tue Jun 21 
02:09:37 2005
@@ -7,6 +7,7 @@
 #include <Interface/RayPacket.h>
 #include <Interface/Renderer.h>
 
+#include <Core/Math/CheapRNG.h>
 
 #include <Engine/PixelSamplers/Sample.h>
 #include <stdio.h>
@@ -20,24 +21,26 @@
 
 PixelSampler* JitterSampler::create(const vector<string>& args)
 {
-  
+
   return new JitterSampler(args);
 }
 
-JitterSampler::JitterSampler(const vector<string>& args)
+JitterSampler::JitterSampler(const vector<string>& args):
+  num_samples(4), use_cheaprng(true)
 {
-  num_samples = 4;
   int argc = static_cast<int>(args.size());
   for(int i = 0; i<argc;i++){
     string arg = args[i];
     if(arg == "-numberOfSamples"){
       if(!getIntArg(i, args, num_samples))
-       throw IllegalArgument("JitterSampler -numberOfSamples", i, args);
+        throw IllegalArgument("JitterSampler -numberOfSamples", i, args);
       if (num_samples < 1)
         throw IllegalArgument("-numberOfSamples must be greater than 0",
                               i, args);
+    } else if (arg == "-nocheap") {
+      use_cheaprng = false;
     }
-   
+
     else {
       throw IllegalArgument("JitterSampler", i, args);
     }
@@ -55,7 +58,15 @@
 void JitterSampler::setupBegin(const SetupContext& context, int numChannels)
 {
   channelInfo.resize(numChannels);
-  random = new MT_RNG[context.numProcs];
+  if ( !use_cheaprng )
+  {
+      random = new MT_RNG[context.numProcs];
+      for ( int i = 0; i < context.numProcs; i++ )
+      {
+          random[i] = MT_RNG();
+          random[i].seed_rng( (unsigned long) i );
+      }
+  }
   context.renderer->setupBegin(context, numChannels);
 }
 
@@ -70,7 +81,7 @@
   ci.yscale = ci.xscale;
   ci.xoffset = (-ci.xres+1)*(Real)0.5*ci.xscale; // Offset to pixel center
   ci.yoffset = (-ci.yres+1)*(Real)0.5*ci.yscale;
-  
+
   context.renderer->setupDisplayChannel(context);
 }
 
@@ -79,94 +90,89 @@
   context.renderer->setupFrame(context);
 }
 
-
-// Ohh, man.  Is this code wacked or what?  Anyway, the point of this
-// code it to gather up all the samples that belong to a single
-// fragment, then update the color in the fragment.  Fagments' samples
-// can exists across multiple RayPackets, so we have to be careful
-// here.  Also with the way the loop works you have to make sure you
-// pick up the last sample if it is part of a newrun (see
-// compute_last_ave below).  Anyway, I know there is probably a more
-// elegant solution out there, but this works for all sorts of
-// combinations of fragment sizes and number of samples.
-void JitterSampler::computeAverages(Fragment& fragment, RayPacket& rays,
-                                    Color* sample_color,
-                                    int* fragment_owning_sample) {
-  // At this point we have rays.getSize() number of samples
-  // that can belong to at most fragment.getSize() number of
-  // fragments.  We need to sum the colors from the samples
-  // for a single fragment then divide it by the total
-  // number of samples and add it to the fragment's total.
-  int slot_index = 0;
-  int num_samples_per_fragment = 1;
-  int current_fragment = fragment_owning_sample[slot_index];
-  Color fragment_color = sample_color[slot_index];
-  // If the last sample is a new run, you need to add it after the for loop.
-  bool compute_last_ave = false; 
-  for(int slot_index = 1; slot_index < rays.getSize(); slot_index++){
-    bool compute_average = false;
-    if (current_fragment == fragment_owning_sample[slot_index]) {
-      fragment_color += sample_color[slot_index];
-      num_samples_per_fragment++;
-      // Now the case where the last sample is has been
-      // reached, we must force it to be averaged.
-      if (slot_index == rays.getSize()-1)
-        compute_average = true;
-    } else {
-      // Now we have a break in the fragment, so time to
-      // compute the average.
-      compute_average = true;
-      // If however we have a break at the last pixel, we need to
-      // signal to pick up that extra sample.
-      if (slot_index == rays.getSize()-1)
-        compute_last_ave = true;
-    }
-    if (compute_average) {
-      // Divide the color by the number of samples and
-      // increment it with the fragment.
-      fragment.get(current_fragment).color +=
-        fragment_color / num_samples;
-      // Now update for the next fragment run
-      fragment_color = sample_color[slot_index];
-      current_fragment = fragment_owning_sample[slot_index];
-      num_samples_per_fragment = 1;
+// The fragment, sample_color, and sample_color_size paramters are
+// obvious enough, but the other two need some explaination.
+//
+// samples_collected_return represent the number of samples that have
+// already been used to color a fragment element.  If a fragment
+// element's samples span more than one RayPacket, then we account for
+// that with this variable.
+//
+// current_fragment_return keeps track of which fragment elements have
+// had their color computed.
+void JitterSampler::computeAverages(Fragment& fragment, Color* sample_color,
+                                    int sample_color_size,
+                                    int& samples_collected_return,
+                                    int& current_fragment_return) {
+  // Copy the values, so the we can hopefully use the cache when
+  // assigning the values.
+  int samples_collected = samples_collected_return;
+  int current_fragment = current_fragment_return;
+  Color fragment_color = Color::black();
+
+  for(int sample_index = 0; sample_index < sample_color_size; 
sample_index++) {
+      //double val = (double)current_fragment/(double)fragment.getSize();
+      //fragment_color += Color(RGBColor(val, val, val));
+      fragment_color += sample_color[sample_index];
+    samples_collected++;
+    // We've collected enough samples, so compute the average and
+    // assign it to the fragment.
+    if(samples_collected == num_samples) {
+      fragment.get(current_fragment).color += fragment_color / num_samples;
+      // Reset our accumulation variables
+      fragment_color = Color::black();
+      samples_collected = 0;
+      current_fragment++;
     }
-  } // end slot_index loop
-
-  // Pick up the last sample if we need to
-  if (compute_last_ave)
+  }
+  // Pick up left over fragments.  It is OK if this is a partial sum.
+  // The remaining sum will be picked up in the next call to
+  // computeAverages.
+  if (samples_collected > 0) {
     fragment.get(current_fragment).color += fragment_color / num_samples;
+  }
+  // Assign the values back to the parameters.
+  samples_collected_return = samples_collected;
+  current_fragment_return = current_fragment;
 }
 
 void JitterSampler::renderFragment(const RenderContext& context,
-                                  Fragment& fragment)
+                                   Fragment& fragment)
 {
   ChannelInfo& ci = channelInfo[context.channelIndex];
   int thd_num = context.proc;
-    
+
   int flags = RayPacket::HaveImageCoordinates;
   if(fragment.getFlags() & Fragment::ConstantEye)
     flags |= RayPacket::ConstantEye;
 
-  int next_slot = 0;
-  Color sample_color[RayPacket::MaxSize];
-  int fragment_owning_sample[RayPacket::MaxSize];
-
   int consecutivex_flag = fragment.getFlags() & Fragment::ConsecutiveX;
 
+  CheapRNG rng;
   if (consecutivex_flag) {
     Fragment::Element& fe = fragment.get(0);
-    random[thd_num].seed_rng(fe.x*ci.xres+fe.y);
+    if (use_cheaprng)
+      rng.seed(fe.x*ci.xres+fe.y);
+    else
+      random[thd_num].seed_rng(fe.x*ci.xres+fe.y);
   }
 
   int depth = 0;
+
   RayPacketData raydata;
   RayPacket rays(raydata, RayPacket::MaxSize, depth, flags);
 
   Real inx = (Real)1/nx;
   Real iny = (Real)1/ny;
   Real px, py;
-  
+
+  int sample_count = 0;
+  Color sample_color[RayPacket::MaxSize];
+  // No samples accumulated yet.
+  int samples_collected = 0;
+  // Index to the first fragment's element.
+  int current_fragment = 0;
+
   // We can compute at most RayPacket::MaxSize number of rays at time.
   for(int frag_index = 0; frag_index < fragment.getSize(); frag_index++) {
     // Initialize the color
@@ -175,49 +181,61 @@
     Fragment::Element& fe0 = fragment.get(frag_index);
 
     if (!consecutivex_flag) {
-      random[thd_num].seed_rng(fe0.x*ci.xres+fe0.y);
+      if (use_cheaprng)
+        rng.seed(fe0.x*ci.xres+fe0.y);
+      else
+        random[thd_num].seed_rng(fe0.x*ci.xres+fe0.y);
     }
-    
+
     // For each fragment start filling up the RayPacket with samples.
     // When you filled up the empty_slots compute the rays, do the
     // average, and store the results in the fragment.
     for(int xs = 0; xs < nx; xs++)
       for(int ys = 0; ys  < ny; ys++)
         {
-          Real x_sample = (xs + random[thd_num].genRealRand<Real>()) * inx;
-          Real y_sample = (ys + random[thd_num].genRealRand<Real>()) * iny;
+          Real x_sample, y_sample;
+          if (use_cheaprng) {
+            x_sample = (xs + rng.rand()) * inx;
+            y_sample = (ys + rng.rand()) * iny;
+          } else {
+            x_sample = (xs + random[thd_num].genRealRand<Real>()) * inx;
+            y_sample = (ys + random[thd_num].genRealRand<Real>()) * iny;
+          }
           px = (fe0.x+(x_sample))*ci.xscale+ci.xoffset;
           py = (fe0.y+(y_sample))*ci.yscale+ci.yoffset;
-          rays.setPixel(next_slot, 0, px, py, &sample_color[next_slot]);
-          fragment_owning_sample[next_slot] = frag_index;
-          next_slot++;
-          
-          if (next_slot == RayPacket::MaxSize) {
+
+          rays.setPixel(sample_count, 0, px, py,
+                        &sample_color[sample_count]);
+          sample_count++;
+
+          if (sample_count == RayPacket::MaxSize) {
             // Filled up the ray packet, so send them off!
-            rays.resize(next_slot);
+            rays.resize(sample_count);
             context.renderer->traceEyeRays(context, rays);
 
-            computeAverages(fragment, rays,
-                            sample_color, fragment_owning_sample);
-            
+            computeAverages(fragment, sample_color, rays.getSize(),
+                            samples_collected, current_fragment);
+
             // Now reset the index, so that we can start filling up
             // the RayPacket again.
-            next_slot = 0;
+            sample_count = 0;
             // Make sure we start with a fresh slate
             rays.resetHit();
-            //            rays.resetFlag(flags);
+            rays.setFlags(flags);
+            //rays.setDepth(depth);
           }
         } // end sample filling loops
   } // end fragment loop
 
   // Pick up any stragling samples
-  if (next_slot > 0) {
-    rays.resize(next_slot);
+  if (sample_count > 0) {
+    rays.resize(sample_count);
     context.renderer->traceEyeRays(context, rays);
-    
-    computeAverages(fragment, rays, sample_color, fragment_owning_sample);
+
+    computeAverages(fragment, sample_color, rays.getSize(),
+                    samples_collected, current_fragment);
   }
-}  
+}
 
 
 

Modified: branches/itanium2/Engine/PixelSamplers/JitterSampler.h
==============================================================================
--- branches/itanium2/Engine/PixelSamplers/JitterSampler.h      (original)
+++ branches/itanium2/Engine/PixelSamplers/JitterSampler.h      Tue Jun 21 
02:09:37 2005
@@ -31,12 +31,14 @@
     JitterSampler(const JitterSampler&);
     JitterSampler& operator=(const JitterSampler&);
 
-    void computeAverages(Fragment& fragment, RayPacket& rays,
-                         Color* sample_color, int* fragment_owning_sample);
+    void computeAverages(Fragment& fragment, Color* sample_color,
+                         int sample_color_size,
+                         int& samples_collected, int& current_fragment);
     
     int num_samples;
     // nx*ny == num_samples where nx~=ny (or as close as you can get it).
     int nx, ny;
+    bool use_cheaprng;
     
     struct ChannelInfo {
       Real xscale;

Modified: branches/itanium2/Interface/RayPacket.h
==============================================================================
--- branches/itanium2/Interface/RayPacket.h     (original)
+++ branches/itanium2/Interface/RayPacket.h     Tue Jun 21 02:09:37 2005
@@ -30,9 +30,9 @@
       HaveUnitNormals       = 0x300,
       HaveInverseDirections = 0x800 };
 
-    
+
     inline RayPacket(RayPacketData& data, int size, int depth, int flags);
-    
+
     // Create a subset of another raypacket
     RayPacket(RayPacket& parent, int start, int end)
       : data(parent.data+start), size(end-start), depth(parent.depth),
@@ -47,6 +47,10 @@
     int getFlags() const {
       return flags;
     }
+    int setFlags(int new_flags)
+    {
+        flags = new_flags;
+    }
     void setFlag(int flag) {
       flags |= flag;
     }
@@ -94,7 +98,7 @@
       return data[which];
     }
     void setPixel(int which, int whichEye, double imageX, double imageY,
-                 Color* color) {
+                  Color* color) {
       data[which].color = color;
       data[which].imageX = imageX;
       data[which].imageY = imageY;
@@ -102,7 +106,7 @@
     }
     void useLocalColors() {
       for(int i=0;i<size;i++)
-       data[i].color = &data[i].localColor;
+        data[i].color = &data[i].localColor;
     }
     HitInfo& hitInfo(int which) {
       return data[which].hitInfo;
@@ -117,7 +121,7 @@
     {
       if(flags & NormalizedDirections)
         return;
-      
+
       if(flags & HaveHitRecords){
         for(int i=0;i<size;i++){
           double length = data[i].ray.normalizeDirection();
@@ -146,7 +150,7 @@
         data[i].inverseDirection = Vector(1./data[i].ray.direction().x(),
                                           1./data[i].ray.direction().y(),
                                           1./data[i].ray.direction().z());
-        
+
         // Set the sign mask at the same time.
         data[i].signMask[0] = (data[i].inverseDirection[0] < 0.0);
         data[i].signMask[1] = (data[i].inverseDirection[1] < 0.0);
@@ -176,7 +180,7 @@
     void computeFrame(const RenderContext& context)
     {
       if(flags & HaveFrame)
-       return;
+        return;
       Element& e0 = data[0];
       const UVMapping* uv = e0.hitInfo.hitPrimitive()->getUVMapping();
       uv->computeFrame(context, *this);
@@ -191,7 +195,7 @@
 
       int end;
       int i = 0;
-      
+
       // Compute normals
       while (i<size) {
 
@@ -202,11 +206,11 @@
 
         while(end < size && data[end].hitInfo.hitPrimitive() == prim)
           end++;
-        
+
         RayPacket subPacket(*this, i, end);
         prim->computeNormal(context, subPacket);
 
-        
+
         i=end;
       }
 
@@ -242,7 +246,7 @@
   };
 
   inline RayPacket::RayPacket(RayPacketData& data, int size,
-                             int depth, int flags)
+                              int depth, int flags)
     : data(&data.data[0]), size(size), depth(depth), flags(flags)
   {
   }





Archive powered by MHonArc 2.6.16.

Top of page