Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[Manta] r1855 - in trunk: Engine/Factory Engine/Renderers Interface Model/Materials


Chronological Thread 
  • From: sparker@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [Manta] r1855 - in trunk: Engine/Factory Engine/Renderers Interface Model/Materials
  • Date: Mon, 19 Nov 2007 23:50:52 -0700 (MST)

Author: sparker
Date: Mon Nov 19 23:50:48 2007
New Revision: 1855

Added:
   trunk/Engine/Renderers/KajiyaPathtracer.cc
   trunk/Engine/Renderers/KajiyaPathtracer.h
Modified:
   trunk/Engine/Factory/RegisterKnownComponents.cc
   trunk/Engine/Renderers/CMakeLists.txt
   trunk/Interface/Material.cc
   trunk/Interface/Material.h
   trunk/Interface/RayPacket.h
   trunk/Model/Materials/Lambertian.cc
   trunk/Model/Materials/Lambertian.h
Log:
Added the beginnings of a kajiya-style pathtracer based on packet sorting. 
I am not convinced it is correct - in fact, I am convinced it is not.
Numerous opportunities for performance improvement exist once it is correct.


Modified: trunk/Engine/Factory/RegisterKnownComponents.cc
==============================================================================
--- trunk/Engine/Factory/RegisterKnownComponents.cc     (original)
+++ trunk/Engine/Factory/RegisterKnownComponents.cc     Mon Nov 19 23:50:48 
2007
@@ -46,6 +46,7 @@
 #include <Engine/PixelSamplers/NullSampler.h>
 #include <Engine/PixelSamplers/SingleSampler.h>
 #include <Engine/PixelSamplers/JitterSampler.h>
+#include <Engine/Renderers/KajiyaPathtracer.h>
 #include <Engine/Renderers/Moire.h>
 #include <Engine/Renderers/Noise.h>
 #include <Engine/Renderers/NullRenderer.h>
@@ -111,6 +112,7 @@
     engine->registerComponent("jittersample", &JitterSampler::create);
 
     // Register renderers
+    engine->registerComponent("pathtracer", &KajiyaPathtracer::create);
     engine->registerComponent("null", &NullRenderer::create);
     engine->registerComponent("raygen", &RayGen::create);
     engine->registerComponent("moire", &Moire::create);

