Browse Source

Merge pull request #1371 from libigl/alecjacobson-dev

Phong color mapping for scalar field data, refactor tutorials
Alec Jacobson 6 years ago
parent
commit
05812f73a6

+ 52 - 0
include/igl/isolines_map.cpp

@@ -0,0 +1,52 @@
+#include "isolines_map.h"
+#include <iostream>
+
+template <
+  typename DerivedCM,
+  typename Derivediso_color,
+  typename DerivedICM
+  >
+IGL_INLINE void igl::isolines_map(
+  const Eigen::MatrixBase<DerivedCM> & CM, 
+  const Eigen::MatrixBase<Derivediso_color> & iso_color,
+  const int interval_thickness,
+  const int iso_thickness,
+  Eigen::PlainObjectBase<DerivedICM> & ICM)
+{
+  ICM.resize(CM.rows()*interval_thickness+(CM.rows()-1)*iso_thickness,3);
+  {
+    int k = 0;
+    for(int c = 0;c<CM.rows();c++)
+    {
+      for(int i = 0;i<interval_thickness;i++)
+      {
+        ICM.row(k++) = CM.row(c);
+      }
+      if(c+1 != CM.rows())
+      {
+        for(int i = 0;i<iso_thickness;i++)
+        {
+          ICM.row(k++) = iso_color;
+        }
+      }
+    }
+    assert(k == ICM.rows());
+  }
+}
+
+template <
+  typename DerivedCM,
+  typename DerivedICM
+  >
+IGL_INLINE void igl::isolines_map(
+  const Eigen::MatrixBase<DerivedCM> & CM, 
+  Eigen::PlainObjectBase<DerivedICM> & ICM)
+{
+  return isolines_map(
+    CM, Eigen::Matrix<typename DerivedCM::Scalar,1,3>(0,0,0), 10, 1, ICM);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::isolines_map<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif

+ 41 - 0
include/igl/isolines_map.h

@@ -0,0 +1,41 @@
+#ifndef IGL_ISOLINES_MAP_H
+#define IGL_ISOLINES_MAP_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+  // Inject a given colormap with evenly spaced isolines.
+  //
+  // Inputs:
+  //   CM  #CM by 3 list of colors
+  //   ico_color  1 by 3 isoline color
+  //   interval_thickness  number of times to repeat intervals (original colors)
+  //   iso_thickness  number of times to repeat isoline color (in between
+  //     intervals)
+  // Outputs:
+  //   ICM  #CM*interval_thickness + (#CM-1)*iso_thickness by 3 list of outputs
+  //     colors
+  template <
+    typename DerivedCM,
+    typename Derivediso_color,
+    typename DerivedICM >
+  IGL_INLINE void isolines_map(
+    const Eigen::MatrixBase<DerivedCM> & CM, 
+    const Eigen::MatrixBase<Derivediso_color> & iso_color,
+    const int interval_thickness,
+    const int iso_thickness,
+    Eigen::PlainObjectBase<DerivedICM> & ICM);
+  template <
+    typename DerivedCM,
+    typename DerivedICM>
+  IGL_INLINE void isolines_map(
+    const Eigen::MatrixBase<DerivedCM> & CM, 
+    Eigen::PlainObjectBase<DerivedICM> & ICM);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "isolines_map.cpp"
+#endif
+
+#endif

+ 10 - 4
include/igl/opengl/MeshGL.cpp

@@ -12,6 +12,12 @@
 #include "destroy_shader_program.h"
 #include <iostream>
 
+IGL_INLINE igl::opengl::MeshGL::MeshGL():
+  tex_filter(GL_LINEAR),
+  tex_wrap(GL_REPEAT)
+{
+}
+
 IGL_INLINE void igl::opengl::MeshGL::init_buffers()
 {
   // Mesh: Vertex Array Object & Buffer objects
@@ -88,10 +94,10 @@ IGL_INLINE void igl::opengl::MeshGL::bind_mesh()
   glBindTexture(GL_TEXTURE_2D, vbo_tex);
   if (dirty & MeshGL::DIRTY_TEXTURE)
   {
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex_wrap);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex_wrap);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data());
   }

+ 5 - 0
include/igl/opengl/MeshGL.h

