diff --git a/src/DemoApp/main.cpp b/src/DemoApp/main.cpp
index d9902a89a614d82e42411070b70cb16977126daf..f299b1318d7915809d9f48a7c2c4eb1dce8fb5b6 100644
--- a/src/DemoApp/main.cpp
+++ b/src/DemoApp/main.cpp
@@ -138,11 +138,20 @@ void AddCustomAttributeToMeshes() {
  * add an edition widget as in Radium app demo
  */
 const std::string customVertexAttrib{"in vec4 myCustomAttrib;\n"
-                                     "out vec4 fragCustomAttrib;\n"
+                                     "out vec4 geomCustomAttrib;\n"
                                      "\nvoid outputCustomAttribs() { \n"
-                                     "fragCustomAttrib=myCustomAttrib;\n"
+                                     "geomCustomAttrib=myCustomAttrib;\n"
                                      "}\n"};
 
+/* Geometry shader : just copy the attrib
+ *
+ */
+const std::string customGeomAttrib{"in vec4 geomCustomAttrib[];\n"
+                                   "out vec4 fragCustomAttrib;\n"
+                                   "\nvoid propagateAttributes() { \n"
+                                   "fragCustomAttrib=geomCustomAttrib[0];\n"
+                                   "}\n"};
+
 /* Fragment shader : here, the objective is to compute the final color of the fragment.
  * This function get the Material associated with the objet. This material could be
  * used through the Radium GLSL BSDF interface (see Radium doc)
@@ -156,7 +165,6 @@ const std::string customVertexAttrib{"in vec4 myCustomAttrib;\n"
  * Note that this string could also be loaded from a file and/or manually edited if you
  * add an edition widget as in Radium app demo
  */
-
 const std::string customFragmentColor{
     "in vec4 fragCustomAttrib;\n"
     "\nvec4 computeCustomColor(Material mat, vec3 lightDir, vec3 viewDir, vec3 normal_world) {\n"
@@ -218,7 +226,7 @@ int main( int argc, char* argv[] ) {
     //! [Instatiating the renderer giving a customization functor]
     RendererController renderControl;
     auto renderer = std::make_shared<RadiumNBR::NodeBasedRenderer>( renderControl );
-    renderControl.setAttribToColorFunc( customVertexAttrib, customFragmentColor );
+    renderControl.setAttribToColorFunc( customVertexAttrib, customGeomAttrib, customFragmentColor );
     //! [Instatiating the renderer giving a customization functor]
 
     //! [Instatiating the application]
@@ -236,58 +244,3 @@ int main( int argc, char* argv[] ) {
 
     return app.exec();
 }
-
-// Will be removed soon
-#if 0
-int main( int argc, char* argv[] ) {
-
-    //! [Instatiating the renderer giving a customization functor]
-    RendererController renderControl;
-    auto renderer = std::make_shared<RadiumNBR::NodeBasedRenderer>( renderControl );
-    renderControl.setAttribToColorFunc( customVertexAttrib, customFragmentColor );
-    //! [Instatiating the renderer giving a customization functor]
-
-    //! [Instatiating the application]
-    Ra::Gui::BaseApplication app( argc, argv );
-    //! [Instatiating the application]
-
-    //! [Initializing the application]
-    // The customization functor is called here
-    app.initialize( DemoWindowFactory( renderer ) );
-    //! [Initializing the application]
-
-    //! [show the base grid on the renderer]
-    renderer->showDebug( false );
-    //! [show the base grid on the renderer]
-
-    //! [Creating the cube]
-    auto cube = Ra::Core::Geometry::makeSharpBox( {0.1f, 0.1f, 0.1f} );
-    //! [Creating the cube]
-
-    //! [Colorize the Cube]
-    cube.addAttrib(
-        "myCustomAttrib",
-        Ra::Core::Vector4Array{cube.vertices().size(), Ra::Core::Utils::Color::Yellow()} );
-    //! [Colorize the Cube]
-
-    //! [Create the engine entity for the cube]
-    auto e = app.m_engine->getEntityManager()->createEntity( "Green cube" );
-    //! [Create the engine entity for the cube]
-
-    //! [Create a geometry component with the cube]
-    auto c =
-        new Ra::Engine::Scene::TriangleMeshComponent( "Cube Mesh", e, std::move( cube ), nullptr );
-    //! [Create a geometry component with the cube]
-
-    //! [Register the entity/component association to the geometry system ]
-    auto geometrySystem = app.m_engine->getSystem( "GeometrySystem" );
-    geometrySystem->addComponent( e, c );
-    //! [Register the entity/component association to the geometry system ]
-
-    //! [Tell the window that something is to be displayed]
-    app.m_mainWindow->prepareDisplay();
-    //! [Tell the window that something is to be displayed]
-
-    return app.exec();
-}
-#endif
diff --git a/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp b/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp
index 6b0fe77b15107eb1d5bf4232e80fc26f820d132a..c8b786923df249bcdb4f51339e7ab74737381a7a 100644
--- a/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp
+++ b/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp
@@ -50,26 +50,51 @@ buildControllerGui( NodeBasedRenderer* renderer, const std::function<void()>& ap
         false );
     controlPanel->endLayout( true );
 
+    // TODO : add a double slider to get the good value. ask @dlyr for its doubleSliderClass ...
+    controlPanel->beginLayout( QBoxLayout::LeftToRight );
+    auto splatSizeCtrl = [&controller]( double v ) { controller.setSplatSize( v ); };
+    controlPanel->addPowerSliderInput(
+        "Splat size", splatSizeCtrl, controller.getSplatSize(), 0, 5 );
+    controlPanel->endLayout( true );
+
     controlPanel->beginLayout( QBoxLayout::LeftToRight );
     controlPanel->beginLayout( QBoxLayout::TopToBottom );
 
     //    auto visualizationFunction = controller.getAttribToColorFunc();
 
-    auto getAttribCode = [&controller]() { return controller.getAttribToColorFunc().first; };
-    auto getColorCode  = [&controller]() { return controller.getAttribToColorFunc().second; };
+    auto getAttribCode = [&controller]() {
+        auto [vs, gs, fs] = controller.getAttribToColorFunc();
+        return vs;
+    };
+    auto getColorCode = [&controller]() {
+        auto [vs, gs, fs] = controller.getAttribToColorFunc();
+        return fs;
+    };
+    auto getGeometryCode = [&controller]() {
+        auto [vs, gs, fs] = controller.getAttribToColorFunc();
+        return gs;
+    };
 
     controlPanel->addCodeEditor(
         "Edit attribute function",
-        [&controller, getColorCode, appUpdateCallback]( const std::string& s ) {
-            controller.setAttribToColorFunc( s, getColorCode() );
+        [&controller, getColorCode, getGeometryCode, appUpdateCallback]( const std::string& s ) {
+            controller.setAttribToColorFunc( s, getGeometryCode(), getColorCode() );
             appUpdateCallback();
         },
         getAttribCode );
 
+    controlPanel->addCodeEditor(
+        "Edit Geometry function",
+        [&controller, getAttribCode, getColorCode, appUpdateCallback]( const std::string& s ) {
+            controller.setAttribToColorFunc( getAttribCode(), s, getColorCode() );
+            appUpdateCallback();
+        },
+        getGeometryCode );
+
     controlPanel->addCodeEditor(
         "Edit Color function",
-        [&controller, getAttribCode, appUpdateCallback]( const std::string& s ) {
-            controller.setAttribToColorFunc( getAttribCode(), s );
+        [&controller, getAttribCode, getGeometryCode, appUpdateCallback]( const std::string& s ) {
+            controller.setAttribToColorFunc( getAttribCode(), getGeometryCode(), s );
             appUpdateCallback();
         },
         getColorCode );
@@ -77,27 +102,41 @@ buildControllerGui( NodeBasedRenderer* renderer, const std::function<void()>& ap
 
     controlPanel->beginLayout( QBoxLayout::TopToBottom );
     auto loadAttribFuncClbk =
-        [&controller, getColorCode, appUpdateCallback]( const std::string& file ) {
+        [&controller, getColorCode, getGeometryCode, appUpdateCallback]( const std::string& file ) {
             if ( file.empty() ) { return; }
-            std::cout << "Loading attrib function from file " << file << std::endl;
+            std::cout << "Loading vertex attribute function from file " << file << std::endl;
             std::ifstream inFile( file );
             std::stringstream strStream;
             strStream << inFile.rdbuf(); // read the file
-            controller.setAttribToColorFunc( strStream.str(), getColorCode() );
+            controller.setAttribToColorFunc( strStream.str(), getGeometryCode(), getColorCode() );
             appUpdateCallback();
         };
-    auto loadColorFuncClbk =
-        [&controller, getAttribCode, appUpdateCallback]( const std::string& file ) {
+
+    auto loadGeomFuncClbk =
+        [&controller, getAttribCode, getColorCode, appUpdateCallback]( const std::string& file ) {
             if ( file.empty() ) { return; }
-            std::cout << "Loading color function from file " << file << std::endl;
+            std::cout << "Loading geometry attribute function from file " << file << std::endl;
             std::ifstream inFile( file );
             std::stringstream strStream;
             strStream << inFile.rdbuf(); // read the file
-            controller.setAttribToColorFunc( getAttribCode(), strStream.str() );
+            controller.setAttribToColorFunc( getAttribCode(), strStream.str(), getColorCode() );
             appUpdateCallback();
         };
+
+    auto loadColorFuncClbk = [&controller, getAttribCode, getGeometryCode, appUpdateCallback](
+                                 const std::string& file ) {
+        if ( file.empty() ) { return; }
+        std::cout << "Loading color function from file " << file << std::endl;
+        std::ifstream inFile( file );
+        std::stringstream strStream;
+        strStream << inFile.rdbuf(); // read the file
+        controller.setAttribToColorFunc( getAttribCode(), getGeometryCode(), strStream.str() );
+        appUpdateCallback();
+    };
     controlPanel->addFileInput(
-        "Load attribute func", loadAttribFuncClbk, "./", "Shaders (*.glsl)" );
+        "Load vertex attribute func", loadAttribFuncClbk, "./", "Shaders (*.glsl)" );
+    controlPanel->addFileInput(
+        "Load geometry attribute func", loadGeomFuncClbk, "./", "Shaders (*.glsl)" );
     controlPanel->addFileInput( "Load color func", loadColorFuncClbk, "./", "Shaders (*.glsl)" );
     controlPanel->endLayout( false );
 
@@ -106,12 +145,18 @@ buildControllerGui( NodeBasedRenderer* renderer, const std::function<void()>& ap
         std::ofstream outFile( file );
         outFile << getAttribCode();
     };
+    auto saveGeomFuncClbk = [getGeometryCode, appUpdateCallback]( const std::string& file ) {
+        std::ofstream outFile( file );
+        outFile << getGeometryCode();
+    };
     auto saveColorFuncClbk = [getColorCode, appUpdateCallback]( const std::string& file ) {
         std::ofstream outFile( file );
         outFile << getColorCode();
     };
     controlPanel->addFileOuput(
-        "Save attribute func", saveAttribFuncClbk, "./", "Shaders (*.glsl)" );
+        "Save vertex attribute func", saveAttribFuncClbk, "./", "Shaders (*.glsl)" );
+    controlPanel->addFileOuput(
+        "Save geometry attribute func", saveGeomFuncClbk, "./", "Shaders (*.glsl)" );
     controlPanel->addFileOuput( "Save color func", saveColorFuncClbk, "./", "Shaders (*.glsl)" );
     controlPanel->endLayout( false );
 
diff --git a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp
index d85a293553b25b4191199de1bcff6df55d4f0b02..2ebbe4e4f1f81083f291c7830c998908e8f150ae 100644
--- a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp
+++ b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp
@@ -8,15 +8,42 @@ using namespace Ra::Core::Utils; // log
 #include <Engine/Data/Material.hpp>
 #include <Engine/Data/ShaderConfigFactory.hpp>
 #include <Engine/Data/ShaderProgramManager.hpp>
-#include <Engine/Data/Texture.hpp>
 #include <Engine/Rendering/RenderObject.hpp>
 #include <Engine/Scene/LightManager.hpp>
 
+// TODO for point cloud. Removed from here when it is no more needed.
+#include <Engine/Scene/GeometryComponent.hpp>
+
 #include <globjects/Framebuffer.h>
 
 namespace RadiumNBR {
 using namespace gl;
 
+/* Test Point cloud parameter provider */
+/*
+ * WARNING : this class is here only for testing and experimentation purpose.
+ * It will be replace soon by a better management of the way components could add specific
+ * properties to a rendertechnique
+ * TODO : see PR Draft and gist subShaderBlob
+ */
+class PointCloudParameterProvider : public Ra::Engine::Data::ShaderParameterProvider
+{
+  public:
+    PointCloudParameterProvider( std::shared_ptr<Ra::Engine::Data::Material> mat,
+                                 Ra::Engine::Scene::PointCloudComponent* pointCloud ) :
+        ShaderParameterProvider(), m_displayMaterial( mat ), m_component( pointCloud ) {}
+    ~PointCloudParameterProvider() override = default;
+    void updateGL() override {
+        m_displayMaterial->updateGL();
+        m_renderParameters = m_displayMaterial->getParameters();
+        m_renderParameters.addParameter( "pointCloudSplatRadius", m_component->getSplatSize() );
+    }
+
+  private:
+    std::shared_ptr<Ra::Engine::Data::Material> m_displayMaterial;
+    Ra::Engine::Scene::PointCloudComponent* m_component;
+};
+
 static const GLenum buffers[] = {GL_COLOR_ATTACHMENT0};
 
 CustomAttribToColorPass::CustomAttribToColorPass(
@@ -75,20 +102,17 @@ void CustomAttribToColorPass::resize( size_t width, size_t height ) {
 
 void CustomAttribToColorPass::execute(
     const Ra::Engine::Data::ViewingParameters& viewParams ) const {
-
+    static constexpr const float clearDepth{1.0f};
     m_fbo->bind();
     // only draw into 1 buffers (Color)
     GL_ASSERT( glDrawBuffers( 1, buffers ) );
-    GL_ASSERT( glDepthMask( GL_FALSE ) );
+    GL_ASSERT( glDepthMask( GL_TRUE ) );
     GL_ASSERT( glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ) );
-
     GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
     GL_ASSERT( glDepthFunc( GL_LEQUAL ) );
-    GL_ASSERT( glEnable( GL_BLEND ) );
+    GL_ASSERT( glDisable( GL_BLEND ) );
 
-    glBlendFunc( GL_ONE, GL_ONE );
-    // To prevent z-fighting, remove polygon offset
-    glDisable( GL_POLYGON_OFFSET_FILL );
+    glClearBufferfv( GL_DEPTH, 0, &clearDepth );
 
     if ( m_lightmanager->count() > 0 )
     {
@@ -106,17 +130,12 @@ void CustomAttribToColorPass::execute(
             }
         }
     }
-    // need to maintain global state invariant
-    glEnable( GL_POLYGON_OFFSET_FILL );
-
-    GL_ASSERT( glDisable( GL_BLEND ) );
 }
 
 bool CustomAttribToColorPass::buildRenderTechnique(
     const Ra::Engine::Rendering::RenderObject* ro,
     Ra::Engine::Rendering::RenderTechnique& rt ) const {
 
-    std::string resourcesRootDir = getResourcesDir();
     auto mat = const_cast<Ra::Engine::Rendering::RenderObject*>( ro )->getMaterial();
     // Volumes are not allowed here
     if ( mat->getMaterialAspect() == Ra::Engine::Data::Material::MaterialAspect::MAT_DENSITY )
@@ -125,11 +144,15 @@ bool CustomAttribToColorPass::buildRenderTechnique(
     if ( m_needConfigRebuild )
     {
         Ra::Engine::Data::ShaderConfigurationFactory::removeConfiguration(
-            {"CustomAtt2ClrPass::CustomColorProgram" + mat->getMaterialName()} );
+            {"CustomAtt2ClrPass::CustomColorProgram" + ro->getName()} );
     }
     if ( auto cfg = Ra::Engine::Data::ShaderConfigurationFactory::getConfiguration(
-             {"CustomAtt2ClrPass::CustomColorProgram" + mat->getMaterialName()} ) )
-    { rt.setConfiguration( *cfg, passIndex() ); }
+             {"CustomAtt2ClrPass::CustomColorProgram" + ro->getName()} ) )
+    {
+        rt.setConfiguration( *cfg, passIndex() );
+        // TODO : warning, the param provider might be erroneous
+        rt.setParametersProvider( mat, passIndex() );
+    }
     else
     {
         // This part is the default configuration for this pass
@@ -212,26 +235,117 @@ bool CustomAttribToColorPass::buildRenderTechnique(
             "}\n"};
 
         Ra::Engine::Data::ShaderConfiguration theConfig{"CustomAtt2ClrPass::CustomColorProgram" +
-                                                        mat->getMaterialName()};
+                                                        ro->getName()};
         theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_VERTEX,
                                    vertexShaderSource + m_customVertexAttrib );
         theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT,
                                    fragmentShadersource + m_customFragmentColor );
         theConfig.addInclude( "\"" + mat->getMaterialName() + ".glsl\"",
                               Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT );
+
+        std::shared_ptr<Ra::Engine::Data::ShaderParameterProvider> paramProvider = mat;
+
+        /*
+         * WARNING : this way of managing specific geometries is here only for testing and
+         * experimentation purpose. It will be replace soon by a better management of the way
+         * components could add specific properties to a render technique
+         * TODO : see PR Draft and gist subShaderBlob
+         */
+        const std::string geometryShadersource{
+            "#include \"DefaultLight.glsl\"\n"
+            "#include \"TransformStructs.glsl\"\n"
+            "in gl_PerVertex {\n"
+            "    vec4 gl_Position;\n"
+            "   float gl_PointSize;\n"
+            "    float gl_ClipDistance[];\n"
+            "}\n"
+            "gl_in[];\n"
+            "out gl_PerVertex {\n"
+            "    vec4 gl_Position;\n"
+            "    float gl_PointSize;\n"
+            "    float gl_ClipDistance[];\n"
+            "};\n"
+            "layout( points ) in;\n"
+            "layout( triangle_strip, max_vertices = 4 ) out;\n"
+            "layout( location = 0 ) in vec3 in_position[];\n"
+            "layout( location = 1 ) in vec3 in_normal[];\n"
+            "layout( location = 2 ) in vec3 in_texcoord[];\n"
+            "layout( location = 3 ) in vec3 in_vertexColor[];\n"
+            "layout( location = 4 ) in vec3 in_tangent[];\n"
+            "layout( location = 5 ) in vec3 in_viewVector[];\n"
+            "layout( location = 6 ) in vec3 in_lightVector[];\n"
+            "uniform Transform transform;\n"
+            "uniform float pointCloudSplatRadius;\n"
+            "layout( location = 0 ) out vec3 out_position;\n"
+            "layout( location = 1 ) out vec3 out_normal;\n"
+            "layout( location = 2 ) out vec3 out_texcoord;\n"
+            "layout( location = 3 ) out vec3 out_vertexcolor;\n"
+            "layout( location = 4 ) out vec3 out_tangent;\n"
+            "layout( location = 5 ) out vec3 out_viewVector;\n"
+            "layout( location = 6 ) out vec3 out_lightVector;\n"
+            "void propagateAttributes();\n"
+            "void main() {\n"
+                "vec3 eye = -transform.view[3].xyz * mat3( transform.view );\n"
+                "// if no normal is provided, splats are aligned with the screen plane\n"
+                "vec3 normal = in_normal[0];\n"
+                "if ( length( normal ) < 0.1 ) { normal = normalize( eye - in_position[0] ); }\n"
+                "// orthonormal basis {u, v, normal}\n"
+                "vec3 u = vec3( 1, 0, 0 );\n"
+                "if ( abs( normal.x ) > 1e-3 ) { u = normalize( vec3( -normal.z / normal.x, 0, 1 ) ); }\n"
+                "vec3 v = normalize( cross( normal, u ) );\n"
+                "vec3 point[4];\n"
+                "point[0] = in_position[0] - pointCloudSplatRadius * ( u + v );\n"
+                "point[1] = point[0] + pointCloudSplatRadius * u * 2;\n"
+                "point[2] = point[0] + pointCloudSplatRadius * v * 2;\n"
+                "point[3] = point[0] + pointCloudSplatRadius * ( u + v ) * 2;\n"
+                "vec2 uv[4];\n"
+                "uv[0] = vec2( -1, -1 );\n"
+                "uv[1] = vec2( -1, +1 );\n"
+                "uv[2] = vec2( +1, -1 );\n"
+                "uv[3] = vec2( +1, +1 );\n"
+                "for ( int idx = 0; idx < 4; ++idx ) {\n"
+                "    gl_Position     = transform.proj * transform.view * vec4( point[idx], 1 );\n"
+                "    out_position    = point[idx];\n"
+                "    out_texcoord    = vec3( uv[idx], 0. );\n"
+                "    out_normal      = normal;\n"
+                "    out_tangent     = in_tangent[0];\n"
+                "    out_viewVector  = in_viewVector[0];\n"
+                "    out_lightVector = in_lightVector[0];\n"
+                "    out_vertexcolor = in_vertexColor[0];\n"
+                "    propagateAttributes();"
+                "    EmitVertex();\n"
+                "}\n"
+               "EndPrimitive();\n"
+            "}\n"
+        };
+
+        auto pointCloudConst =
+            dynamic_cast<const Ra::Engine::Scene::PointCloudComponent*>( ro->getComponent() );
+        auto pointCloud = const_cast<Ra::Engine::Scene::PointCloudComponent*>( pointCloudConst );
+        if ( pointCloud )
+        {
+            theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_GEOMETRY,
+                                       geometryShadersource + m_customGeometryAttrib );
+            // construct the parameter provider for the technique
+            paramProvider = std::make_shared<PointCloudParameterProvider>( mat, pointCloud );
+            pointCloud->setSplatSize(0.025);
+        }
         // Add to the ShaderConfigManager
         Ra::Engine::Data::ShaderConfigurationFactory::addConfiguration( theConfig );
         // Add to the RenderTechnique
         rt.setConfiguration( theConfig, passIndex() );
+        rt.setParametersProvider( paramProvider, passIndex() );
     }
-    rt.setParametersProvider( mat, passIndex() );
+
     return true;
 }
 
 void CustomAttribToColorPass::setAttribToColorFunc( const std::string& vertex_source,
+                                                    const std::string& geometry_source,
                                                     const std::string& fragment_source ) {
     m_customVertexAttrib  = vertex_source;
     m_customFragmentColor = fragment_source;
+    m_customGeometryAttrib = geometry_source;
     rebuildShaders();
 }
 
@@ -248,4 +362,15 @@ void CustomAttribToColorPass::rebuildShaders() {
     }
     m_needConfigRebuild = false;
 }
