Browse Source

Matcaps (material captures aka environment maps) in Viewer (#1482)

* matcap from texture, default normal image matcap

* update grid_texture() to generate checkerboard texture, but without UVs

Co-authored-by: Jérémie Dumas <[email protected]>
Alec Jacobson 5 years ago
parent
commit
29b75796b2

+ 25 - 17
include/igl/opengl/MeshGL.cpp

@@ -220,27 +220,35 @@ R"(#version 150
   uniform float specular_exponent;
   uniform float specular_exponent;
   uniform float lighting_factor;
   uniform float lighting_factor;
   uniform float texture_factor;
   uniform float texture_factor;
+  uniform float matcap_factor;
   uniform float double_sided;
   uniform float double_sided;
   out vec4 outColor;
   out vec4 outColor;
   void main()
   void main()
   {
   {
-    vec3 Ia = La * vec3(Kai);    // ambient intensity
-
-    vec3 vector_to_light_eye = light_position_eye - position_eye;
-    vec3 direction_to_light_eye = normalize (vector_to_light_eye);
-    float dot_prod = dot (direction_to_light_eye, normalize(normal_eye));
-    float clamped_dot_prod = abs(max (dot_prod, -double_sided));
-    vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod;    // Diffuse intensity
-
-    vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye));
-    vec3 surface_to_viewer_eye = normalize (-position_eye);
-    float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);
-    dot_prod_specular = float(abs(dot_prod)==dot_prod) * abs(max (dot_prod_specular, -double_sided));
-    float specular_factor = pow (dot_prod_specular, specular_exponent);
-    vec3 Is = Ls * vec3(Ksi) * specular_factor;    // specular intensity
-    vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3);
-    outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;
-    if (fixed_color != vec4(0.0)) outColor = fixed_color;
+    if(matcap_factor == 1.0f)
+    {
+      vec2 uv = normalize(normal_eye).xy * 0.5 + 0.5;
+      outColor = texture(tex, uv);
+    }else
+    {
+      vec3 Ia = La * vec3(Kai);    // ambient intensity
+
+      vec3 vector_to_light_eye = light_position_eye - position_eye;
+      vec3 direction_to_light_eye = normalize (vector_to_light_eye);
+      float dot_prod = dot (direction_to_light_eye, normalize(normal_eye));
+      float clamped_dot_prod = abs(max (dot_prod, -double_sided));
+      vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod;    // Diffuse intensity
+
+      vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye));
+      vec3 surface_to_viewer_eye = normalize (-position_eye);
+      float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);
+      dot_prod_specular = float(abs(dot_prod)==dot_prod) * abs(max (dot_prod_specular, -double_sided));
+      float specular_factor = pow (dot_prod_specular, specular_exponent);
+      vec3 Is = Ls * vec3(Ksi) * specular_factor;    // specular intensity
+      vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3);
+      outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;
+      if (fixed_color != vec4(0.0)) outColor = fixed_color;
+    }
   }
   }
 )";
 )";
 
 

+ 3 - 0
include/igl/opengl/ViewerCore.cpp

@@ -172,6 +172,7 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
   GLint lighting_factori      = glGetUniformLocation(data.meshgl.shader_mesh,"lighting_factor");
   GLint lighting_factori      = glGetUniformLocation(data.meshgl.shader_mesh,"lighting_factor");
   GLint fixed_colori          = glGetUniformLocation(data.meshgl.shader_mesh,"fixed_color");
   GLint fixed_colori          = glGetUniformLocation(data.meshgl.shader_mesh,"fixed_color");
   GLint texture_factori       = glGetUniformLocation(data.meshgl.shader_mesh,"texture_factor");
   GLint texture_factori       = glGetUniformLocation(data.meshgl.shader_mesh,"texture_factor");
+  GLint matcap_factori        = glGetUniformLocation(data.meshgl.shader_mesh,"matcap_factor");
   GLint double_sidedi         = glGetUniformLocation(data.meshgl.shader_mesh,"double_sided");
   GLint double_sidedi         = glGetUniformLocation(data.meshgl.shader_mesh,"double_sided");
 
 
   glUniform1f(specular_exponenti, data.shininess);
   glUniform1f(specular_exponenti, data.shininess);