@@ -24,6 +24,7 @@ class MeshGL
 {
 public:
   typedef unsigned int GLuint;
+  typedef unsigned int GLint;
 
   enum DirtyFlags
   {
@@ -82,6 +83,8 @@ public:
 
   int tex_u;
   int tex_v;
+  GLint tex_filter;
+  GLint tex_wrap;
   Eigen::Matrix<char,Eigen::Dynamic,1> tex;
 
   Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> F_vbo;
@@ -91,6 +94,8 @@ public:
   // Marks dirty buffers that need to be uploaded to OpenGL
   uint32_t dirty;
 
+  IGL_INLINE MeshGL();
+
   // Initialize shaders and buffers
   IGL_INLINE void init();
 

+ 46 - 3
include/igl/opengl/ViewerData.cpp

@@ -14,6 +14,9 @@
 #include "../parula.h"
 #include "../per_vertex_normals.h"
 
+// Really? Just for GL_NEAREST?
+#include "gl.h"
+
 #include <iostream>
 
 
@@ -138,11 +141,12 @@ IGL_INLINE void igl::opengl::ViewerData::set_colors(const Eigen::MatrixXd &C)
 {
   using namespace std;
   using namespace Eigen;
+  // This Gouraud coloring should be deprecated in favor of Phong coloring in
+  // set-data
   if(C.rows()>0 && C.cols() == 1)
   {
-    Eigen::MatrixXd C3;
-    igl::parula(C,true,C3);
-    return set_colors(C3);
+    assert(false && "deprecated: call set_data directly instead");
+    return set_data(C);
   }
   // Ambient color should be darker color
   const auto ambient = [](const MatrixXd & C)->MatrixXd
@@ -260,6 +264,44 @@ IGL_INLINE void igl::opengl::ViewerData::set_texture(
   dirty |= MeshGL::DIRTY_TEXTURE;
 }
 
+IGL_INLINE void igl::opengl::ViewerData::set_data(
+  const double caxis_min,
+  const double caxis_max,
+  const Eigen::VectorXd & D)
+{
+  if(!show_texture)
+  {
+    Eigen::MatrixXd CM;
+    igl::parula(Eigen::VectorXd::LinSpaced(21,0,1).eval(),false,CM);
+    set_colormap(CM);
+  } 
+  set_uv(((D.array()-caxis_min)/(caxis_max-caxis_min)).replicate(1,2));
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_data( const Eigen::VectorXd & D)
+{
+  const double caxis_min = D.minCoeff();
+  const double caxis_max = D.maxCoeff();
+  return set_data(caxis_min,caxis_max,D);
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_colormap(const Eigen::MatrixXd & CM)
+{
+  assert(CM.cols() == 3 && "colormap CM should have 3 columns");
+  // Convert to R,G,B textures
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic, Eigen::Dynamic> R =
+    (CM.col(0)*255.0).cast<unsigned char>();
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic, Eigen::Dynamic> G =
+    (CM.col(1)*255.0).cast<unsigned char>();
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic, Eigen::Dynamic> B = 
+    (CM.col(2)*255.0).cast<unsigned char>();
+  set_colors(Eigen::RowVector3d(1,1,1));
+  set_texture(R,G,B);
+  show_texture = true;
+  meshgl.tex_filter = GL_NEAREST;
+  meshgl.tex_wrap = GL_CLAMP_TO_EDGE;
+}
+
 IGL_INLINE void igl::opengl::ViewerData::set_points(
   const Eigen::MatrixXd& P,
   const Eigen::MatrixXd& C)
@@ -407,6 +449,7 @@ IGL_INLINE void igl::opengl::ViewerData::clear()
   labels_strings.clear();
 
   face_based = false;
+  show_texture = false;
 }
 
 IGL_INLINE void igl::opengl::ViewerData::compute_normals()

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

@@ -82,7 +82,6 @@ public:
     const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
     const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
     const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B);
-
   // Set the texture associated with the mesh.
   //
   // Inputs:
@@ -96,6 +95,26 @@ public:
     const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
     const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
     const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A);
+  // Set pseudo-colorable scalar data associated with the mesh.
+  //
+  // Inputs:
+  //   caxis_min  caxis minimum bound
+  //   caxis_max  caxis maximum bound
+  //   D  #V by 3 list of colors
+  //
+  // To-do: support #F by 1 per-face data
+  IGL_INLINE void set_data(
+    const double caxis_min, 
+    const double caxis_max, 
+    const Eigen::VectorXd & D);
+  // Use min(D) and max(D) to set caxis.
+  IGL_INLINE void set_data(const Eigen::VectorXd & D);
+  // Not to be confused with set_colors, this creates a _texture_ that will be
+  // referenced to pseudocolor according to the scalar field passed to set_data.
+  //
+  // Inputs:
+  //   CM  #CM by 3 list of colors
+  IGL_INLINE void set_colormap(const Eigen::MatrixXd & CM);
 
   // Sets points given a list of point vertices. In constrast to `add_points`
   // this will (purposefully) clober existing points.

+ 2 - 0
include/igl/projection_constraint.cpp

@@ -44,5 +44,7 @@ void igl::projection_constraint(
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // generated by autoexplicit.sh
+template void igl::projection_constraint<Eigen::Matrix<double, -1, 1, 0, 3, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 1, 0, 2, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&);
+// generated by autoexplicit.sh
 template void igl::projection_constraint<Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 1, 0, 2, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&);
 #endif

+ 3 - 0
include/igl/unproject_in_mesh.cpp

@@ -90,6 +90,9 @@ template < typename DerivedV, typename DerivedF, typename Derivedobj>
   return unproject_in_mesh(pos,model,proj,viewport,V,F,obj,hits);
 }
 #ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template int igl::unproject_in_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
 template int igl::unproject_in_mesh<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, std::function<void (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
 template int igl::unproject_in_mesh<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, std::function<void (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
 template int igl::unproject_in_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, std::function<void (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);

+ 4 - 0
include/igl/unproject_on_line.cpp

@@ -55,5 +55,9 @@ void igl::unproject_on_line(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::unproject_on_line<Eigen::Matrix<double, -1, 1, 0, 3, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+// generated by autoexplicit.sh
+template void igl::unproject_on_line<Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
 template void igl::unproject_on_line<Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::Matrix<double, 2, 1, 0, 2, 1>::Scalar&);
 #endif

+ 2 - 0
include/igl/unproject_on_plane.cpp

@@ -31,4 +31,6 @@ void igl::unproject_on_plane(
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::unproject_on_plane<Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 1, 4, 1, 1, 4>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 4, 1, 1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
 #endif

+ 4 - 6
tutorial/104_Colors/main.cpp

@@ -1,6 +1,5 @@
 #include <igl/readOFF.h>
 #include <igl/opengl/glfw/Viewer.h>
-#include <igl/jet.h>
 #include "tutorial_shared_path.h"
 
 Eigen::MatrixXd V;
@@ -16,11 +15,10 @@ int main(int argc, char *argv[])
   igl::opengl::glfw::Viewer viewer;
   viewer.data().set_mesh(V, F);
 
-  // Use the z coordinate as a scalar field over the surface
-  Eigen::VectorXd Z = V.col(2);
-
-  // Compute per-vertex colors
-  igl::jet(Z,true,C);
+  // Use the (normalized) vertex positions as colors
+  C = 
+    (V.rowwise()            - V.colwise().minCoeff()).array().rowwise()/
+    (V.colwise().maxCoeff() - V.colwise().minCoeff()).array();
 
   // Add per-vertex colors
   viewer.data().set_colors(C);

+ 1 - 6
tutorial/202_GaussianCurvature/main.cpp

@@ -3,7 +3,6 @@
 #include <igl/invert_diag.h>
 #include <igl/readOFF.h>
 #include <igl/opengl/glfw/Viewer.h>
-#include <igl/jet.h>
 #include "tutorial_shared_path.h"
 
 int main(int argc, char *argv[])
@@ -24,13 +23,9 @@ int main(int argc, char *argv[])
   // Divide by area to get integral average
   K = (Minv*K).eval();
 
-  // Compute pseudocolor
-  MatrixXd C;
-  igl::jet(K,true,C);
-
   // Plot the mesh with pseudocolors
   igl::opengl::glfw::Viewer viewer;
   viewer.data().set_mesh(V, F);
-  viewer.data().set_colors(C);
+  viewer.data().set_data(K);
   viewer.launch();
 }

+ 1 - 5
tutorial/203_CurvatureDirections/main.cpp

@@ -46,11 +46,7 @@ int main(int argc, char *argv[])
   igl::opengl::glfw::Viewer viewer;
   viewer.data().set_mesh(V, F);
 
-
-  // Compute pseudocolor
-  MatrixXd C;
-  igl::parula(H,true,C);
-  viewer.data().set_colors(C);
+  viewer.data().set_data(H);
 
   // Average edge length for sizing
   const double avg = igl::avg_edge_length(V,F);

+ 1 - 6
tutorial/204_Gradient/main.cpp

@@ -35,12 +35,7 @@ int main(int argc, char *argv[])
   igl::opengl::glfw::Viewer viewer;
   viewer.data().set_mesh(V, F);
 
-  // Compute pseudocolor for original function
-  MatrixXd C;
-  igl::jet(U,true,C);
-  // // Or for gradient magnitude
-  //igl::jet(GU_mag,true,C);
-  viewer.data().set_colors(C);
+  viewer.data().set_data(U);
 
   // Average edge length divided by average gradient (for scaling)
   const double max_size = igl::avg_edge_length(V,F) / GU_mag.mean();

+ 8 - 9
tutorial/206_GeodesicDistance/main.cpp

@@ -1,8 +1,9 @@
 #include <igl/readOBJ.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/exact_geodesic.h>
-#include <igl/colormap.h>
 #include <igl/unproject_onto_mesh.h>
+#include <igl/parula.h>
+#include <igl/isolines_map.h>
 #include <igl/PI.h>
 #include <iostream>
 #include "tutorial_shared_path.h"
@@ -29,15 +30,12 @@ int main(int argc, char *argv[])
     Eigen::VectorXd d;
     std::cout<<"Computing geodesic distance to vertex "<<vid<<"..."<<std::endl;
     igl::exact_geodesic(V,F,VS,FS,VT,FT,d);
-    const double strip_size = 0.05;
-    // The function should be 1 on each integer coordinate
-    d = (d/strip_size*igl::PI).array().sin().abs().eval();
-    // Compute per-vertex colors
-    Eigen::MatrixXd C;
-    igl::colormap(igl::COLOR_MAP_TYPE_INFERNO,d,false,C);
     // Plot the mesh
-    viewer.data().set_mesh(V, F);
-    viewer.data().set_colors(C);
+    Eigen::MatrixXd CM;
+    igl::parula(Eigen::VectorXd::LinSpaced(21,0,1).eval(),false,CM);
+    igl::isolines_map(Eigen::MatrixXd(CM),CM);
+    viewer.data().set_colormap(CM);
+    viewer.data().set_data(d);
   };
 
   // Plot a distance when a vertex is picked
@@ -68,6 +66,7 @@ int main(int argc, char *argv[])
     return false;
   };
   viewer.data().set_mesh(V,F);
