Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[Manta] r2228 - trunk/Engine/Renderers


Chronological Thread 
  • From: roni@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [Manta] r2228 - trunk/Engine/Renderers
  • Date: Sun, 27 Apr 2008 20:56:08 -0600 (MDT)

Author: roni
Date: Sun Apr 27 20:56:07 2008
New Revision: 2228

Modified:
   trunk/Engine/Renderers/NPREdges.cc
   trunk/Engine/Renderers/NPREdges.h
Log:
Replaced square stencil with circular stencil; detecting lines now
works better for not axis-aligned lines.

Changed "quality" parameter (-N) to refer to how dense the stencil is.
Default is N=1; N=2 gives better quality, and N=3 seems to hit
diminishing returns.


Modified: trunk/Engine/Renderers/NPREdges.cc
==============================================================================
--- trunk/Engine/Renderers/NPREdges.cc  (original)
+++ trunk/Engine/Renderers/NPREdges.cc  Sun Apr 27 20:56:07 2008
@@ -30,7 +30,7 @@
     lineWidth(2.0), normalThreshold(0.0),
     computeCreases(true),
     noshade(false),
-    N(2)
+    N(1)
 {
   bool threshold_set = false;
 
@@ -65,6 +65,17 @@
 
   if(!threshold_set)
     this->setNormalThreshold(0.1);
+
+  // M is one more than the square root of the number of total
+  // samples (the "middle" sample should be omitted).
+  M = 1+2*N;
+  stencil_size = M*M-1;
+
+  // last_ring is the stencil index of the first element of the final
+  // ring of stencil rays.  This is used to compute the stencil
+  // indices of the rays to be used for the normal gradient
+  // computation.
+  last_ring = (2*N-1)*(2*N-1) - 1;
 }
 
 NPREdges::~NPREdges()
@@ -125,46 +136,17 @@
 
   // Create parallel ray packets, each containing one member of a
   // "surround" for each ray in the rays parameter.
