From 14d5ea07354c896eecfbea071d82c1f51ac72b3b Mon Sep 17 00:00:00 2001
From: jean-claude iehl <jean-claude.iehl@liris.cnrs.fr>
Date: Wed, 20 Mar 2024 14:23:28 +0100
Subject: [PATCH] framebuffer: accumulation des samples sur des doubles, pour
 faire de belles courbes de convergence...

---
 code/projects/framebuffer.h | 77 +++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 code/projects/framebuffer.h

diff --git a/code/projects/framebuffer.h b/code/projects/framebuffer.h
new file mode 100644
index 0000000..464f926
--- /dev/null
+++ b/code/projects/framebuffer.h
@@ -0,0 +1,77 @@
+
+#ifndef _FRAMEBUFFER_H
+#define _FRAMEBUFFER_H
+
+#include <vector>
+
+#include "image.h"
+
+
+// les floats 32 bits ne sont pas assez precis pour accumuler des milliers d'echantillons par pixel...
+struct Framebuffer
+{
+    struct pixel
+    {
+        double r, g, b;
+        unsigned n;
+    };
+    
+    std::vector<pixel> pixels;
+    std::vector<pixel> m2;
+    int m_width;
+    int m_height;
+    
+    Framebuffer( const int w, const int h ) : pixels(w*h), m2(w*h), m_width(w), m_height(h) {}
+    
+    int width() { return m_width; }
+    int height() { return m_height; }
+    
+    void splat( const float x, const float y, const Color& color )
+    {
+        int px= int(x);
+        int py= int(y);
+        assert(px >= 0 && px < m_width);
+        assert(py >= 0 && py < m_height);
+        int offset= py * m_width + px;
+        
+        // evaluation numerique stable de la moyenne et de la variance
+        // cf https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
+        pixels[offset].n++;
+        double r= color.r - pixels[offset].r;
+        double g= color.g - pixels[offset].g;
+        double b= color.b - pixels[offset].b;
+        
+        // moyenne
+        pixels[offset].r+= r / pixels[offset].n;
+        pixels[offset].g+= g / pixels[offset].n;
+        pixels[offset].b+= b / pixels[offset].n;
+        
+        // variance
+        m2[offset].r+= r * ( color.r - pixels[offset].r ); 
+        m2[offset].g+= g * ( color.g - pixels[offset].g ); 
+        m2[offset].b+= b * ( color.b - pixels[offset].b );
+    }
+    
+    
+    // renvoie la moyenne / image classique.
+    Image flatten( ) 
+    {
+        Image tmp(m_width, m_height);
+        for(unsigned i= 0; i < tmp.size(); i++)
+            tmp(i)= Color( float(pixels[i].r), float(pixels[i].g), float(pixels[i].b) );
+        
+        return tmp;
+    }
+    
+    // renvoie la variance / image classique.
+    Image flatten_var( ) 
+    {
+        Image tmp(m_width, m_height);
+        for(unsigned i= 0; i < tmp.size(); i++)
+            tmp(i)= Color( m2[i].r / pixels[i].n, m2[i].g / pixels[i].n, m2[i].b / pixels[i].n );
+        
+        return tmp;
+    }
+};
+
+#endif
-- 
GitLab