iridescence icon indicating copy to clipboard operation
iridescence copied to clipboard

seperate intensity and color vertices?

Open VRichardJP opened this issue 11 months ago • 3 comments

I am developing a point painting extension module for GLIM which adds RGB colors to GLIM maps. To display the result, I could use the vert_color shader attribute, but unfortunately that attribute is already used to show map intensity. Thus, it is necessary to overwrite the vertex data whenever I want to change color from intensity-based to point color.

Currently, GLIM maps intensity to RGB colors using fixed table, and use that data for vert_color input. Maybe it could make sense to have the following approach instead:

  • use in vec4 vert_color for raw RGB colors
  • use in u8 vert_colormap_index and uniform vec3 colormap[256] for intensity base coloring

To render intensity, the host would only convert the value to a u8 index and pass the colormap as uniform parameter. The advantage of this appraoch is that colormaps could be changed on the fly without the need to re-upload the points data.

VRichardJP avatar Mar 17 '25 03:03 VRichardJP

Example PoC, where a vert_intensity is used in a new "colormap" mode. In order not to break existing code, I have kept the original add_intensity functions (which still write into the vert_color buffer), and simply added new add_intensity methods which don't take a colormap and use the new vert_intensity buffer:

diff --git a/data/shader/rainbow.vert b/data/shader/rainbow.vert
index f1bf380..9804c2c 100644
--- a/data/shader/rainbow.vert
+++ b/data/shader/rainbow.vert
@@ -20,6 +20,7 @@ uniform mat4 projection_matrix;
 // colormode = 1 : material_color
 // colormode = 2 : vert_color
 // colormode = 3 : texture_color
+// colormode = 4 : colormap
 uniform int color_mode;
 uniform vec4 material_color;
 uniform sampler2D colormap_sampler;
@@ -32,6 +33,7 @@ in vec3 vert_position;
 in vec4 vert_color;
 in vec2 vert_texcoord;
 in vec3 vert_normal;
+in float vert_intensity; // in range [0, 1]
 
 out vec4 frag_color;
 out vec2 frag_texcoord;
@@ -42,6 +44,10 @@ vec4 rainbow(vec3 position) {
     return texture(colormap_sampler, vec2(p, 0.0));
 }
 
