I would like to use the libigl viewer to display a 3d model and a point. The 3d model will remain unchanged at all time, but the point will move around. My current approach is basically:

  1. load the 3d model and point
  2. viewer.data().clear() to clear the viewer
  3. go to step 1 again

However, it's slow especially when the 3d model has a lot of vertices because it needs reload everything after each clear. Preferably, I want to either clear only that single point or move that point to a new coordinate. Is there a way to do that?

1 Answers

1
Alec Jacobson On Best Solutions

viewer.data().set_points(...) will clear just the point-related data and replace it with the input positions and color(s). The mesh will not be modified or cleared. So, no need to call viewer.data().clear() when just changing the points.

Here's a minimalish example based on the libigl-example-project:

#include <igl/opengl/glfw/Viewer.h>
int main(int argc, char *argv[])
{
  // Inline mesh of a cube
  const Eigen::MatrixXd V= (Eigen::MatrixXd(8,3)<< -1.0,-1.0,-1.0, -1.0,-1.0, 1.0, -1.0, 1.0,-1.0, -1.0, 1.0, 1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0, 1.0).finished();
  const Eigen::MatrixXi F = (Eigen::MatrixXi(12,3)<< 1,7,5, 1,3,7, 1,4,3, 1,2,4, 3,8,7, 3,4,8, 5,7,8, 5,8,6, 1,5,6, 1,6,2, 2,6,8, 2,8,4).finished().array()-1;
  igl::opengl::glfw::Viewer viewer;
  // Set mesh
  viewer.data().set_mesh(V, F);
  viewer.data().set_face_based(true);
  viewer.core().is_animating = true;
  // Initialize point
  Eigen::MatrixXd P = (Eigen::MatrixXd(1,3)<<1.42,0,0).finished();
  // function will be  called before every draw
  viewer.callback_pre_draw = [&](igl::opengl::glfw::Viewer & )->bool
  {
    // Create orbiting animation
    P = (1.42*(P+Eigen::RowVector3d(P(1),-P(0),P(2))*0.1).normalized()).eval();
    // update point location. no .clear() necessary
    viewer.data().set_points(P,Eigen::RowVector3d(1,1,1));
    return false;
  };
  viewer.launch();
}

animation of point in libigl viewer