+
+void CustomAttribToColorPass::setSplatSize(float s) {
+    m_splatsSize = s;
+    for ( auto ro : *m_objectsToRender ) {
+        auto pointCloud =
+            dynamic_cast<Ra::Engine::Scene::PointCloudComponent*>( ro->getComponent() );
+        if ( pointCloud ) {
+            pointCloud->setSplatSize( m_splatsSize );
+        }
+    }
+}
 } // namespace RadiumNBR
diff --git a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp
index 37bdfe432c60ef320c9fd3911a445707598fac6b..343e952045b5d0cf1e97522943a37ff9617dc809 100644
--- a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp
+++ b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp
@@ -17,6 +17,8 @@ class Framebuffer;
 
 namespace RadiumNBR {
 /// Render pass that draws objects using a custom color computation function (in glsl)
+/// For now, this pass is dedicated to visualize only point cloud (and only one at a time here)
+/// and can't be mixed with any other pass except clear pass.
 class CustomAttribToColorPass : public RenderPass
 {
   public:
@@ -43,10 +45,17 @@ class CustomAttribToColorPass : public RenderPass
 
     /// Set the custom glsl function for attrib management (vertex) and colorcomputation (fragment)
     void setAttribToColorFunc( const std::string& vertex_source,
+                               const std::string& geometry_source,
                                const std::string& fragment_source );
 
     void rebuildShaders();
 
+    /// Set the splat size for pointclouds
+    inline float getSplatSize() { return m_splatsSize; }
+
+    // return the splatSize used for point clouds
+    void setSplatSize(float s);
+
   private:
     /// The framebuffer used to render this pass
     std::unique_ptr<globjects::Framebuffer> m_fbo{nullptr};
@@ -60,6 +69,10 @@ class CustomAttribToColorPass : public RenderPass
     /// The custom Attrib Vertex shader function
     std::string m_customVertexAttrib{"void outputCustomAttribs(){}\n"};
 
+    /// The custom Attrib Geometry shader function
+    /// Todo : find what is the gooe profile ...
+    std::string m_customGeometryAttrib{"void propagateAttributes(){}\n"};
+
     /// the custom FragmentColor shader function
     /// If not changed, compute the same expression (without ao) than the light stage
     std::string m_customFragmentColor{
@@ -74,5 +87,8 @@ class CustomAttribToColorPass : public RenderPass
 
     /// The light manager to use
     const Ra::Engine::Scene::LightManager* m_lightmanager;
+
+    /// The splats size
+    float m_splatsSize{0.025};
 };
 } // namespace RadiumNBR
diff --git a/src/libRender/RadiumNBR/Renderer/Visualization.cpp b/src/libRender/RadiumNBR/Renderer/Visualization.cpp
index d5049658ce1f103876ea2fe607c5f6ae9cd59b88..df101c6151b141bd2f3febae02df79ba77803391 100644
--- a/src/libRender/RadiumNBR/Renderer/Visualization.cpp
+++ b/src/libRender/RadiumNBR/Renderer/Visualization.cpp
@@ -44,21 +44,6 @@ void VisualizationController::configure( RadiumNBR::NodeBasedRenderer* renderer,
     }
     //! [Adding a clear-screen pass]
 
-    //! [Adding a Z-only pass]
-    {
-        // the z-only pass takes all the objects and draw them only on the shared depth buffer.
-        auto pass = std::make_shared<RadiumNBR::GeomPrePass>( renderer->allRenderObjects(), 1 );
-        // set the output to the shared depth texture
-        pass->setOutput( *depthtexture );
-        // configure access to shader/resources files and initialize the pass
-        pass->setResourcesDir( resourcesPath );
-        pass->initializePass( w, h, shaderManager );
-        // add the pass to the renderer and activate it
-        renderer->addPass( pass, pass->index() );
-        pass->activate();
-    }
-    //! [Adding a Z-only pass]
-
     //! [Adding a CustomAttribToColorPass pass]
     {
         // this pass draw all the objects using the custom color function,
@@ -70,7 +55,8 @@ void VisualizationController::configure( RadiumNBR::NodeBasedRenderer* renderer,
         m_customPass->setInputs( *depthtexture );
         m_customPass->setOutput( *colortexture );
         m_customPass->setLightManager( renderer->getLightManager() );
-        m_customPass->setAttribToColorFunc( m_vertexFunction, m_fragmentFunction );
+        m_customPass->setAttribToColorFunc(
+            m_vertexFunction, m_geometryFunction, m_fragmentFunction );
         // configure access to shader/resources files and initialize the pass
         m_customPass->setResourcesDir( resourcesPath );
         m_customPass->initializePass( w, h, shaderManager );
@@ -104,17 +90,32 @@ void VisualizationController::resize( int w, int h ){
 
 /// Set the custom glsl function for attrib management (vertex) and colorcomputation (fragment)
 void VisualizationController::setAttribToColorFunc( const std::string& vertex_source,
+                                                    const std::string& geometry_source,
                                                     const std::string& fragment_source ) {
     m_vertexFunction   = vertex_source;
+    m_geometryFunction = geometry_source;
     m_fragmentFunction = fragment_source;
     if ( m_customPass )
     {
-        m_customPass->setAttribToColorFunc( m_vertexFunction, m_fragmentFunction );
+        m_customPass->setAttribToColorFunc(
+            m_vertexFunction, m_geometryFunction, m_fragmentFunction );
         m_customPass->rebuildShaders();
     }
 }
 
-std::pair<std::string&, std::string&> VisualizationController::getAttribToColorFunc() {
-    return {m_vertexFunction, m_fragmentFunction};
+std::tuple<std::string&, std::string&, std::string&>
+VisualizationController::getAttribToColorFunc() {
+    return {m_vertexFunction, m_geometryFunction, m_fragmentFunction};
 }
+
+float VisualizationController::getSplatSize() {
+    if ( m_customPass )
+        return m_customPass->getSplatSize();
+    else
+    { return 0.025; }
+}
+void VisualizationController::setSplatSize( float s ) {
+    m_customPass->setSplatSize( s );
+};
+
 } // namespace RadiumNBR
diff --git a/src/libRender/RadiumNBR/Renderer/Visualization.hpp b/src/libRender/RadiumNBR/Renderer/Visualization.hpp
index 9df91aa533a773c29017b79d1eba8792774e12d5..bf1973c0ed8604110d95fb4b565813069414aee5 100644
--- a/src/libRender/RadiumNBR/Renderer/Visualization.hpp
+++ b/src/libRender/RadiumNBR/Renderer/Visualization.hpp
@@ -23,10 +23,11 @@ class NodeBasedRenderer_LIBRARY_API VisualizationController
 
     /// Set the custom glsl function for attrib management (vertex) and colorcomputation (fragment)
     void setAttribToColorFunc( const std::string& vertex_source,
+                               const std::string& geometry_source,
                                const std::string& fragment_source );
 
     /// Get the glsl functions
-    std::pair<std::string&, std::string&> getAttribToColorFunc();
+    std::tuple<std::string&, std::string&, std::string&> getAttribToColorFunc();
 
     /// activate or deactivate the gamma-correction on the computed color
     inline void enablePostProcess( bool b ) {
@@ -34,6 +35,9 @@ class NodeBasedRenderer_LIBRARY_API VisualizationController
         m_renderer->enablePostProcess( b );
     }
 
+    float getSplatSize();
+    void setSplatSize( float s );
+
   private:
     /// The custom pass if needed for modification
     std::shared_ptr<RadiumNBR::CustomAttribToColorPass> m_customPass;
@@ -42,9 +46,13 @@ class NodeBasedRenderer_LIBRARY_API VisualizationController
     std::shared_ptr<RadiumNBR::ClearPass> m_clearPass;
     ///
     std::string m_vertexFunction{"void outputCustomAttribs() {\n}\n"};
+    std::string m_geometryFunction{"void propagateAttributes(){}\n"};
     std::string m_fragmentFunction{
-        "vec4 computeCustomColor(Material mat, vec3 lightDir, "
-        "vec3 viewDir, vec3 normal_world) {\n return vec4(normal_world*0.5+0.5, 1);\n}\n"};
+        "vec4 computeCustomColor(Material mat, vec3 light_dir, vec3 view_dir) {\n"
+        "vec3 bsdf= evaluateBSDF(material, getPerVertexTexCoord(), light_dir, view_dir);\n"
+        "vec3 contribution    = lightContributionFrom(light, getWorldSpacePosition().xyz);\n"
+        "return vec4(bsdf * 3.141592 * contribution, 1.0);\n"
+        "}\n"};
 
     RadiumNBR::NodeBasedRenderer* m_renderer;