+vec4 colormap(float intensity) {
+    return texture(colormap_sampler, vec2(intensity, 0.0));
+}
+
 void main() {
     vec4 world_position = model_matrix * vec4(vert_position, 1.0);
     vec3 frag_world_position = world_position.xyz;
@@ -64,6 +70,10 @@ void main() {
         case 3:
             frag_texcoord = vert_texcoord;
             break;
+
+        case 4:
+            frag_color = colormap(vert_intensity);
+            break;
     }
 
     if(normal_enabled) {
diff --git a/include/glk/pointcloud_buffer.hpp b/include/glk/pointcloud_buffer.hpp
index 92f1818..9145ddf 100644
--- a/include/glk/pointcloud_buffer.hpp
+++ b/include/glk/pointcloud_buffer.hpp
@@ -59,10 +59,15 @@ public:
   void add_intensity(glk::COLORMAP colormap, const std::vector<double>& intensities, float scale = 1.0f);
   void add_intensity(glk::COLORMAP colormap, const float* intensities, const int num_points, float scale = 1.0f);
   void add_intensity(glk::COLORMAP colormap, const double* intensities, const int num_points, float scale = 1.0f);
+  void add_intensity(const std::vector<float>& intensities, float scale = 1.0f);
+  void add_intensity(const std::vector<double>& intensities, float scale = 1.0f);
+  void add_intensity(const float* intensities, const int num_points, float scale = 1.0f);
+  void add_intensity(const double* intensities, const int num_points, float scale = 1.0f);
 
   void add_normals(const float* data, int stride, int num_points);
   void add_color(const float* data, int stride, int num_points);
   void add_intensity(glk::COLORMAP colormap, const float* data, int stride, int num_points, float scale = 1.0f);
+  void add_intensity_buffer(const float* data, int stride, int num_points);
   void add_buffer(const std::string& attribute_name, int dim, const float* data, int stride, int num_points);
 
   // Partial attribute update methods (User must ensure that stride and dim are matched with existing attribute)
diff --git a/include/guik/viewer/shader_setting.hpp b/include/guik/viewer/shader_setting.hpp
index b58ed00..885b07d 100644
--- a/include/guik/viewer/shader_setting.hpp
+++ b/include/guik/viewer/shader_setting.hpp
@@ -13,7 +13,7 @@
 namespace guik {
 
 struct ColorMode {
-  enum MODE { RAINBOW = 0, FLAT_COLOR = 1, VERTEX_COLOR = 2, TEXTURE_COLOR = 3 };
+  enum MODE { RAINBOW = 0, FLAT_COLOR = 1, VERTEX_COLOR = 2, TEXTURE_COLOR = 3, COLORMAP = 4 };
 };
 
 struct PointScaleMode {
diff --git a/src/glk/pointcloud_buffer.cpp b/src/glk/pointcloud_buffer.cpp
index 3e6904d..c3bff2e 100644
--- a/src/glk/pointcloud_buffer.cpp
+++ b/src/glk/pointcloud_buffer.cpp
@@ -89,6 +89,41 @@ void PointCloudBuffer::add_intensity(glk::COLORMAP colormap, const double* inten
   return add_intensity(colormap, intensities_, scale);
 }
 
+
+void PointCloudBuffer::add_intensity(const std::vector<float>& intensities, float scale) {
+  std::vector<float> intensities_;
+  intensities_.reserve(intensities.size());
+  std::transform(intensities.begin(), intensities.end(), std::back_inserter(intensities_),
+    [&](const auto intensity) { return scale * intensity; });
+
+    add_intensity_buffer(intensities_.data(), sizeof(float), intensities_.size());
+}
+
+void PointCloudBuffer::add_intensity(const std::vector<double>& intensities, float scale) {
+  std::vector<float> intensities_;
+  intensities_.reserve(intensities.size());
+  std::transform(intensities.begin(), intensities.end(), std::back_inserter(intensities_),
+    [&](const auto intensity) { return scale * intensity; });
+
+    add_intensity_buffer(intensities_.data(), sizeof(float), intensities_.size());
+}
+
+void PointCloudBuffer::add_intensity(const float* intensities, const int num_points, float scale) {
+  std::vector<float> intensities_(num_points);
+  for (int i = 0; i < num_points; ++i) {
+    intensities_[i] = scale * intensities[i];
+  }
+  add_intensity_buffer(intensities_.data(), sizeof(float), intensities_.size());
+}
+
+void PointCloudBuffer::add_intensity(const double* intensities, const int num_points, float scale) {
+  std::vector<float> intensities_(num_points);
+  for (int i = 0; i < num_points; ++i) {
+    intensities_[i] = scale * intensities[i];
+  }
+  add_intensity_buffer(intensities_.data(), sizeof(float), intensities_.size());
+}
+
 void PointCloudBuffer::add_color(const Eigen::Vector4f* colors, int num_points) {
   add_color(colors->data(), sizeof(float) * 4, num_points);
 }
@@ -116,6 +151,10 @@ void PointCloudBuffer::add_intensity(glk::COLORMAP colormap, const float* data,
   add_color(colors[0].data(), sizeof(Eigen::Vector4f), num_points);
 }
 
+void PointCloudBuffer::add_intensity_buffer(const float* data, int stride, int num_points) {
+  add_buffer("vert_intensity", 1, data, stride, num_points);
+}
+
 void PointCloudBuffer::add_buffer(const std::string& attribute_name, int dim, const float* data, int stride, int num_points) {
   assert(this->num_points == num_points);

Example integration:

diff --git a/src/glim/viewer/interactive_viewer.cpp b/src/glim/viewer/interactive_viewer.cpp
index ad3b3d7..50e35e3 100644
--- a/src/glim/viewer/interactive_viewer.cpp
+++ b/src/glim/viewer/interactive_viewer.cpp
@@ -464,21 +465,27 @@ void InteractiveViewer::update_viewer(bool force_render) {
     auto_z_range[1] = std::max(auto_z_range[1], submap_pose.translation().z());
 
     auto drawable = viewer->find_drawable("submap_" + std::to_string(submap->id));
-    if (drawable.first) {
-      drawable.first->add("model_matrix", submap_pose.matrix());
+    auto update_shader_settings = [&](auto& shader_setting) {
+      shader_setting.add("model_matrix", submap_pose.matrix());
 
       switch (color_mode) {
         case 0:
-          drawable.first->set_color_mode(guik::ColorMode::RAINBOW);
+          shader_setting.set_color_mode(guik::ColorMode::RAINBOW);
           break;
-        case 1:
-        case 3:
-          drawable.first->set_color_mode(guik::ColorMode::VERTEX_COLOR);
+        case 1: // intensity
+          shader_setting.set_color_mode(guik::ColorMode::COLORMAP);
           break;
         case 2:
-          drawable.first->set_color_mode(guik::ColorMode::FLAT_COLOR);
+          shader_setting.set_color_mode(guik::ColorMode::FLAT_COLOR);
+          break;
+        case 3: // color
+          shader_setting.set_color_mode(guik::ColorMode::VERTEX_COLOR);
           break;
       }
+    };
+
+    if (drawable.first && !force_render) {
+      update_shader_settings(*drawable.first);
     } else {
       const Eigen::Vector4f color = glk::colormap_categoricalf(glk::COLORMAP::TURBO, submap->session_id, 6);
 
@@ -487,7 +494,7 @@ void InteractiveViewer::update_viewer(bool force_render) {
 
       if (submap->frame->has_intensities()) {
         cloud_buffer
-          ->add_intensity(glk::COLORMAP::TURBO, submap->frame->intensities, submap->frame->size(), 1.0 / *std::max_element(submap->frame->intensities, submap->frame->intensities));
+          ->add_intensity(submap->frame->intensities, submap->frame->size(), 1.0 / *std::max_element(submap->frame->intensities, submap->frame->intensities + submap->frame->size()));
       }
 
       if (submap->frame->has_colors()) {
@@ -501,6 +508,8 @@ void InteractiveViewer::update_viewer(bool force_render) {
         shader_setting.add("dynamic_object", 0).make_transparent();
       }
 
+      update_shader_settings(shader_setting);
+
       viewer->update_drawable("submap_" + std::to_string(submap->id), cloud_buffer, shader_setting);
     }
 

In intensity mode: Image

In color mode: Image

VRichardJP avatar Mar 17 '25 06:03 VRichardJP

Sorry for the late response. I think it would be good to add the colormap mode to iridescence. Are you willing to open a PR?

koide3 avatar Apr 01 '25 01:04 koide3

No problem!

How would you suggest naming things? In my PoC implementation, I have added in float vert_intensity and a few PointCloudBuffer::add_intensity() methods, but the behavior of these new add_intensity methods is different from the already existing add_intensity methods:

  • new ones don't take a colormap and write data to vert_intensity
  • old ones take a colormap, convert intensity to color and write the color to vert_color

Having the same name for 2 different things feels a bit odd.

I feel with this change the existing add_intensity would be better renamed to something like add_color_from_intensity, or the functionality should be simply moved to a color_to_intensity helper. Obviously, this would mean breaking existing code. I don't know your policy regarding breaking changes.

Or do you have a suggestion of a better name than vert_intensity and add_intensity for this new functionality?

VRichardJP avatar Apr 01 '25 02:04 VRichardJP