Modified: trunk/Engine/Renderers/CMakeLists.txt
==============================================================================
--- trunk/Engine/Renderers/CMakeLists.txt       (original)
+++ trunk/Engine/Renderers/CMakeLists.txt       Mon Nov 19 23:50:48 2007
@@ -1,5 +1,7 @@
 
 SET (Manta_Renderers_SRCS
+     Renderers/KajiyaPathtracer.h
+     Renderers/KajiyaPathtracer.cc
      Renderers/Moire.h
      Renderers/Moire.cc
      Renderers/Noise.h

Added: trunk/Engine/Renderers/KajiyaPathtracer.cc
==============================================================================
--- (empty file)
+++ trunk/Engine/Renderers/KajiyaPathtracer.cc  Mon Nov 19 23:50:48 2007
@@ -0,0 +1,377 @@
+// TODO
+// If single pixel, use a single accumulator
+// Put background rays at end to make alignment easier - DO BACKGROUND RAYS 
ALL AT ONCE!!!
+// Try sorting after MC by direction/origin and do not sort by matl
+// shadow rays with important sampling?
+// Russian roulette for shadow rays?
+#include <Engine/Renderers/KajiyaPathtracer.h>
+#include <Interface/Background.h>
+#include <Interface/Camera.h>
+#include <Interface/Context.h>
+#include <Interface/Material.h>
+#include <Interface/Object.h>
+#include <Interface/RayPacket.h>
+#include <Interface/SampleGenerator.h>
+#include <Interface/Scene.h>
+#include <Interface/ShadowAlgorithm.h>
+#include <Core/Math/MiscMath.h>
+#include <Core/Util/Assert.h>
+#include <Core/Util/NotFinished.h>
+#include <Core/Color/ColorSpace_fancy.h>
+#include <iostream>
+using namespace std;
+
+using namespace Manta;
+using SCIRun::Abs;
+
+Renderer* KajiyaPathtracer::create(const vector<string>& args)
+{
+  return new KajiyaPathtracer(args);
+}
+
+KajiyaPathtracer::KajiyaPathtracer(const vector<string>& /*args*/)
+{
+}
+
+KajiyaPathtracer::~KajiyaPathtracer()
+{
+}
+
+void KajiyaPathtracer::setupBegin(const SetupContext&, int)
+{
+}
+
+void KajiyaPathtracer::setupDisplayChannel(SetupContext&)
+{
+}
+
+void KajiyaPathtracer::setupFrame(const RenderContext&)
+{
+}
+
+static inline bool sort_needs_swap(const RayPacketData* data, int i, int j)
+{
+  return (long)data->hitMatl[i] > (long)data->hitMatl[j];
+}
+
+template<class T>
+static inline void swap(T* array, int i, int j)
+{
+  T tmp = array[i];
+  array[i] = array[j];
+  array[j] = tmp;
+}
+
+void KajiyaPathtracer::traceEyeRays(const RenderContext& context, RayPacket& 
rays)
+{
+  ASSERT(rays.getFlag(RayPacket::HaveImageCoordinates));
+  context.camera->makeRays(context, rays);
+  rays.initializeImportance();
+
+  Packet<Color> result;
+  result.fill(rays.begin(), rays.end(), Color::black());
+  Packet<Color> total_attenuation;
+  total_attenuation.fill(rays.begin(), rays.end(), Color::white());
+  Packet<Color> reflectance;
+
+  Packet<int> permute;
+  if(!rays.getFlag(RayPacket::ConstantPixel)){
+    for(int i=rays.begin();i<rays.end();i++)
+      permute.data[i] = i;
+  }
+
+  int originalBegin = rays.begin();
+  int originalEnd = rays.end();
+
+  RayPacketData* data = rays.data;
+  int depth = 0;
+  int maxdepth = context.scene->getRenderParameters().maxDepth;
+  for(;;){
+
+    rays.resetHits();
+    context.scene->getObject()->intersect(context, rays);
+
+    // Sort the rays based on the material that they hit
+    // Simple bubble sort for now - performance will come later
+    // This may not be worthwhile if we sort by directions, but
+    // we would still need to sort out the background rays (one pass)
+    // Another option is to use a sort that picks one unique value and then
+    // searches for all pointers of this type.   It could probably be SSEd.
+    for(int i=rays.begin();i<rays.end()-1;i++){
+      for(int j=i+1;j<rays.end();j++){
+        if(sort_needs_swap(data, i, j)){
+          // Move hitPrim, hitMatl, hitTex, origin, direction, minT, time
+          swap(data->hitPrim, i, j);
+          swap(data->hitMatl, i, j);
+          swap(data->hitTex, i, j);
+          for(int k=0;k<3;k++)
+            swap(data->origin[k], i, j);
+          for(int k=0;k<3;k++)
+            swap(data->direction[k], i, j);
+          swap(data->minT, i, j);
+          swap(data->time, i, j);
+
+          // Conditionally: normal
+          for(int k=0;k<3;k++)
+            swap(data->normal[k], i, j);
+
+          // Conditionally: ffnormal,
+          for(int k=0;k<3;k++)
+            swap(data->ffnormal[k], i, j);
+
+          // Conditionally: hitPosition,
+          for(int k=0;k<3;k++)
+            swap(data->hitPosition[k], i, j);
+
+          // Conditionally: texCoords, dPdu, dpDv
+          for(int k=0;k<3;k++)
+            swap(data->texCoords[k], i, j);
+          for(int k=0;k<3;k++)
+            swap(data->dPdu[k], i, j);
+          for(int k=0;k<3;k++)
+            swap(data->dPdv[k], i, j);
+
+          // Move sample_id, region_id
+          swap(data->sample_id, i, j);
+          swap(data->region_id, i, j);
+
+          // Move scratchpads???
+          // Move result
+          for(int k=0;k<3;k++)
+            swap(result.colordata[k], i, j);
+
+          // Move total attenuation
+          for(int k=0;k<3;k++)
+            swap(total_attenuation.colordata[k], i, j);
+
+          // Move permute
+          swap(permute.data, i, j);
+        }
+      }
+    }
+    // Skip background rays - they will be shaded all at once below
+    int newBegin = rays.begin();
+    while(!rays.wasHit(newBegin))
+      newBegin++;
+    rays.resize(newBegin, rays.end());
+    if(rays.begin() == rays.end())
+      break;
+
+    // Clear inverseDirection, corner_dir, signs
+    rays.flags &= ~(RayPacket::HaveCornerRays | 
RayPacket::HaveInverseDirections | RayPacket::HaveSigns);
+
+    rays.computeFFNormals(context); // Must do this before writing over the 
ray direction
+
+    // Compute new rays and reflectance for anything that hit a surface
+    for(int i = rays.begin();i<rays.end();){
+      const Material* hit_matl = rays.getHitMaterial(i);
+      int end = i+1;
+      while(end < rays.end() &&  rays.getHitMaterial(end) == hit_matl)
+        end++;
+      RayPacket subPacket(rays, i, end);
+      hit_matl->sampleBSDF(context, subPacket, reflectance);
+      i=end;
+    }
+
+    // Russian roulette and collapse
+    bool do_russian_roulette = true;
+    if(do_russian_roulette){
+      Packet<Real> rr;
+      context.sample_generator->nextSeeds(context, rr, rays);
+      int newEnd = rays.end();
+      for(int i=rays.begin();i<newEnd;i++){
+        if(rr.get(i) > reflectance.get(i).luminance()){
+          // Kill it by swapping with the last ray
+          // We may not need to move origin/direction back....
+          --newEnd;
+          // Move origin, direction
+          // Look at one-way move optimization
+          for(int j=0;j<3;j++)
+            swap(data->origin[j], i, newEnd);
+          for(int j=0;j<3;j++)
+            swap(data->direction[j], i, newEnd);
+          
+          // Move time
+          // Look at one-way move optimization
+          swap(data->time, i, newEnd);
+          
+          // Move sample_id, region_id
+          // Look at one-way move optimization
+          swap(data->sample_id, i, newEnd);
+          swap(data->region_id, i, newEnd);
+          
+          // Move result
+          for(int j=0;j<3;j++)
+            swap(result.colordata[j], i, newEnd);
+          
+          // Move reflectance
+          // Look at one-way move optimization
+          for(int j=0;j<3;j++)
+            swap(reflectance.colordata[j], i, newEnd);
+          
+          // Move total attenuation
+          // Look at one-way move optimization
+          for(int j=0;j<3;j++)
+            swap(total_attenuation.colordata[j], i, newEnd);
+          
+          // Move rr
+          // Look at one-way move optimization
+          swap(rr.data, i, newEnd);
+
+          // Move permute
+          swap(permute.data, i, newEnd);
+
+          --i;
+        } else {
+          Real scale = 1./reflectance.get(i).luminance();
+          for(int j=0;j<3;j++)
+            reflectance.colordata[j][i] *= scale;
+          for(int j=0;j<3;j++)
+            total_attenuation.colordata[j][i] *= reflectance.colordata[j][i];
+        }
+      
+        rays.resize(rays.begin(), newEnd);
+        if(rays.begin() == rays.end())
+          break;
+      }
+    } else {
+      for(int i=rays.begin();i<rays.end();i++){
+        for(int j=0;j<3;j++)
+          total_attenuation.colordata[j][i] *= reflectance.colordata[j][i];
+      }
+    }
+
+
+    // Cast shadow rays
+    ShadowAlgorithm::StateBuffer shadowState;
+    do {
+      RayPacketData shadowData;
+      RayPacket shadowRays(shadowData, RayPacket::UnknownShape, 0, 0, depth, 
false);
+
+      // Call the shadowalgorithm(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.
+      context.shadowAlgorithm->computeShadows(context, shadowState, 
context.scene->getLights(),
+                                              rays, shadowRays);
+
+      // We need normalized 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 lighting contributions.
+          Vector normal = rays.getFFNormal(i);
+          Vector light_dir = shadowRays.getDirection(i);
+          double dist = light_dir.normalize();
+          // This should be retrieved from the light somehow - probably put 
into the light color
+          double A = 20;
+          //NOT_FINISHED("Light source area and normal");
+          Vector light_normal = Vector(0, -1, 0);
+          double weight=Dot(normal, light_dir) * Abs(Dot(light_normal, 
light_dir)) * A / (M_PI*dist*dist);
+          Color light_color = shadowRays.getColor(i);
+          result.set(i, result.get(i) + total_attenuation.get(i) * 
light_color * weight);
+        }
+      }
+    } while(!shadowState.done());
+
+    depth++;
+    if(depth >= maxdepth)
+      break;
+
+    rays.flags &= RayPacket::ConstantEye |  RayPacket::ConstantPixel | 
RayPacket::ConstantSampleRegion;
+  }
+
+  // Add contribution from background rays, which will be at the beginning.  
 