-  RayPacketData *stencil_data = MANTA_STACK_ALLOC(RayPacketData, N*N);
-  RayPacket *stencil = MANTA_STACK_ALLOC(RayPacket, N*N);
-
-  // Each ray in each stencil raypacket is at a constant offset from
-  // the rays in the sample raypacket, so they can inherit the shape
-  // flag.
-  for(int i=0; i<N*N; i++){
-    new (stencil_data+i)RayPacketData;
-    new (stencil+i)RayPacket(stencil_data[i], rays.shape, rays.begin(), 
rays.end(), rays.getDepth(), RayPacket::HaveImageCoordinates);
-  }
-
-  // Populate the surround packets' image coordinates.
-  for(int i=rays.begin(); i<rays.end(); i++){
-    int eye = rays.getWhichEye(i);
-
-    // (low_x, low_y) is the bottom left of a box of size (imageX,
-    // imageY), with the sample ray intersecting it in the center.
-    const Real inc_x = imageX / N;
-    const Real inc_y = imageY / N;
-    const Real low_x = rays.getImageCoordinates(i, 0) - 0.5*imageX + 
0.5*inc_x;
-    const Real low_y = rays.getImageCoordinates(i, 1) - 0.5*imageY + 
0.5*inc_y;
-
-    if(debugFlag){
-      std::cout << "sample ray: (" << rays.getImageCoordinates(i, 0) << ", " 
<< rays.getImageCoordinates(i, 1) << ")" << std::endl;
-    }
+  RayPacketData *stencil_data = 0;
+  RayPacket *stencil = 0;
 
-    for(int j=0; j<N; j++){
-      const Real ypos = low_y + j*inc_y;
-      for(int k=0; k<N; k++){
-        stencil[j*N+k].setPixel(i, eye, low_x + k*inc_x, ypos);
+  stencil_data = MANTA_STACK_ALLOC(RayPacketData, stencil_size);
+  stencil = MANTA_STACK_ALLOC(RayPacket, stencil_size);
+  
+  // Compute the stencil locations.
+  computeCircleStencil(stencil, stencil_data, rays);
 
-        if(debugFlag){
-          std::cout << "stencil ray (" << j << ", " << k << "): (" << (low_x 
+ k*inc_x) << ", " << ypos << ")" << std::endl;
-        }
-      }
-    }
-  }
-
-  // Generate camera rays for the surround and trace them.
-  for(int i=0; i<N*N; i++){
+  // Generate camera rays for the stencil and trace them.
+  for(int i=0; i<stencil_size; i++){
     context.camera->makeRays(context, stencil[i]);
     stencil[i].resetHits();
     context.scene->getObject()->intersect(context, stencil[i]);
@@ -181,7 +163,7 @@
         if(debugFlag)
           cerr << "count was " << count << endl;
 
-        float lightness = Abs(count - N*N/2.0) / (N*N/2.0);
+        float lightness = Abs(count - stencil_size/2.0) / (stencil_size/2.0);
         rays.setColor(i, rays.getColor(i)*lightness);
 
         ++i;
@@ -219,10 +201,10 @@
         // the case but need to make sure.
         //
         // Check for crease line.
-        RayPacket normRight(stencil[N-1], i, j);
-        RayPacket normLeft(stencil[N*(N-1)], i, j);
-        RayPacket normUp(stencil[N*N-1], i, j);
-        RayPacket normDown(stencil[0], i, j);
+        RayPacket normRight(stencil[last_ring + 0], i, j);
+        RayPacket normUp(stencil[last_ring + 2*N], i, j);
+        RayPacket normLeft(stencil[last_ring + 4*N], i, j);
+        RayPacket normDown(stencil[last_ring + 6*N], i, j);
 
         normRight.computeFFNormals(context);
         normLeft.computeFFNormals(context);
@@ -268,13 +250,13 @@
   if(sample.wasHit(i)){
     // The sample ray hit a primitive; check if this is an intersection 
sample.
     const Primitive *hit = sample.getHitPrimitive(i);
-    for(int j=0; j<N*N; j++)
+    for(int j=0; j<stencil_size; j++)
       if(!(stencil[j].wasHit(i) && (stencil[j].getHitPrimitive(i) == hit)))
        return Intersection;
   }
   else{
     // The sample ray struck the background; check if this is an 
intersection sample.
-    for(int j=0; j<N*N; j++)
+    for(int j=0; j<stencil_size; j++)
       if(stencil[j].wasHit(i))
        return Intersection;
     
@@ -294,10 +276,21 @@
     // The sample ray hit a primitive; check if this is an intersection 
sample.
     count = 0;
     const Primitive *hit = sample.getHitPrimitive(i);
-    for(int j=0; j<N*N; j++)
+
+    if(debugFlag){
+      std::cout << "hit = " << hit << std::endl;
+    }
+
+    for(int j=0; j<stencil_size; j++)
       if(!(stencil[j].wasHit(i) && (stencil[j].getHitPrimitive(i) == hit))){
+        if(debugFlag){
+          std::cout << "stencil[" << j << "] off (" << 
stencil[j].getHitPrimitive(i) << ")" << std::endl;
+        }
         ++count;
       }
+      else if(debugFlag){
+        std::cout << "stencil[" << j << "] on" << std::endl;
+      }
 
     if(debugFlag)
       std::cout << "count = " << count << std::endl;
@@ -308,9 +301,16 @@
   else{
     // The sample ray struck the background; check if this is an 
intersection sample.
     count = 0;
-    for(int j=0; j<N*N; j++)
-      if(stencil[j].wasHit(i))
+    for(int j=0; j<stencil_size; j++)
+      if(stencil[j].wasHit(i)){
+        if(debugFlag){
+          std::cout << "stencil[" << j << "] struck " << 
stencil[j].getHitPrimitive(i) << std::endl;
+        }
         ++count;
+      }
+      else if(debugFlag){
+        std::cout << "stencil[" << j << "] struck background" << std::endl;
+      }
 
     if(count > 0)
       return Intersection;
@@ -346,4 +346,51 @@
 
 void NPREdges::setNormalThreshold(Real val){
   normalThreshold = val*val*lineWidth*lineWidth;
+}
+
+void NPREdges::computeCircleStencil(RayPacket *stencil, RayPacketData 
*stencil_data, const RayPacket& rays) const {
+  static Real *x = 0, *y = 0;
+  if(!x){
+    // TODO(choudhury): x and y should be data members so they can be
+    // delete'ed at destruction time.
+    x = new Real[stencil_size];
+    y = new Real[stencil_size];
+
+#ifndef NDEBUG
+    std::cout << "Stencil ray positions:" << std::endl;
+#endif
+
+    int j=0;
+    for(int r=1; r<=N; r++){
+      const int ringsize = 8*r;
+      const int start = j;
+      const int end = j+ringsize;
+
+      const float angle_inc = 2*M_PI/(ringsize);
+      const float radius = r*imageX*0.5 / N;
+
+      for(; j<end; j++){
+        x[j] = radius*cos(angle_inc*(j-start));
+        y[j] = radius*sin(angle_inc*(j-start));
+
+#ifndef NDEBUG
+        std::cout << x[j] << " " << y[j] << std::endl;
+#endif
+      }
+    }
+  }
+
+  for(int i=0; i<stencil_size; i++){
+    new (stencil_data+i)RayPacketData;
+    new (stencil+i)RayPacket(stencil_data[i], rays.shape, rays.begin(), 
rays.end(), rays.getDepth(), RayPacket::HaveImageCoordinates);
+  }
+
+  for(int i=rays.begin(); i<rays.end(); i++){
+    int eye = rays.getWhichEye(i);
+
+    for(int j=0; j<stencil_size; j++)
+      stencil[j].setPixel(i-rays.begin(), eye,
+                          rays.getImageCoordinates(i, 0) + x[j],
+                          rays.getImageCoordinates(i, 1) + y[j]);
+  }
 }

Modified: trunk/Engine/Renderers/NPREdges.h
==============================================================================
--- trunk/Engine/Renderers/NPREdges.h   (original)
+++ trunk/Engine/Renderers/NPREdges.h   Sun Apr 27 20:56:07 2008
@@ -11,6 +11,7 @@
 namespace Manta {
   class Primitive;
   class Raytracer;
+  class RayPacketData;
 
   using namespace std;
 
@@ -32,6 +33,9 @@
     void setNormalThreshold(Real val);
 
   protected:
+    void computeCircleStencil(RayPacket *stencil, RayPacketData 
*stencil_data, const RayPacket& rays) const;
+
+  protected:
     typedef enum {
       Background,
       Shade,
@@ -49,7 +53,8 @@
     Real lineWidth, normalThreshold;
     bool computeCreases, noshade;
 
-    int N;
+    int N, M, stencil_size;
+    int last_ring;
 
   private:
     NPREdges(const NPREdges&);




  • [Manta] r2228 - trunk/Engine/Renderers, roni, 04/27/2008

Archive powered by MHonArc 2.6.16.

Top of page