+  viewer.data().show_lines = false;
 
   cout << "Click on mesh to define new source.\n" << std::endl;
   update_distance(0);

+ 1 - 5
tutorial/303_LaplaceEquation/main.cpp

@@ -60,14 +60,10 @@ int main(int argc, char *argv[])
   igl::min_quad_with_fixed_precompute((-L).eval(),b,Aeq,true,mqwf);
   igl::min_quad_with_fixed_solve(mqwf,B,bc,Beq,Z);
 
-  // Pseudo-color based on solution
-  MatrixXd C;
-  igl::jet(Z,true,C);
-
   // Plot the mesh with pseudocolors
   igl::opengl::glfw::Viewer viewer;
   viewer.data().set_mesh(V, F);
   viewer.data().show_lines = false;
-  viewer.data().set_colors(C);
+  viewer.data().set_data(Z);
   viewer.launch();
 }

+ 3 - 11
tutorial/304_LinearEqualityConstraints/main.cpp

@@ -61,30 +61,23 @@ int main(int argc, char *argv[])
   }
 
 
-  // Pseudo-color based on solution
-  struct Data{
-    MatrixXd C,C_const;
-  } data;
   // Use same color axes
   const double min_z = std::min(Z.minCoeff(),Z_const.minCoeff());
   const double max_z = std::max(Z.maxCoeff(),Z_const.maxCoeff());