+  if(rays.begin() != originalBegin){
+    RayPacket subPacket(rays, originalBegin, rays.begin());
+    context.scene->getBackground()->shade(context, subPacket);
+    for(int i=originalBegin;i<rays.begin();i++){
+      for(int j=0;j<3;j++)
+        result.colordata[j][i] += data->color[j][i] * 
total_attenuation.colordata[j][i];
+    }
+  }
+
+  rays.resize(originalBegin, originalEnd);
+  rays.resetHits();
+  rays.flags &= RayPacket::ConstantEye |  RayPacket::ConstantPixel | 
RayPacket::ConstantSampleRegion;
+  rays.flags |= RayPacket::NormalizedDirections;
+  rays.shape = RayPacket::UnknownShape;
+
+  for(int i=rays.begin();i<rays.end();i++){
+    rays.setColor(permute.get(i), result.get(i));
+  }
+
+}
+
+void KajiyaPathtracer::traceRays(const RenderContext& context, RayPacket& 
rays)
+{
+  int debugFlag = rays.getAllFlags() & RayPacket::DebugPacket;
+  rays.resetHits();
+  context.scene->getObject()->intersect(context, rays);
+
+  // Go through the ray packet and shade them.  Group rays that hit the
+  // same object and material to shade with a single shade call
+  for(int i = rays.begin();i<rays.end();){
+    if(rays.wasHit(i)){
+      const Material* hit_matl = rays.getHitMaterial(i);
+      int end = i+1;
+      while(end < rays.end() && rays.wasHit(end) &&
+            rays.getHitMaterial(end) == hit_matl)
+        end++;
+      if (debugFlag) {
+        rays.computeHitPositions();
+        for (int j = i; j < end; ++j) {
+          cerr << "raytree: ray_index "<<j
+               << " depth " << rays.getDepth()
+               << " origin "<< rays.getOrigin(j)
+               << " direction "<< rays.getDirection(j)
+               << " hitpos " << rays.getHitPosition(j)
+               << "\n";
+        }
+      }
+      RayPacket subPacket(rays, i, end);
+      hit_matl->shade(context, subPacket);
+      i=end;
+    } else {
+      int end = i+1;
+      while(end < rays.end() && !rays.wasHit(end))
+        end++;
+      if (debugFlag) {
+        for (int j = i; j < end; ++j) {
+          cerr << "raytree: ray_index "<<j
+               << " depth " << rays.getDepth()
+               << " origin "<< rays.getOrigin(j)
+               << " direction "<< rays.getDirection(j)
+               << "\n";
+        }
+      }
+      RayPacket subPacket(rays, i, end);
+      context.scene->getBackground()->shade(context, subPacket);
+      i=end;
+    }
+  }
+}
+
+void KajiyaPathtracer::traceRays(const RenderContext& context, RayPacket& 
rays, Real cutoff)
+{
+  for(int i = rays.begin(); i != rays.end();) {
+    if(rays.getImportance(i).luminance() > cutoff) {
+      int end = i + 1;
+      while(end < rays.end() && rays.getImportance(end).luminance() > cutoff)
+        end++;
+
+      RayPacket subPacket(rays, i, end);
+      traceRays(context, subPacket);
+      i = end;
+    } else {
+      // need to set the color to black
+      rays.setColor(i, Color::black());
+      int end = i + 1;
+      while(end < rays.end() && rays.getImportance(end).luminance() <= 
cutoff) {
+        rays.setColor(end, Color::black());
+        end++;
+      }
+      i = end;
+    }
+  }
+}