@@ -186,8 +187,10 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
     {
     {
       // Texture
       // Texture
       glUniform1f(texture_factori, is_set(data.show_texture) ? 1.0f : 0.0f);
       glUniform1f(texture_factori, is_set(data.show_texture) ? 1.0f : 0.0f);
+      glUniform1f(matcap_factori, is_set(data.use_matcap) ? 1.0f : 0.0f);
       glUniform1f(double_sidedi, data.double_sided ? 1.0f : 0.0f);
       glUniform1f(double_sidedi, data.double_sided ? 1.0f : 0.0f);
       data.meshgl.draw_mesh(true);
       data.meshgl.draw_mesh(true);
+      glUniform1f(matcap_factori, 0.0f);
       glUniform1f(texture_factori, 0.0f);
       glUniform1f(texture_factori, 0.0f);
     }
     }
 
 

+ 30 - 19
include/igl/opengl/ViewerData.cpp

@@ -32,6 +32,7 @@ IGL_INLINE igl::opengl::ViewerData::ViewerData()
   show_faceid       (false),
   show_faceid       (false),
   show_labels       (false),
   show_labels       (false),
   show_texture      (false),
   show_texture      (false),
+  use_matcap        (false),
   point_size(30),
   point_size(30),
   line_width(0.5f),
   line_width(0.5f),
   line_color(0,0,0,1),
   line_color(0,0,0,1),
@@ -80,6 +81,7 @@ IGL_INLINE void igl::opengl::ViewerData::set_mesh(
       Eigen::Vector3d(GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]),
       Eigen::Vector3d(GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]),
       Eigen::Vector3d(GOLD_SPECULAR[0], GOLD_SPECULAR[1], GOLD_SPECULAR[2]));
       Eigen::Vector3d(GOLD_SPECULAR[0], GOLD_SPECULAR[1], GOLD_SPECULAR[2]));
 
 
+    // Generates a checkerboard texture
     grid_texture();
     grid_texture();
   }
   }
   else
   else
@@ -133,6 +135,7 @@ IGL_INLINE void igl::opengl::ViewerData::copy_options(const ViewerCore &from, co
   to.set(show_overlay      , from.is_set(show_overlay)      );
   to.set(show_overlay      , from.is_set(show_overlay)      );
   to.set(show_overlay_depth, from.is_set(show_overlay_depth));
   to.set(show_overlay_depth, from.is_set(show_overlay_depth));
   to.set(show_texture      , from.is_set(show_texture)      );
   to.set(show_texture      , from.is_set(show_texture)      );
+  to.set(use_matcap        , from.is_set(use_matcap)        );
   to.set(show_faces        , from.is_set(show_faces)        );
   to.set(show_faces        , from.is_set(show_faces)        );
   to.set(show_lines        , from.is_set(show_lines)        );
   to.set(show_lines        , from.is_set(show_lines)        );
 }
 }
@@ -454,6 +457,7 @@ IGL_INLINE void igl::opengl::ViewerData::clear()
   double_sided = false;
   double_sided = false;
   invert_normals = false;
   invert_normals = false;
   show_texture = false;
   show_texture = false;
+  use_matcap = false;
 }
 }
 
 
 IGL_INLINE void igl::opengl::ViewerData::compute_normals()
 IGL_INLINE void igl::opengl::ViewerData::compute_normals()
@@ -508,25 +512,33 @@ IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
   dirty |= MeshGL::DIRTY_SPECULAR | MeshGL::DIRTY_DIFFUSE | MeshGL::DIRTY_AMBIENT;
   dirty |= MeshGL::DIRTY_SPECULAR | MeshGL::DIRTY_DIFFUSE | MeshGL::DIRTY_AMBIENT;
 }
 }
 
 