-  igl::jet(      Z,min_z,max_z,data.C);
-  igl::jet(Z_const,min_z,max_z,data.C_const);
 
   // Plot the mesh with pseudocolors
   igl::opengl::glfw::Viewer viewer;
   viewer.data().set_mesh(V, F);
   viewer.data().show_lines = false;
-  viewer.data().set_colors(data.C);
+  viewer.data().set_data(min_z,max_z,Z);
 
   viewer.callback_key_down = 
-    [](igl::opengl::glfw::Viewer& viewer,unsigned char key,int mod)->bool
+    [&Z,&Z_const,&min_z,&max_z](igl::opengl::glfw::Viewer& viewer,unsigned char key,int mod)->bool
     {
       if(key == ' ')
       {
-        Data & data = *static_cast<Data*>(viewer.callback_key_down_data);
         static bool toggle = true;
-        viewer.data().set_colors(toggle?data.C_const:data.C);
+        viewer.data().set_data(min_z,max_z,toggle?Z_const:Z);
         toggle = !toggle;
         return true;
       }else
@@ -92,7 +85,6 @@ int main(int argc, char *argv[])
         return false;
       }
     };
-  viewer.callback_key_down_data = &data;
   cout<<
     "Press [space] to toggle between unconstrained and constrained."<<endl;
   viewer.launch();