Added: trunk/Engine/Renderers/KajiyaPathtracer.h
==============================================================================
--- (empty file)
+++ trunk/Engine/Renderers/KajiyaPathtracer.h   Mon Nov 19 23:50:48 2007
@@ -0,0 +1,35 @@
+
+#ifndef Manta_Engine_KajiyaPathtracer_h
+#define Manta_Engine_KajiyaPathtracer_h
+
+#include <Interface/Renderer.h>
+#include <sgi_stl_warnings_off.h>
+#include <string>
+#include <vector>
+#include <sgi_stl_warnings_on.h>
+
+namespace Manta {
+  using namespace std;
+  class ShadowAlgorithm;
+
+  class KajiyaPathtracer : public Renderer {
+  public:
+    KajiyaPathtracer() {}
+    KajiyaPathtracer(const vector<string>& args);
+    virtual ~KajiyaPathtracer();
+    virtual void setupBegin(const SetupContext&, int numChannels);
+    virtual void setupDisplayChannel(SetupContext&);
+    virtual void setupFrame(const RenderContext& context);
+
+    virtual void traceEyeRays(const RenderContext&, RayPacket& rays);
+    virtual void traceRays(const RenderContext&, RayPacket& rays);
+    virtual void traceRays(const RenderContext&, RayPacket& rays, Real 
cutoff);
+
+    static Renderer* create(const vector<string>& args);
+  private:
+    KajiyaPathtracer(const KajiyaPathtracer&);
+    KajiyaPathtracer& operator=(const KajiyaPathtracer&);
+  };
+}
+
+#endif