-IGL_INLINE void igl::opengl::ViewerData::grid_texture()
+IGL_INLINE void igl::opengl::ViewerData::normal_matcap()
 {
 {
-  // Don't do anything for an empty mesh
-  if(V.rows() == 0)
-  {
-    V_uv.resize(V.rows(),2);
-    return;
-  }
-  if (V_uv.rows() == 0)
-  {
-    V_uv = V.block(0, 0, V.rows(), 2);
-    V_uv.col(0) = V_uv.col(0).array() - V_uv.col(0).minCoeff();
-    V_uv.col(0) = V_uv.col(0).array() / V_uv.col(0).maxCoeff();
-    V_uv.col(1) = V_uv.col(1).array() - V_uv.col(1).minCoeff();
-    V_uv.col(1) = V_uv.col(1).array() / V_uv.col(1).maxCoeff();
-    V_uv = V_uv.array() * 10;
-    dirty |= MeshGL::DIRTY_TEXTURE;
+  const int size = 512;
+  texture_R.resize(size, size);
+  texture_G.resize(size, size);
+  texture_B.resize(size, size);
+  const Eigen::Vector3d navy(0.3,0.3,0.5);
+  static const auto clamp = [](double t){ return std::max(std::min(t,1.0),0.0);};
+  for(int i = 0;i<size;i++)
+  {
+    const double x = (double(i)/double(size-1)*2.-1.);
+    for(int j = 0;j<size;j++)
+    {
+      const double y = (double(j)/double(size-1)*2.-1.);
+      const double z = sqrt(1.0-std::min(x*x+y*y,1.0));
+      Eigen::Vector3d C = Eigen::Vector3d(x*0.5+0.5,y*0.5+0.5,z);
+      texture_R(i,j) = clamp(C(0))*255;
+      texture_G(i,j) = clamp(C(1))*255;
+      texture_B(i,j) = clamp(C(2))*255;
+    }
   }
   }
+  texture_A.setConstant(texture_R.rows(),texture_R.cols(),255);
+  dirty |= MeshGL::DIRTY_TEXTURE;
+}
 
 
+IGL_INLINE void igl::opengl::ViewerData::grid_texture()
+{
   unsigned size = 128;
   unsigned size = 128;
   unsigned size2 = size/2;
   unsigned size2 = size/2;
   texture_R.resize(size, size);
   texture_R.resize(size, size);
@@ -688,8 +700,7 @@ IGL_INLINE void igl::opengl::ViewerData::updateGL(
                 data.F_uv(i,j) : data.F(i,j)).cast<float>();
                 data.F_uv(i,j) : data.F(i,j)).cast<float>();
       }
       }
     }
     }
-  }
-  else
+  } else
   {
   {
     if (meshgl.dirty & MeshGL::DIRTY_POSITION)
     if (meshgl.dirty & MeshGL::DIRTY_POSITION)
     {
     {
@@ -729,7 +740,7 @@ IGL_INLINE void igl::opengl::ViewerData::updateGL(
         meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
         meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
     }
     }
 
 
-    if (meshgl.dirty & MeshGL::DIRTY_UV)
+    if( (meshgl.dirty & MeshGL::DIRTY_UV) && data.V_uv.rows()>0)
     {
     {
         meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
         meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
         for (unsigned i=0; i<data.F.rows();++i)
         for (unsigned i=0; i<data.F.rows();++i)

+ 5 - 1
include/igl/opengl/ViewerData.h

@@ -183,7 +183,10 @@ public:
     const Eigen::Vector4d& diffuse,
     const Eigen::Vector4d& diffuse,
     const Eigen::Vector4d& specular);
     const Eigen::Vector4d& specular);
 
 
-  // Generates a default grid texture
+  // Generate a normal image matcap
+  IGL_INLINE void normal_matcap();
+
+  // Generates a default grid texture (without uvs)
   IGL_INLINE void grid_texture();
   IGL_INLINE void grid_texture();
 
 
   // Copy visualization options from one viewport to another
   // Copy visualization options from one viewport to another
@@ -253,6 +256,7 @@ public:
   unsigned int show_overlay;
   unsigned int show_overlay;
   unsigned int show_overlay_depth;
   unsigned int show_overlay_depth;
   unsigned int show_texture;
   unsigned int show_texture;
+  unsigned int use_matcap;
   unsigned int show_faces;
   unsigned int show_faces;
   unsigned int show_lines;
   unsigned int show_lines;
   bool show_vertid; // shared across viewports for now
   bool show_vertid; // shared across viewports for now

+ 0 - 5
include/igl/opengl/glfw/Viewer.cpp

@@ -447,11 +447,6 @@ namespace glfw
                    Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
                    Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
                    Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
                    Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
 
 
-    // Alec: why?
-    if (data().V_uv.rows() == 0)
-    {
-      data().grid_texture();
-    }
     for(int i=0;i<core_list.size(); i++)
     for(int i=0;i<core_list.size(); i++)
         core_list[i].align_camera_center(data().V,data().F);
         core_list[i].align_camera_center(data().V,data().F);