+ 1 - 4
tutorial/305_QuadraticProgramming/main.cpp

@@ -20,10 +20,7 @@ void solve(igl::opengl::glfw::Viewer &viewer)
   igl::active_set_params as;
   as.max_iter = 8;
   igl::active_set(Q,B,b,bc,Aeq,Beq,Aieq,Bieq,lx,ux,as,Z);
-  // Pseudo-color based on solution
-  Eigen::MatrixXd C;
-  igl::jet(Z,0,1,C);
-  viewer.data().set_colors(C);
+  viewer.data().set_data(Z);
 }
 
 bool key_down(igl::opengl::glfw::Viewer &viewer, unsigned char key, int mod)

+ 5 - 6
tutorial/306_EigenDecomposition/main.cpp

@@ -52,20 +52,19 @@ int main(int argc, char * argv[])
         // Rescale eigen vectors for visualization
         VectorXd Z =
           bbd*0.5*U.col(c);
-        Eigen::MatrixXd C;
-        igl::parula(U.col(c).eval(),false,C);
-        c = (c+1)%U.cols();
         if(twod)
         {
           V.col(2) = Z;
+          viewer.data().set_mesh(V,F);
+          viewer.data().compute_normals();
         }
-        viewer.data().set_mesh(V,F);
-        viewer.data().compute_normals();
-        viewer.data().set_colors(C);
+        viewer.data().set_data(U.col(c).eval());
+        c = (c+1)%U.cols();
         return true;
       }
     }
   };
+  viewer.data().set_mesh(V,F);
   viewer.callback_key_down(viewer,' ',0);
   viewer.data().show_lines = false;
   std::cout<<

+ 3 - 10
tutorial/403_BoundedBiharmonicWeights/main.cpp

@@ -85,13 +85,6 @@ bool pre_draw(igl::opengl::glfw::Viewer & viewer)
   return false;
 }
 
-void set_color(igl::opengl::glfw::Viewer &viewer)
-{
-  Eigen::MatrixXd C;
-  igl::jet(W.col(selected).eval(),true,C);
-  viewer.data().set_colors(C);
-}
-
 bool key_down(igl::opengl::glfw::Viewer &viewer, unsigned char key, int mods)
 {
   switch(key)
@@ -102,12 +95,12 @@ bool key_down(igl::opengl::glfw::Viewer &viewer, unsigned char key, int mods)
     case '.':
       selected++;
       selected = std::min(std::max(selected,0),(int)W.cols()-1);
-      set_color(viewer);
+      viewer.data().set_data(W.col(selected));
       break;
     case ',':
       selected--;
       selected = std::min(std::max(selected,0),(int)W.cols()-1);
-      set_color(viewer);
+      viewer.data().set_data(W.col(selected));
       break;
   }
   return true;
@@ -162,7 +155,7 @@ int main(int argc, char *argv[])
   // Plot the mesh with pseudocolors
   igl::opengl::glfw::Viewer viewer;
   viewer.data().set_mesh(U, F);
-  set_color(viewer);
+  viewer.data().set_data(W.col(selected));
   viewer.data().set_edges(C,BE,sea_green);
   viewer.data().show_lines = false;
   viewer.data().show_overlay_depth = false;

+ 9 - 22
tutorial/602_Matlab/main.cpp

@@ -1,11 +1,14 @@
-#include <igl/jet.h>
+#include "tutorial_shared_path.h"
+
 #include <igl/readOFF.h>
 #include <igl/cotmatrix.h>
 #include <igl/matlab/matlabinterface.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <iostream>
 
-#include "tutorial_shared_path.h"
+// On mac you may need to issue something like:
+//
+//     PATH=$PATH:/Applications/MATLAB_R2019a.app/bin/ ./tutorial/602_Matlab_bin
 
 // Base mesh
 Eigen::MatrixXd V;
@@ -17,29 +20,13 @@ Engine* engine;
 // Eigenvectors of the laplacian
 Eigen::MatrixXd EV;
 