Modified: trunk/Interface/Material.cc
==============================================================================
--- trunk/Interface/Material.cc (original)
+++ trunk/Interface/Material.cc Mon Nov 19 23:50:48 2007
@@ -1,5 +1,6 @@
 
 #include <Interface/Material.h>
+#include <Core/Exceptions/InternalError.h>
 
 using namespace Manta;
 
@@ -9,5 +10,11 @@
 
 Material::~Material()
 {
+}
+
+void Material::sampleBSDF(const RenderContext& context,
+                          RayPacket& rays, Packet<Color>& reflectance) const
+{
+  throw SCIRun::InternalError("computeBSDF not implemented for this 
material", __FILE__, __LINE__);
 }
 

Modified: trunk/Interface/Material.h
==============================================================================
--- trunk/Interface/Material.h  (original)
+++ trunk/Interface/Material.h  Mon Nov 19 23:50:48 2007
@@ -31,11 +31,14 @@
 */
 
 #include <Interface/Interpolable.h>
+#include <Core/Color/Color.h>
 
 namespace Manta {
   class PreprocessContext;
   class RayPacket;
   class RenderContext;
+  class Vector;
+  template<class T> class Packet;
 
   class Material : public Interpolable {
   public:
@@ -50,6 +53,8 @@
     // represent no light.
     virtual void attenuateShadows(const RenderContext& context,
                                   RayPacket& shadowRays) const = 0;
+    virtual void sampleBSDF(const RenderContext& context,
+                            RayPacket& rays, Packet<Color>& reflectance) 
const;
 
   private:
     // Material(const Material&);

Modified: trunk/Interface/RayPacket.h
==============================================================================
--- trunk/Interface/RayPacket.h (original)
+++ trunk/Interface/RayPacket.h Mon Nov 19 23:50:48 2007
@@ -156,6 +156,8 @@
       HaveSurfaceDerivatives = 0x00008000,
       ConstantSampleRegion   = 0x00010000,
 
+      ConstantPixel          = 0x00020000,
+
       DebugPacket            = 0x80000000,
     };
 

Modified: trunk/Model/Materials/Lambertian.cc
==============================================================================
--- trunk/Model/Materials/Lambertian.cc (original)
+++ trunk/Model/Materials/Lambertian.cc Mon Nov 19 23:50:48 2007
@@ -33,13 +33,17 @@
 #include <Interface/RayPacket.h>
 #include <Interface/AmbientLight.h>
 #include <Interface/Context.h>
+#include <Interface/SampleGenerator.h>
 #include <Interface/ShadowAlgorithm.h>
+#include <Core/Math/Expon.h>
+#include <Core/Math/Trig.h>
 #include <Core/Persistent/MantaRTTI.h>
 #include <Core/Persistent/ArchiveElement.h>
 #include <Interface/InterfaceRTTI.h>
 #include <Model/Textures/Constant.h>
 #include <iostream>
 using namespace Manta;
+using namespace SCIRun;
 using std::cerr;
 
 Lambertian::Lambertian(const Color& color)
@@ -235,6 +239,33 @@
 #endif
 
 }
+
+void Lambertian::sampleBSDF(const RenderContext& context,
+                          RayPacket& rays, Packet<Color>& reflectance) const
+{
+  rays.computeHitPositions();
+  Packet<Real> r1;
+  context.sample_generator->nextSeeds(context, r1, rays);
+  Packet<Real> r2;
+  context.sample_generator->nextSeeds(context, r2, rays);
+  rays.computeFFNormals(context);
+  rays.computeSurfaceDerivatives(context);
+  for(int i=rays.begin();i<rays.end();i++){
+    Real sintheta2 = r1.get(i);
+    Real sintheta=Sqrt(sintheta2);
+    Real costheta=Sqrt(1-sintheta2);
+    Real phi=2*M_PI*r2.get(i);
+    Real cosphi=Cos(phi)*sintheta;
+    Real sinphi=Sin(phi)*sintheta;
+    Vector normal = rays.getFFNormal(i);
+    Vector v1 = rays.getSurfaceDerivativeU(i);
+    Vector v2 = rays.getSurfaceDerivativeV(i);
+    rays.setDirection(i, normal * costheta + v1 * cosphi + v2 * sinphi);
+    rays.setOrigin(i, rays.getHitPosition(i));
+  }
+  colortex->mapValues(reflectance, context, rays);
+}
+
 
 namespace Manta {
   MANTA_DECLARE_RTTI_DERIVEDCLASS(Lambertian, LitMaterial, ConcreteClass, 
readwriteMethod);

Modified: trunk/Model/Materials/Lambertian.h
==============================================================================
--- trunk/Model/Materials/Lambertian.h  (original)
+++ trunk/Model/Materials/Lambertian.h  Mon Nov 19 23:50:48 2007
@@ -46,6 +46,9 @@
     virtual ~Lambertian();
 
     virtual void shade(const RenderContext& context, RayPacket& rays) const;
+    virtual void sampleBSDF(const RenderContext& context,
+                            RayPacket& rays, Packet<Color>& reflectance) 
const;
+
     void readwrite(ArchiveElement* archive);
   private:
     const Texture<Color>* colortex;




  • [Manta] r1855 - in trunk: Engine/Factory Engine/Renderers Interface Model/Materials, sparker, 11/20/2007

Archive powered by MHonArc 2.6.16.

Top of page