Browse Source

Photons mapping to triangles, other improvements

Josh Engebretson 8 years ago
parent
commit
7ace2ca4aa

+ 5 - 1
Source/AtomicGlow/Kernel/BakeMesh.cpp

@@ -396,7 +396,11 @@ void BakeMesh::Preprocess()
     // If GI is enabled, setup bounce metrics
     if (GlobalGlowSettings.giEnabled_)
     {
-        photonMap_ = new PhotonMap(radianceWidth_, radianceHeight_);
+        // granularity setting?
+        int pwidth = Min<int>(32, radianceWidth_ / 4);
+        int pheight = Min<int>(32, radianceHeight_ / 4);
+
+        photonMap_ = new PhotonMap(this, pwidth, pheight);
     }
 }
 

+ 92 - 32
Source/AtomicGlow/Kernel/Photons.cpp

@@ -21,6 +21,8 @@
 // THE SOFTWARE.
 //
 
+#include <Atomic/Core/StringUtils.h>
+
 #include "EmbreeScene.h"
 #include "SceneBaker.h"
 #include "Photons.h"
@@ -30,7 +32,8 @@ namespace AtomicGlow
 {
 
 
-PhotonMap::PhotonMap(int width, int height) :
+PhotonMap::PhotonMap(BakeMesh* bakeMesh, int width, int height) :
+    bakeMesh_(bakeMesh),
     width_(width),
     height_(height)
 {
@@ -52,20 +55,79 @@ PhotonMap::~PhotonMap()
 
 }
 
-void PhotonMap::Gather( int radius )
+void PhotonMap::SavePng(const String& filename) const
+{
+    Image image(bakeMesh_->GetContext());
+
+    image.SetSize(width_, height_, 3);
+    image.Clear(Color::BLACK);
+
+    for( int y = 0; y < height_; y++ )
+    {
+        for( int x = 0; x < width_; x++ )
+        {
+            const Photon& photon = photons_[y * width_ + x];
+
+            int count;
+            Color gathered = Color::BLACK;
+
+            for (count = 0; count < PHOTON_TRI_MAX; count++)
+            {
+                if (photon.tris_[count] == PHOTON_TRI_INVALID)
+                    break;
+
+                gathered += photon.gathered_[count];
+
+            }
+
+            if (!count)
+                continue;
+
+            gathered.r_ *= (1.0f / float(count));
+            gathered.g_ *= (1.0f / float(count));
+            gathered.b_ *= (1.0f / float(count));
+            gathered.a_ *= (1.0f / float(count));
+
+            image.SetPixel(x, y, gathered);
+        }
+
+    }
+
+    image.SavePNG(filename);
+
+}
+
+void PhotonMap::Gather(int radius )
 {
     for( int y = 0; y < height_; y++ )
     {
         for( int x = 0; x < width_; x++ )
         {
-            photons_[y * width_ + x].gathered_ = Gather(x, y, radius);
+            Photon& photon = photons_[y * width_ + x];
+
+            for (int i = 0; i < PHOTON_TRI_MAX; i++)
+            {
+                if (photon.tris_[i] == PHOTON_TRI_INVALID)
+                    break;
+
+                photon.gathered_[i] = Gather(photon.tris_[i], x, y, radius);
+            }
         }
     }
+
+    /*
+    if (true)
+    {
+        String filename = ToString("/Users/jenge/Temp/PhotonMap%i.png", bakeMesh_->GetGeomID());
+        SavePng(filename);
+    }
+    */
+
 }
 
-Color PhotonMap::Gather( int x, int y, int radius ) const
+Color PhotonMap::Gather( int triIndex, int x, int y, int radius ) const
 {
-    Color color;
+    Color color = Color::BLACK;
     int photons = 0;
 
     for( int j = y - radius; j <= y + radius; j++ )
@@ -79,16 +141,23 @@ Color PhotonMap::Gather( int x, int y, int radius ) const
 
             const Photon& photon = photons_[j * width_ + i];
 
+            int idx = photon.MapTriIndex(triIndex);
+
+            if (idx == PHOTON_TRI_INVALID)
+            {
+                continue;
+            }
+
             float distance = sqrtf( static_cast<float>( (x - i) * (x - i) + (y - j) * (y - j) ) );
 
             if( distance > radius ) {
                 continue;
             }
 
-            if (photon.photons_)
+            if (photon.photons_[idx])
             {
-                color += photon.color_;
-                photons += photon.photons_;
+                color += photon.color_[idx];
+                photons += photon.photons_[idx];
             }
         }
     }