-void plotEV(igl::opengl::glfw::Viewer& viewer, int id)
-{
-  Eigen::VectorXd v = EV.col(id);
-  v = v.array() - v.minCoeff();
-  v = v.array() / v.maxCoeff();
-
-  // Map to colors using jet colorramp
-  Eigen::MatrixXd C(V.rows(),3);
-  for (unsigned i=0; i<V.rows(); ++i)
-  {
-    double r,g,b;
-    igl::jet(v(i),r,g,b);
-    C.row(i) << r,g,b;
-  }
-
-  viewer.data().set_colors(C);
-}
-
 // This function is called every time a keyboard button is pressed
 bool key_down(igl::opengl::glfw::Viewer& viewer, unsigned char key, int modifier)
 {
   if (key >= '1' && key <= '9')
-    plotEV(viewer,(key - '1') + 1);
+  {
+    viewer.data().set_data(EV.col((key - '1') + 1));
+  }
 
   return false;
 }
@@ -77,7 +64,7 @@ int main(int argc, char *argv[])
   viewer.data().set_mesh(V, F);
 
   // Plot the first non-trivial eigenvector
-  plotEV(viewer,1);
+  viewer.data().set_data(EV.col(1));
 
   // Launch the viewer
   viewer.launch();

+ 2 - 10
tutorial/704_SignedDistance/main.cpp

@@ -78,14 +78,8 @@ void update_visualization(igl::opengl::glfw::Viewer & viewer)
     // Bunny is a watertight mesh so use pseudonormal for signing
     signed_distance_pseudonormal(V_vis,V,F,tree,FN,VN,EN,EMAP,S_vis,I,C,N);
   }
-  // push to [0,1] range
-  S_vis.array() = 0.5*(S_vis.array()/max_distance)+0.5;
-  MatrixXd C_vis;
-  // color without normalizing
-  igl::parula(S_vis,false,C_vis);
 
-
-  const auto & append_mesh = [&C_vis,&F_vis,&V_vis](
+  const auto & append_mesh = [&F_vis,&V_vis](
     const Eigen::MatrixXd & V,
     const Eigen::MatrixXi & F,
     const RowVector3d & color)
@@ -94,8 +88,6 @@ void update_visualization(igl::opengl::glfw::Viewer & viewer)
     F_vis.bottomRows(F.rows()) = F.array()+V_vis.rows();
     V_vis.conservativeResize(V_vis.rows()+V.rows(),3);
     V_vis.bottomRows(V.rows()) = V;
-    C_vis.conservativeResize(C_vis.rows()+V.rows(),3);
-    C_vis.bottomRows(V.rows()).rowwise() = color;
   };
   if(overlay)
   {
@@ -103,7 +95,7 @@ void update_visualization(igl::opengl::glfw::Viewer & viewer)
   }
   viewer.data().clear();
   viewer.data().set_mesh(V_vis,F_vis);
-  viewer.data().set_colors(C_vis);
+  viewer.data().set_data(S_vis);
   viewer.core().lighting_factor = overlay;
 }
 

+ 9 - 13
tutorial/712_DataSmoothing/main.cpp

@@ -2,8 +2,8 @@
 #include <igl/hessian_energy.h>
 #include <igl/massmatrix.h>
 #include <igl/cotmatrix.h>
-#include <igl/jet.h>
-#include <igl/edges.h>
+#include <igl/isolines_map.h>
+#include <igl/parula.h>
 #include <igl/vertex_components.h>
 #include <igl/remove_unreferenced.h>
 #include <igl/opengl/glfw/Viewer.h>
@@ -18,7 +18,6 @@
 
 #include "tutorial_shared_path.h"
 
-#include <igl/isolines.h>
 
 
 int main(int argc, char * argv[])
@@ -27,12 +26,11 @@ int main(int argc, char * argv[])
 
     //Read our mesh
     Eigen::MatrixXd V;
-    Eigen::MatrixXi F, E;
+    Eigen::MatrixXi F;
     if(!igl::read_triangle_mesh(
         argc>1?argv[1]: TUTORIAL_SHARED_PATH "/beetle.off",V,F)) {
         std::cout << "Failed to load mesh." << std::endl;
     }
-    igl::edges(F,E);
 
     //Constructing an exact function to smooth
     Eigen::VectorXd zexact = V.block(0,2,V.rows(),1).array()
@@ -88,14 +86,7 @@ int main(int argc, char * argv[])
             default:
                 return false;
         }
-        Eigen::MatrixXd isoV;
-        Eigen::MatrixXi isoE;
-        if(key!='2')
-            igl::isolines(V, F, *z, 30, isoV, isoE);
-        viewer.data().set_edges(isoV,isoE,Eigen::RowVector3d(0,0,0));
-        Eigen::MatrixXd colors;
-        igl::jet(*z, true, colors);
-        viewer.data().set_colors(colors);
+        viewer.data().set_data(*z);
         return true;
     };
     std::cout << R"(Usage:
@@ -105,6 +96,11 @@ int main(int argc, char * argv[])
 4  Biharmonic smoothing (natural Hessian boundary)
 
 )";
+    Eigen::MatrixXd CM;
+    igl::parula(Eigen::VectorXd::LinSpaced(21,0,1).eval(),false,CM);
+    igl::isolines_map(Eigen::MatrixXd(CM),CM);
+    viewer.data().set_colormap(CM);
+    viewer.data().set_data(znoisy);
     viewer.launch();
 
     return 0;

+ 47 - 116
tutorial/716_HeatGeodesics/main.cpp

@@ -4,11 +4,28 @@
 #include <igl/heat_geodesics.h>
 #include <igl/unproject_onto_mesh.h>
 #include <igl/avg_edge_length.h>
+#include <igl/isolines_map.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/opengl/create_shader_program.h>
 #include <igl/opengl/destroy_shader_program.h>
 #include <iostream>
 
+void set_colormap(igl::opengl::glfw::Viewer & viewer)
+{
+  const int num_intervals = 30;
+  Eigen::MatrixXd CM(num_intervals,3);
+  // Colormap texture
+  for(int i = 0;i<num_intervals;i++)
+  {
+    double t = double(num_intervals - i - 1)/double(num_intervals-1);
+    CM(i,0) = std::max(std::min(2.0*t-0.0,1.0),0.0);
+    CM(i,1) = std::max(std::min(2.0*t-1.0,1.0),0.0);
+    CM(i,2) = std::max(std::min(6.0*t-5.0,1.0),0.0);
+  }
+  igl::isolines_map(Eigen::MatrixXd(CM),CM);
+  viewer.data().set_colormap(CM);
+}
+
 int main(int argc, char *argv[])
 {
   // Create the peak height field
@@ -29,8 +46,6 @@ int main(int argc, char *argv[])
   };
   precompute();
 
-  // Initialize white
-  Eigen::MatrixXd C = Eigen::MatrixXd::Constant(V.rows(),3,1);
   igl::opengl::glfw::Viewer viewer;
   bool down_on_mesh = false;
   const auto update = [&]()->bool
@@ -43,20 +58,33 @@ int main(int argc, char *argv[])
     if(igl::unproject_onto_mesh(Eigen::Vector2f(x,y), viewer.core().view,
       viewer.core().proj, viewer.core().viewport, V, F, fid, bc))
     {
-      // 3d position of hit
-      const Eigen::RowVector3d m3 =
-        V.row(F(fid,0))*bc(0) + V.row(F(fid,1))*bc(1) + V.row(F(fid,2))*bc(2);
-      int cid = 0;
-      Eigen::Vector3d(
-          (V.row(F(fid,0))-m3).squaredNorm(),
-          (V.row(F(fid,1))-m3).squaredNorm(),
-          (V.row(F(fid,2))-m3).squaredNorm()).minCoeff(&cid);
-      const int vid = F(fid,cid);
-      C.row(vid)<<1,0,0;
-      Eigen::VectorXd D = Eigen::VectorXd::Zero(data.Grad.cols());
-	  D(vid) = 1;
-      igl::heat_geodesics_solve(data,(Eigen::VectorXi(1,1)<<vid).finished(),D);
-      viewer.data().set_colors((D/D.maxCoeff()).replicate(1,3));
+      Eigen::VectorXd D;
+      // if big mesh, just use closest vertex. Otherwise, blend distances to
+      // vertices of face using barycentric coordinates.
+      if(F.rows()>100000)
+      {
+        // 3d position of hit
+        const Eigen::RowVector3d m3 =
+          V.row(F(fid,0))*bc(0) + V.row(F(fid,1))*bc(1) + V.row(F(fid,2))*bc(2);
+        int cid = 0;
+        Eigen::Vector3d(
+            (V.row(F(fid,0))-m3).squaredNorm(),
+            (V.row(F(fid,1))-m3).squaredNorm(),
+            (V.row(F(fid,2))-m3).squaredNorm()).minCoeff(&cid);
+        const int vid = F(fid,cid);
+        igl::heat_geodesics_solve(data,(Eigen::VectorXi(1,1)<<vid).finished(),D);
+      }else
+      {
+        D = Eigen::VectorXd::Zero(V.rows());
+        for(int cid = 0;cid<3;cid++)
+        {
+          const int vid = F(fid,cid);
+          Eigen::VectorXd Dc;
+          igl::heat_geodesics_solve(data,(Eigen::VectorXi(1,1)<<vid).finished(),Dc);
+          D += Dc*bc(cid);
+        }
+      }
+      viewer.data().set_data(D);
       return true;
     }
     return false;