@@ -155,10 +224,10 @@ void Photons::EmitPhotons( const BakeLight* light )
 
     for( int i = 0, n = emitter->GetPhotonCount(); i < n; i++ )
     {
-        // ** Emit photon
+        // Emit photon
         emitter->Emit( sceneBaker_, position, direction );
 
-        // ** Calculate light cutoff
+        // Calculate light cutoff
         float cut = 1.0f;
 
         if( const LightCutoff* cutoff = light->GetCutoffModel() )
@@ -178,7 +247,7 @@ void Photons::EmitPhotons( const BakeLight* light )
 
 void Photons::Trace(const LightAttenuation* attenuation, const Vector3& position, const Vector3& direction, const Color& color, int depth , unsigned lastGeomID, unsigned lastPrimID)
 {
-    // ** Maximum depth or energy threshold exceeded
+    // Maximum depth or energy threshold exceeded
     if( depth > maxDepth_ || color.Luma() < energyThreshold_ )
     {
         return;
@@ -210,13 +279,14 @@ void Photons::Trace(const LightAttenuation* attenuation, const Vector3& position
     Vector3 hitNormal(ray.Ng[0], ray.Ng[1], ray.Ng[2]);
     hitNormal.Normalize();
 
-    // ** Energy attenuation after a photon has passed the traced segment
+    // energy attenuation after a photon has passed the traced segment
     float att = 1.0f;
-    if( attenuation ) {
-        /*att =*/ attenuation->Calculate( (position - hitPosition).Length() );
+    if( attenuation )
+    {
+        att = attenuation->Calculate( (position - hitPosition).Length() );
     }
 
-    // ** Energy after reflection
+    // energy after reflection
     float influence = LightInfluence::GetLambert( direction, hitNormal ) * att;
 
     if (influence <= 0.0f)
@@ -235,7 +305,7 @@ void Photons::Trace(const LightAttenuation* attenuation, const Vector3& position
         return;
     }
 
-    // ** Final photon color
+    // final photon color
     hitColor.r_ *= (color.r_ * influence);
     hitColor.g_ *= (color.g_ * influence);
     hitColor.b_ *= (color.b_ * influence);
@@ -243,36 +313,26 @@ void Photons::Trace(const LightAttenuation* attenuation, const Vector3& position
     Vector2 st;
     bakeMesh->GetST(ray.primID, 1, bary, st);
 
-    // ** Store photon energy
-    Store( bakeMesh->GetPhotonMap(), hitColor, st );
+    // store photon energy
+    Store( bakeMesh->GetPhotonMap(), (int) ray.primID, hitColor, st );
 
-    // ** Keep tracing
+    // keep tracing
     Vector3 dir;
     Vector3::GetRandomHemisphereDirection(dir, hitNormal);
-    Trace( attenuation,hitPosition, dir, hitColor, depth + 1, ray.geomID, ray.primID );
+    Trace( attenuation, hitPosition, dir, hitColor, depth + 1, ray.geomID, ray.primID );
 }
 
-void Photons::Store( PhotonMap* photonmap, const Color& color, const Vector2& uv )
+void Photons::Store(PhotonMap* photonmap, int triIdx, const Color& color, const Vector2& uv )
 {
     if( !photonmap ) {
         return;
     }
 
-    if (color.r_ < 0.01f && color.g_ < 0.01f && color.b_ < 0.01f)
+    if (!photonmap->AddPhoton(triIdx, uv, color))
     {
-        // filter out tiny adds
         return;
     }
 
-    PhotonMap::Photon* photon = photonmap->GetPhoton( uv );
-
-    if( !photon ) {
-        return;
-    }
-
-    photon->color_ += color;
-    photon->photons_++;
-
     photonCount_++;
 }
 

+ 124 - 12
Source/AtomicGlow/Kernel/Photons.h

@@ -36,6 +36,9 @@ namespace AtomicGlow
 
 class SceneBaker;
 
+const int PHOTON_TRI_MAX = 8;
+const int PHOTON_TRI_INVALID = -1;
+
 class PhotonMap : public RefCounted
 {
     ATOMIC_REFCOUNTED(PhotonMap)
@@ -44,44 +47,153 @@ public:
 
     struct Photon
     {
-      Color gathered_;
-      Color color_;
-      int photons_;
+      int tris_[PHOTON_TRI_MAX];
+      Color gathered_[PHOTON_TRI_MAX];
+      Color color_[PHOTON_TRI_MAX];
+      int photons_[PHOTON_TRI_MAX];
+
+      int MapTriIndex(int triIndex) const
+      {
+          for (int i = 0; i < PHOTON_TRI_MAX; i++)
+          {
+              if (tris_[i] == PHOTON_TRI_INVALID)
+                  break;
+
+              if (tris_[i] == triIndex)
+                  return i;
+          }
+
+          return PHOTON_TRI_INVALID;
+
+      }
 
       void Reset()
       {
-        color_ = gathered_ = Color::BLACK;
-        photons_ = 0;
+          for (int i = 0; i < PHOTON_TRI_MAX; i++)
+          {
+              tris_[i] = PHOTON_TRI_INVALID;
+              color_[i] = gathered_[i] = Color::BLACK;
+              photons_[i] = 0;
+          }
       }
+
     };
 
-    PhotonMap(int width, int height);
+    PhotonMap(BakeMesh* bakeMesh, int width, int height);
     virtual ~PhotonMap();
 
-    Photon* GetPhoton(const Vector2& uv)
+    // Allocates a triangle, always check return, in readOnly mode won't allocate new tri
+    bool GetPhoton(int triIndex, const Vector2& uv, Color& color, int& photons, Color& gathered, bool readOnly = false)
     {
+        color = Color::BLACK;
+        gathered = Color::BLACK;
+        photons = 0;
+
         int x = static_cast<int>( uv.x_ * (width_  - 1) );
         int y = static_cast<int>( uv.y_ * (height_ - 1) );
 
         if (x < 0 || x >= width_)
-            return 0;
+            return false;
 
         if (y < 0 || y >= height_)
-            return 0;
+            return false;
 
-        return &photons_[y * width_ + x];
+        Photon* photon = &photons_[y * width_ + x];
+
+        int idx = photon->MapTriIndex(triIndex);
+
+        if (idx == PHOTON_TRI_INVALID)
+        {
+            if (readOnly)
+            {
+                return false;
+            }
+
+            for ( int i = 0; i < PHOTON_TRI_MAX; i++ )
+            {
+                if (photon->tris_[i] == PHOTON_TRI_INVALID)
+                {
+                    idx = photon->tris_[i] = triIndex;
+                    break;
+                }
+            }
+
+        }
+
+        if (idx == PHOTON_TRI_INVALID)
+        {
+            // out of tri storage
+            return false;
+        }
+
+        color = photon->color_[idx];
+        gathered = photon->gathered_[idx];
+        photons = photon->photons_[idx];
+
+        return true;
 
     }
 
+    // Adds a photon
+    bool AddPhoton(int triIndex, const Vector2& uv, const Color& color)
+    {
+
+        if (color.r_ < 0.01f && color.g_ < 0.01f && color.b_ < 0.01f)
+        {
+            // filter out tiny adds
+            return false;
+        }
+
+        int x = static_cast<int>( uv.x_ * (width_  - 1) );
+        int y = static_cast<int>( uv.y_ * (height_ - 1) );
+
+        if (x < 0 || x >= width_)
+            return false;
+
+        if (y < 0 || y >= height_)
+            return false;
+
+        Photon* photon = &photons_[y * width_ + x];
+
+        int idx = photon->MapTriIndex(triIndex);
+
+        if (idx == PHOTON_TRI_INVALID)
+        {
+            for ( int i = 0; i < PHOTON_TRI_MAX; i++ )
+            {
+                if (photon->tris_[i] == PHOTON_TRI_INVALID)
+                {
+                    idx = photon->tris_[i] = triIndex;
+                    break;
+                }
+            }
+        }
+
+        if (idx == PHOTON_TRI_INVALID)
+        {
+            // out of tri storage
+            return false;
+        }
+
+        photon->color_[idx] += color;
+        photon->photons_[idx]++;
+
+        return true;
+
+    }
+
+    void SavePng(const String& filename) const;
+
     void Gather( int radius );
 
-    Color Gather( int x, int y, int radius ) const;
+    Color Gather( int triIndex, int x, int y, int radius ) const;
 
 private:
 
     int width_;
     int height_;
 
+    WeakPtr<BakeMesh> bakeMesh_;
     SharedArrayPtr<Photon> photons_;
 
 };
@@ -124,7 +236,7 @@ private:
     void Trace(const LightAttenuation* attenuation, const Vector3& position, const Vector3& direction, const Color& color, int depth, unsigned lastGeomID = RTC_INVALID_GEOMETRY_ID, unsigned lastPrimID = RTC_INVALID_GEOMETRY_ID );
 
     //Stores a photon bounce.
-    void Store( PhotonMap* photonmap, const Color& color, const Vector2& uv );
+    void Store( PhotonMap* photonmap, int triIdx, const Color& color, const Vector2& uv );
 
 private:
 

+ 7 - 3
Source/AtomicGlow/Kernel/SceneBaker.cpp

@@ -640,12 +640,16 @@ void SceneBaker::IndirectLight( LightRay* lightRay)
         Vector2 st;
         bakeMesh->GetST(ray.primID, 1, bary, st);
 
-        PhotonMap::Photon* photon = photonMap->GetPhoton(Vector2(ray.u, ray.v));
+        int photons;
+        Color pcolor;
+        Color gcolor;
 
-        if (!photon || !photon->photons_)
+        if (!photonMap->GetPhoton( (int) ray.primID, st, pcolor, photons, gcolor, true))
+        {
             continue;
+        }
 
-        gathered += photon->gathered_.ToVector3() * influence;// + ambientColor;
+        gathered += gcolor.ToVector3() * influence;// + ambientColor;
 
     }