@@ -122,106 +150,9 @@ int main(int argc, char *argv[])
 
   // Show mesh
   viewer.data().set_mesh(V, F);
-  viewer.data().set_colors(C);
+  viewer.data().set_data(Eigen::VectorXd::Zero(V.rows()));
+  set_colormap(viewer);
   viewer.data().show_lines = false;
-  viewer.launch_init(true,false);
-
-  viewer.data().meshgl.init();
-  igl::opengl::destroy_shader_program(viewer.data().meshgl.shader_mesh);
-
-  {
-    std::string mesh_vertex_shader_string =
-R"(#version 150
-uniform mat4 view;
-uniform mat4 proj;
-uniform mat4 normal_matrix;
-in vec3 position;
-in vec3 normal;
-out vec3 position_eye;
-out vec3 normal_eye;
-in vec4 Ka;
-in vec4 Kd;
-in vec4 Ks;
-in vec2 texcoord;
-out vec2 texcoordi;
-out vec4 Kai;
-out vec4 Kdi;
-out vec4 Ksi;
-
-void main()
-{
-  position_eye = vec3 (view * vec4 (position, 1.0));
-  normal_eye = vec3 (normal_matrix * vec4 (normal, 0.0));
-  normal_eye = normalize(normal_eye);
-  gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * vec4(position, 1.0);
-  Kai = Ka;
-  Kdi = Kd;
-  Ksi = Ks;
-  texcoordi = texcoord;
-})";
-
-    std::string mesh_fragment_shader_string =
-R"(#version 150
-uniform mat4 view;
-uniform mat4 proj;
-uniform vec4 fixed_color;
-in vec3 position_eye;
-in vec3 normal_eye;
-uniform vec3 light_position_eye;
-vec3 Ls = vec3 (1, 1, 1);
-vec3 Ld = vec3 (1, 1, 1);
-vec3 La = vec3 (1, 1, 1);
-in vec4 Ksi;
-in vec4 Kdi;
-in vec4 Kai;
-in vec2 texcoordi;
-uniform sampler2D tex;
-uniform float specular_exponent;
-uniform float lighting_factor;
-uniform float texture_factor;
-out vec4 outColor;
-void main()
-{
-vec3 Ia = La * vec3(Kai);    // ambient intensity
-float ni = 30.0; // number of intervals
-float t = 1.0-round(ni*Kdi.r)/ni; // quantize and reverse
-vec3 Kdiq = clamp(vec3(2.*t,2.*t-1.,6.*t-5.),0,1); // heat map
-
-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 = max (dot_prod, 0.0);
-vec3 Id = Ld * Kdiq * 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) * max (dot_prod_specular, 0.0);
-float specular_factor = pow (dot_prod_specular, specular_exponent);
-vec3 Kfi = 0.5*vec3(Ksi);
-vec3 Lf = Ls;
-float fresnel_exponent = 2*specular_exponent;
-float fresnel_factor = 0;
-{
-  float NE = max( 0., dot( normalize(normal_eye), surface_to_viewer_eye));
-  fresnel_factor = pow (max(sqrt(1. - NE*NE),0.0), fresnel_exponent);
-}
-vec3 Is = Ls * vec3(Ksi) * specular_factor;    // specular intensity
-vec3 If = Lf * vec3(Kfi) * fresnel_factor;     // fresnel intensity
-vec4 color = vec4(lighting_factor * (If + Is + Id) + Ia +
-  (1.0-lighting_factor) * Kdiq,(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;
-})";
-
-    igl::opengl::create_shader_program(
-      mesh_vertex_shader_string,
-      mesh_fragment_shader_string,
-      {},
-      viewer.data().meshgl.shader_mesh);
-  }
-
-  viewer.launch_rendering(true);
-  viewer.launch_shut();
+  viewer.launch();
 
 }