فهرست منبع

flare eyes example working

Former-commit-id: 49c32ed512664cb6143d7e3ac0fa99d82a1f8400
Alec Jacobson (jalec 11 سال پیش
والد
کامیت
bd42504bec

+ 1 - 1
examples/flare-eyes/Makefile

@@ -48,5 +48,5 @@ obj/%.o: %.cpp %.h
 	g++ $(OPENMP) $(AFLAGS) $(CFLAGS) -c $< -o $@ $(INC)
 
 clean:
-	rm -f example.o
+	rm -f $(OBJ_FILES)
 	rm -f example

+ 65 - 28
examples/flare-eyes/example.cpp

@@ -22,6 +22,8 @@
 #include <igl/Camera.h>
 #include <igl/ReAntTweakBar.h>
 #include <igl/PI.h>
+#include <igl/render_to_tga.h>
+#include <igl/STR.h>
 #define IGL_HEADER_ONLY
 #include <igl/lens_flare.h>
 
@@ -34,6 +36,7 @@
 
 #include <string>
 #include <vector>
+#include <iomanip>
 #include <stack>
 #include <iostream>
 
@@ -43,8 +46,9 @@ double x=6,y=232,z=61;
 std::vector<igl::Flare> flares;
 std::vector<GLuint> shine_ids;
 std::vector<GLuint> flare_ids;
-int shine_tic;
+int shine_tic = 0;
 
+GLuint list_id = 0;
 Eigen::MatrixXd V,N;
 Eigen::VectorXd Vmid,Vmin,Vmax;
 double bbd = 1.0;
@@ -68,6 +72,8 @@ std::stack<State> redo_stack;
 bool is_rotating = false;
 int down_x,down_y;
 igl::Camera down_camera;
+bool render_to_png_on_next = false;
+int render_count = 0;
 
 int width,height;
 Eigen::Vector4f light_pos(-0.1,-0.1,0.9,0);
@@ -75,9 +81,12 @@ Eigen::Vector4f light_pos(-0.1,-0.1,0.9,0);
 #define REBAR_NAME "temp.rbr"
 igl::ReTwBar rebar;
 
-// No-op setter, does nothing
-void TW_CALL no_op(const void * /*value*/, void * /*clientData*/)
+void TW_CALL set_camera_rotation(const void * value, void *clientData)
 {
+  using namespace std;
+  // case current value to double
+  const double * quat = (const double *)(value);
+  std::copy(quat,quat+4,s.camera.rotation);
 }
 
 void TW_CALL get_camera_rotation(void * value, void *clientData)
@@ -181,12 +190,12 @@ void lights()
   glEnable(GL_LIGHT0);
   glEnable(GL_LIGHT1);
   float WHITE[4] =  {0.8,0.8,0.8,1.};
-  float GREY[4] =  {0.4,0.4,0.4,1.};
+  float GREY[4] =  {0.2,0.2,0.2,1.};
   float BLACK[4] =  {0.,0.,0.,1.};
   Vector4f pos = light_pos;
   glLightfv(GL_LIGHT0,GL_AMBIENT,GREY);
   glLightfv(GL_LIGHT0,GL_DIFFUSE,WHITE);
-  glLightfv(GL_LIGHT0,GL_SPECULAR,BLACK);
+  glLightfv(GL_LIGHT0,GL_SPECULAR,GREY);
   glLightfv(GL_LIGHT0,GL_POSITION,pos.data());
   pos(0) *= -1;
   pos(1) *= -1;
@@ -207,7 +216,8 @@ void draw_flare()
   using namespace Eigen;
   glPushMatrix();
   glScaled(bbd*0.5,bbd*0.5,bbd*0.5);
-  Vector3f light(0,0.1,0);
+  glScaled(0.2,0.2,0.2);
+  Vector3f light(0,0,0);
   lens_flare_draw(flares,shine_ids,flare_ids,light,1.0,shine_tic);
   glPopMatrix();
 }
@@ -282,7 +292,7 @@ void display()
 {
   using namespace igl;
   using namespace std;
-  glClearColor(0,0,0,0);
+  glClearColor(0.03,0.03,0.04,0);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
   glEnable(GL_DEPTH_TEST);
@@ -291,38 +301,60 @@ void display()
   glEnable(GL_NORMALIZE);
   lights();
   push_scene();
-  push_object();
 
-  // Set material properties
-  glDisable(GL_COLOR_MATERIAL);
-  const float NEAR_BLACK[4] = {0.1,0.1,0.1,1.0};
-  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  NEAR_BLACK);
-  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  MIDNIGHT_BLUE_DIFFUSE);
-  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, SILVER_SPECULAR);
-  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128);
 
   
-  draw_mesh(V,F,N);
+  if(list_id == 0)
+  {
+    list_id = glGenLists(1);
+    glNewList(list_id,GL_COMPILE);
+
+    push_object();
+    // Set material properties
+    glDisable(GL_COLOR_MATERIAL);
+    const float NEAR_BLACK[4] = {0.1,0.1,0.1,1.0};
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  NEAR_BLACK);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  MIDNIGHT_BLUE_DIFFUSE);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, SILVER_SPECULAR);
+    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128);
+    draw_mesh(V,F,N);
+    pop_object();
+    // Draw a nice floor
+    glPushMatrix();
+    const double floor_offset =
+      -2./bbd*(V.col(1).maxCoeff()-Vmid(1));
+    glTranslated(0,floor_offset,0);
+    const float GREY[4] = {0.5,0.5,0.6,1.0};
+    const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
+    draw_floor(GREY,DARK_GREY);
+    glPopMatrix();
+
+    glEndList();
+  }
+  glCallList(list_id);
+
+
+  push_object();
   if(eyes_visible)
   {
     draw_eyes();
   }
   pop_object();
 
-  // Draw a nice floor
-  glPushMatrix();
-  const double floor_offset =
-    -2./bbd*(V.col(1).maxCoeff()-Vmid(1));
-  glTranslated(0,floor_offset,0);
-  const float GREY[4] = {0.5,0.5,0.6,1.0};
-  const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
-  draw_floor(GREY,DARK_GREY);
-  glPopMatrix();
-
   pop_scene();
 
   report_gl_error();
 
+  if(render_to_png_on_next)
+  {
+    GLint viewport[4];
+    glGetIntegerv(GL_VIEWPORT,viewport);
+    render_to_tga(
+      STR("./"<< "flare-eyes-" << setw(4) << setfill('0') << render_count++ << ".tga"),
+      viewport[2],viewport[3],true);
+    //render_to_png_on_next = false;
+  }
+
   TwDraw();
   glutSwapBuffers();
   glutPostRedisplay();
@@ -658,7 +690,7 @@ int main(int argc, char * argv[])
   }
   // Create a tweak bar
   rebar.TwNewBar("TweakBar");
-  rebar.TwAddVarCB("camera_rotation", TW_TYPE_QUAT4D, no_op,get_camera_rotation, NULL, "open readonly=true");
+  rebar.TwAddVarCB("camera_rotation", TW_TYPE_QUAT4D, set_camera_rotation,get_camera_rotation, NULL, "open");
   TwEnumVal RotationTypesEV[NUM_ROTATION_TYPES] = 
   {
     {ROTATION_TYPE_IGL_TRACKBALL,"igl trackball"},
@@ -692,7 +724,12 @@ int main(int argc, char * argv[])
   const float RED[3] = {1,0,0};
   const float GREEN[3] = {0,1,0};
   const float BLUE[3] = {0,0,1};
-  lens_flare_create(RED,GREEN,BLUE,flares);
+  //lens_flare_create(RED,GREEN,BLUE,flares);
+  flares.resize(4);
+  flares[0] = Flare(-1, 1.0f, 1.*0.1f,  BLUE, 1.0);
+  flares[1] = Flare(-1, 1.0f, 1.*0.15f, GREEN, 1.0);
+  flares[2] = Flare(-1, 1.0f, 1.*0.35f, RED, 1.0);
+  flares[3] = Flare( 2, 1.0f, 1.*0.1f, RED, 0.4);
 
   glutMainLoop();
 

+ 3 - 2
examples/transparency/example.cpp

@@ -11,12 +11,13 @@
 #include <igl/trackball.h>
 #include <igl/report_gl_error.h>
 #include <igl/matlab_format.h>
-#include <igl/sort_triangles.h>
 #include <igl/colon.h>
 #include <igl/slice.h>
 #include <igl/report_gl_error.h>
 #include <igl/ReAntTweakBar.h>
 #include <igl/EPS.h>
+#define IGL_HEADER_ONLY
+#include <igl/sort_triangles.h>
 
 #ifdef __APPLE__
 #  include <GLUT/glut.h>
@@ -154,7 +155,7 @@ void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
       // sort!
       push_scene();
       push_object();
-      sort_triangles(V,F,sorted_F,I);
+      sort_triangles_robust(V,F,sorted_F,I);
       slice(N,I,1,sorted_N);
       init_C(I);
       pop_object();

+ 59 - 55
include/igl/lens_flare.cpp

@@ -6,6 +6,8 @@
 #include "shine_textures.h"
 #include "flare_textures.h"
 
+#include <iostream>
+
 // http://www.opengl.org/archives/resources/features/KilgardTechniques/LensFlare/glflare.c
 
 static void setup_texture(
@@ -55,6 +57,7 @@ void igl::lens_flare_create(
   std::vector<igl::Flare> & flares)
 {
   using namespace igl;
+  using namespace std;
   flares.resize(12);
   /* Shines */
   flares[0] = Flare(-1, 1.0f, 0.1f, C, 1.0);
@@ -81,79 +84,76 @@ void igl::lens_flare_draw(
   const float near_clip,
   int & shine_tic)
 {
-  bool ot2,ob,odt;
-  int obsa,obda;
-  ot2 = glIsEnabled(GL_TEXTURE_2D);
-  ob = glIsEnabled(GL_BLEND);
-  odt = glIsEnabled(GL_DEPTH_TEST);
+  bool ot2 = glIsEnabled(GL_TEXTURE_2D);
+  bool ob = glIsEnabled(GL_BLEND);
+  bool odt = glIsEnabled(GL_DEPTH_TEST);
+  bool ocm = glIsEnabled(GL_COLOR_MATERIAL);
+  bool ol = glIsEnabled(GL_LIGHTING);
+  int obsa,obda,odf,odwm;
   glGetIntegerv(GL_BLEND_SRC_ALPHA,&obsa);
   glGetIntegerv(GL_BLEND_DST_ALPHA,&obda);
+  glGetIntegerv(GL_DEPTH_FUNC,&odf);
+  glGetIntegerv(GL_DEPTH_WRITEMASK,&odwm);
 
+  glDisable(GL_COLOR_MATERIAL);
+  glEnable(GL_DEPTH_TEST);
+  //glDepthFunc(GL_LEQUAL);
+  glDepthMask(GL_FALSE);
   glEnable(GL_TEXTURE_2D);
-  glDisable(GL_DEPTH_TEST);
+  glDisable(GL_LIGHTING);
   glEnable(GL_BLEND);
   glBlendFunc(GL_ONE, GL_ONE);
 
   using namespace Eigen;
   using namespace igl;
-
-  // Assuming scene is pushed
-  Vector3f win_o,from,at;
-  project(Vector3f(0,0,0),win_o);
-  win_o(2) = -1e26;
-  unproject(win_o,from);
-  win_o(2) = 1;
-  unproject(win_o,at);
-
-  Vector3f view_dir, tmp, light0, light_dir, position, dx, dy,
-    center, axis, sx, sy;
-  GLfloat dot, global_scale = 1.0;
-  int i;
-
-  /* view_dir = normalize(at-from) */
-  view_dir =  at -  from;
-  view_dir.normalize();
-
-  /* center = from + near_clip * view_dir */
-  tmp =  near_clip* view_dir;
-  center =  from +  tmp;
-
-  /* light_dir = normalize(light-from) */
-  light_dir =  light -  from;
-  light_dir.normalize();
-
-  /* light0 = from + dot(light,view_dir)*near_clip*light_dir */
-  dot = light_dir.dot( view_dir);
-  tmp =  near_clip / dot* light_dir;
-  light0 =  from + light_dir;
-
-  /* axis = light - center */
-  axis =  light0 -  center;
-  dx =  axis;
-
-  /* dx = normalize(axis) */
-  dx.normalize();
-
-  /* dy = cross(dx,view_dir) */
-  dy =  dx.cross( view_dir);
-
-
-  for (i = 0; i < (int)flares.size(); i++)
+  using namespace std;
+
+  //// view_dir  direction from eye to position is is looking at
+  //const Vector3f view_dir =  (at - from).normalized();
+
+  //// near_clip  distance from eye to near clipping plane along view_dir
+  //// center   position on near clipping plane along viewdir from eye
+  //const Vector3f center =  from + near_clip*view_dir;
+
+  Vector3f plight = project(light);
+  // Orthogonal vectors to view direction at light
+  Vector3f psx = plight;
+  psx(0) += 1;
+  Vector3f psy = plight;
+  psy(1) += 1;
+
+  // axis toward center
+  int vp[4];
+  glGetIntegerv(GL_VIEWPORT,vp);
+  Vector3f center = unproject(Vector3f(0.5*vp[2],0.5*vp[3],plight[2]-1e-3));
+  //Vector3f center(0,0,1);
+  Vector3f axis = light-center;
+  glLineWidth(4.);
+  glColor3f(1,0,0);
+  glBegin(GL_LINES);
+  glVertex3fv(center.data());
+  glVertex3fv(light.data());
+  glEnd();
+
+  const Vector3f SX = unproject(psx).normalized();
+  const Vector3f SY = unproject(psy).normalized();
+
+  for(int i = 0; i < (int)flares.size(); i++)
   {
-    sx =  flares[i].scale * global_scale* dx;
-    sy =  flares[i].scale * global_scale* dy;
-
+    const Vector3f sx = flares[i].scale * SX;
+    const Vector3f sy = flares[i].scale * SY;
     glColor3fv(flares[i].color);
     if (flares[i].type < 0) {
       glBindTexture(GL_TEXTURE_2D, shine_ids[shine_tic]);
       shine_tic = (shine_tic + 1) % shine_ids.size();
-    } else {
+    } else 
+    {
       glBindTexture(GL_TEXTURE_2D, flare_ids[flares[i].type]);
     }
 
     /* position = center + flare[i].loc * axis */
-    tmp =  flares[i].loc* axis;
-    position =  center +  tmp;
+    const Vector3f position = center + flares[i].loc * axis;
+    Vector3f tmp;
 
     glBegin(GL_QUADS);
     glTexCoord2f(0.0, 0.0);
@@ -180,5 +180,9 @@ void igl::lens_flare_draw(
   ot2?glEnable(GL_TEXTURE_2D):glDisable(GL_TEXTURE_2D);
   ob?glEnable(GL_BLEND):glDisable(GL_BLEND);
   odt?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST);
+  ocm?glEnable(GL_COLOR_MATERIAL):glDisable(GL_COLOR_MATERIAL);
+  ol?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING);
   glBlendFunc(obsa,obda);
+  glDepthFunc(odf);
+  glDepthMask(odwm);
 }

+ 4 - 3
include/igl/matlab/MatlabWorkspace.h

@@ -1,12 +1,13 @@
 #ifndef IGL_WRITE_MATLAB_WORKSPACE
 #define IGL_WRITE_MATLAB_WORKSPACE
 
-#include <string>
-#include <vector>
 #include <Eigen/Dense>
 #include <Eigen/Sparse>
 
-#include "mat.h"
+#include <mat.h>
+
+#include <string>
+#include <vector>
 
 namespace igl
 {

+ 15 - 1
include/igl/project.cpp

@@ -60,7 +60,21 @@ IGL_INLINE int igl::project(
   igl::report_gl_error();
 #endif
 
-  return gluProject(objX,objY,objZ,MV,P,VP,winX,winY,winZ);
+#ifdef EXTREME_VERBOSE
+  cout<<"obj=["<<endl<<
+    objX<<" "<< objY<<" "<< objZ<<endl<<
+    "];"<<endl;
+#endif
+
+
+  int ret = gluProject(objX,objY,objZ,MV,P,VP,winX,winY,winZ);
+
+#ifdef EXTREME_VERBOSE
+  cout<<"win=["<<endl<<
+    *winX<<" "<< *winY<<" "<< *winZ<<endl<<
+    "];"<<endl;
+#endif
+  return ret;
 }
 
 template <typename Derivedobj, typename Derivedwin>

+ 409 - 0
include/igl/sort_triangles.cpp

@@ -146,8 +146,417 @@ void igl::sort_triangles_slow(
   slice(F,I,1,FF);
 }
 
+#include "EPS.h"
+#include <functional>
+#include <algorithm>
+
+static int tough_count = 0;
+template <typename Vec3>
+class Triangle
+{
+  public:
+    static inline bool z_comp(const Vec3 & A, const Vec3 & B)
+    {
+      return A(2) > B(2);
+    }
+   static typename Vec3::Scalar ZERO()
+   {
+     return igl::EPS<typename Vec3::Scalar>();
+     return 0;
+   }
+  public:
+    int id;
+    // Sorted projected coners: c[0] has smallest z value
+    Vec3 c[3];
+    Vec3 n;
+  public:
+    Triangle():id(-1) { };
+    Triangle(int id, const Vec3 c0, const Vec3 c1, const Vec3 c2):
+      id(id)
+    {
+      using namespace std;
+      c[0] = c0;
+      c[1] = c1;
+      c[2] = c2;
+      sort(c,c+3,Triangle<Vec3>::z_comp);
+      // normal pointed toward viewpoint
+      n = (c0-c1).cross(c2-c0);
+      if(n(2) < 0)
+      {
+        n *= -1.0;
+      }
+      // Avoid NaNs
+      typename Vec3::Scalar len = n.norm();
+      if(len == 0)
+      {
+        cout<<"avoid NaN"<<endl;
+        assert(false);
+        len = 1;
+      }
+      n /= len;
+    };
+
+    typename Vec3::Scalar project(const Vec3 & r) const
+    {
+      //return n.dot(r-c[2]);
+      int closest = -1;
+      typename Vec3::Scalar min_dist = 1e26;
+      for(int ci = 0;ci<3;ci++)
+      {
+        typename Vec3::Scalar dist = (c[ci]-r).norm();
+        if(dist < min_dist)
+        {
+          min_dist = dist;
+          closest = ci;
+        }
+      }
+      assert(closest>=0);
+      return n.dot(r-c[closest]);
+    }
+
+    // Z-values of this are < z-values of that
+    bool is_completely_behind(const Triangle & that) const
+    {
+      const typename Vec3::Scalar ac0 = that.c[0](2);
+      const typename Vec3::Scalar ac1 = that.c[1](2);
+      const typename Vec3::Scalar ac2 = that.c[2](2);
+      const typename Vec3::Scalar ic0 = this->c[0](2);
+      const typename Vec3::Scalar ic1 = this->c[1](2);
+      const typename Vec3::Scalar ic2 = this->c[2](2);
+      return
+        (ic0 <  ac2 && ic1 <= ac2 && ic2 <= ac2) ||
+        (ic0 <= ac2 && ic1 <  ac2 && ic2 <= ac2) ||
+        (ic0 <= ac2 && ic1 <= ac2 && ic2 <  ac2);
+    }
+
+    bool is_behind_plane(const Triangle &that) const
+    {
+      using namespace std;
+      const typename Vec3::Scalar apc0 = that.project(this->c[0]);
+      const typename Vec3::Scalar apc1 = that.project(this->c[1]);
+      const typename Vec3::Scalar apc2 = that.project(this->c[2]);
+      cout<<"    "<<
+        apc0<<", "<<
+        apc1<<", "<<
+        apc2<<", "<<endl;
+      return (apc0 <  ZERO() && apc1 < ZERO() && apc2 < ZERO());
+    }
+
+    bool is_in_front_of_plane(const Triangle &that) const
+    {
+      using namespace std;
+      const typename Vec3::Scalar apc0 = that.project(this->c[0]);
+      const typename Vec3::Scalar apc1 = that.project(this->c[1]);
+      const typename Vec3::Scalar apc2 = that.project(this->c[2]);
+      cout<<"    "<<
+        apc0<<", "<<
+        apc1<<", "<<
+        apc2<<", "<<endl;
+      return (apc0 >  ZERO() && apc1 > ZERO() && apc2 > ZERO());
+    }
+
+    bool is_coplanar(const Triangle &that) const
+    {
+      using namespace std;
+      const typename Vec3::Scalar apc0 = that.project(this->c[0]);
+      const typename Vec3::Scalar apc1 = that.project(this->c[1]);
+      const typename Vec3::Scalar apc2 = that.project(this->c[2]);
+      return (fabs(apc0)<=ZERO() && fabs(apc1)<=ZERO() && fabs(apc2)<=ZERO());
+    }
+
+    // http://stackoverflow.com/a/14561664/148668
+    // a1 is line1 start, a2 is line1 end, b1 is line2 start, b2 is line2 end
+    static bool seg_seg_intersect(const Vec3 &  a1, const Vec3 &  a2, const Vec3 &  b1, const Vec3 &  b2)
+    {
+      Vec3 b = a2-a1;
+      Vec3 d = b2-b1;
+      typename Vec3::Scalar bDotDPerp = b(0) * d(1) - b(1) * d(0);
+
+      // if b dot d == 0, it means the lines are parallel so have infinite intersection points
+      if (bDotDPerp == 0)
+        return false;
+
+      Vec3 c = b1-a1;
+      typename Vec3::Scalar t = (c(0) * d(1) - c(1) * d(0)) / bDotDPerp;
+      if (t < 0 || t > 1)
+        return false;
+
+      typename Vec3::Scalar u = (c(0) * b(1) - c(1) * b(0)) / bDotDPerp;
+      if (u < 0 || u > 1)
+        return false;
+
+      return true;
+    }
+    bool has_corner_inside(const Triangle & that) const
+    {
+      // http://www.blackpawn.com/texts/pointinpoly/
+      // Compute vectors        
+      Vec3 A = that.c[0];
+      Vec3 B = that.c[1];
+      Vec3 C = that.c[2];
+      A(2) = B(2) = C(2) = 0;
+      for(int ci = 0;ci<3;ci++)
+      {
+        Vec3 P = this->c[ci];
+        P(2) = 0;
+
+        Vec3 v0 = C - A;
+        Vec3 v1 = B - A;
+        Vec3 v2 = P - A;
+        
+        // Compute dot products
+        typename Vec3::Scalar dot00 = v0.dot(v0);
+        typename Vec3::Scalar dot01 = v0.dot(v1);
+        typename Vec3::Scalar dot02 = v0.dot(v2);
+        typename Vec3::Scalar dot11 = v1.dot(v1);
+        typename Vec3::Scalar dot12 = v1.dot(v2);
+        
+        // Compute barycentric coordinates
+        typename Vec3::Scalar invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+        typename Vec3::Scalar u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+        typename Vec3::Scalar v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+        
+        // Check if point is in triangle
+        if((u >= 0) && (v >= 0) && (u + v < 1))
+        {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    bool overlaps(const Triangle &that) const
+    {
+      // Edges cross
+      for(int e = 0;e<3;e++)
+      {
+        for(int f = 0;f<3;f++)
+        {
+          if(seg_seg_intersect(
+            this->c[e],this->c[(e+1)%3],
+            that.c[e],that.c[(e+1)%3]))
+          {
+            return true;
+          }
+        }
+      }
+      // This could be entirely inside that
+      if(this->has_corner_inside(that))
+      {
+        return true;
+      }
+      // vice versa
+      if(that.has_corner_inside(*this))
+      {
+        return true;
+      }
+      return false;
+    }
+
+
+    bool operator< (const Triangle &that) const
+    {
+      // THIS < THAT if "depth" of THIS  < "depth" of THAT
+      //      "      if THIS should be draw before THAT
+      using namespace std;
+      bool ret = false;
+      // Self compare
+      if(that.id == this->id)
+      {
+        ret = false;
+      }
+      if(this->is_completely_behind(that))
+      {
+        cout<<" "<<this->id<<" completely behind "<<that.id<<endl;
+        ret = false;
+      }else if(that.is_completely_behind(*this))
+      {
+        cout<<" "<<that.id<<" completely behind "<<this->id<<endl;
+        ret = true;
+      }else
+      {
+        if(!this->overlaps(that))
+        {
+          assert(!that.overlaps(*this));
+          cout<<"  THIS does not overlap THAT"<<endl;
+          // No overlap use barycenter
+          return 
+            1./3.*(this->c[0](2) + this->c[1](2) + this->c[2](2)) >
+            1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2));
+        }else
+        {
+          if(this->is_coplanar(that) || that.is_coplanar(*this))
+          { 
+            cout<<"  coplanar"<<endl;
+            // co-planar: decide based on barycenter depth
+            ret = 
+              1./3.*(this->c[0](2) + this->c[1](2) + this->c[2](2)) >
+              1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2));
+          }else if(this->is_behind_plane(that))
+          {
+            cout<<"  THIS behind plane of THAT"<<endl;
+            ret = true;
+          }else if(that.is_behind_plane(*this))
+          { 
+            cout<<"  THAT behind of plane of THIS"<<endl;
+            ret = false;
+          // THAT is in front of plane of THIS
+          }else if(that.is_in_front_of_plane(*this))
+          { 
+            cout<<"  THAT in front of plane of THIS"<<endl;
+            ret = true;
+          // THIS is in front of plane of THAT
+          }else if(this->is_in_front_of_plane(that))
+          {
+            cout<<"  THIS in front plane of THAT"<<endl;
+            ret = false;
+          }else
+          {
+            cout<<"  compare bary"<<endl;
+            ret = 
+              1./3.*(this->c[0](2) + this->c[1](2) + this->c[2](2)) >
+              1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2));
+          }
+        }
+      }
+      if(ret)
+      {
+        // THIS < THAT so better not be THAT < THIS
+        cout<<this->id<<" < "<<that.id<<endl;
+        assert(!(that < *this));
+      }else
+      {
+        // THIS >= THAT so could be THAT < THIS or THAT == THIS
+      }
+      return ret;
+    }
+};
+//#include <igl/matlab/MatlabWorkspace.h>
+//
+//template <
+//  typename DerivedV,
+//  typename DerivedF,
+//  typename DerivedMV,
+//  typename DerivedP,
+//  typename DerivedFF,
+//  typename DerivedI>
+//IGL_INLINE void igl::sort_triangles_robust(
+//  const Eigen::PlainObjectBase<DerivedV> & V,
+//  const Eigen::PlainObjectBase<DerivedF> & F,
+//  const Eigen::PlainObjectBase<DerivedMV> & MV,
+//  const Eigen::PlainObjectBase<DerivedP> & P,
+//  Eigen::PlainObjectBase<DerivedFF> & FF,
+//  Eigen::PlainObjectBase<DerivedI> & I)
+//{
+//  assert(false && 
+//    "THIS WILL NEVER WORK because depth sorting is not a numerical sort where"
+//    "pairwise comparisons of triangles are transitive.  Rather it is a"
+//    "topological sort on a dependecy graph. Dependency encodes 'This triangle"
+//    "must be drawn before that one'");
+//  using namespace std;
+//  using namespace Eigen;
+//  using namespace igl;
+//  typedef Matrix<typename DerivedV::Scalar,3,1> Vec3;
+//  assert(V.cols() == 4);
+//  Matrix<typename DerivedV::Scalar, DerivedV::RowsAtCompileTime,3> VMVP =
+//    V*(MV.transpose()*P.transpose().eval().block(0,0,4,3));
+//
+//  MatrixXd projV(V.rows(),3);
+//  for(int v = 0;v<V.rows();v++)
+//  {
+//    Vector3d vv;
+//    vv(0) = V(v,0);
+//    vv(1) = V(v,1);
+//    vv(2) = V(v,2);
+//    Vector3d p;
+//    project(vv,p);
+//    projV.row(v) = p;
+//  }
+//
+//  vector<Triangle<Vec3> > vF(F.rows());
+//  MatrixXd N(F.rows(),3);
+//  MatrixXd C(F.rows()*3,3);
+//  for(int f = 0;f<F.rows();f++)
+//  {
+//    vF[f] = 
+//      //Triangle<Vec3>(f,VMVP.row(F(f,0)),VMVP.row(F(f,1)),VMVP.row(F(f,2)));
+//      Triangle<Vec3>(f,projV.row(F(f,0)),projV.row(F(f,1)),projV.row(F(f,2)));
+//    N.row(f) = vF[f].n;
+//    for(int c = 0;c<3;c++)
+//      for(int d = 0;d<3;d++)
+//        C(f*3+c,d) = vF[f].c[c](d);
+//  }
+//  MatlabWorkspace mw;
+//  mw.save_index(F,"F");
+//  mw.save(V,"V");
+//  mw.save(MV,"MV");
+//  mw.save(P,"P");
+//  Vector4i VP;
+//  glGetIntegerv(GL_VIEWPORT, VP.data());
+//  mw.save(projV,"projV");
+//  mw.save(VP,"VP");
+//  mw.save(VMVP,"VMVP");
+//  mw.save(N,"N");
+//  mw.save(C,"C");
+//  mw.write("ao.mat");
+//  sort(vF.begin(),vF.end());
+//
+//  // check
+//  for(int f = 0;f<F.rows();f++)
+//  {
+//    for(int g = f+1;g<F.rows();g++)
+//    {
+//      assert(!(vF[g] < vF[f])); // should never happen
+//    }
+//  }
+//  FF.resize(F.rows(),3);
+//  I.resize(F.rows(),1);
+//  for(int f = 0;f<F.rows();f++)
+//  {
+//    FF.row(f) = F.row(vF[f].id);
+//    I(f) = vF[f].id;
+//  }
+//
+//  mw.save_index(FF,"FF");
+//  mw.save_index(I,"I");
+//  mw.write("ao.mat");
+//}
+
+//template <
+//  typename DerivedV,
+//  typename DerivedF,
+//  typename DerivedFF,
+//  typename DerivedI>
+//IGL_INLINE void igl::sort_triangles_robust(
+//  const Eigen::PlainObjectBase<DerivedV> & V,
+//  const Eigen::PlainObjectBase<DerivedF> & F,
+//  Eigen::PlainObjectBase<DerivedFF> & FF,
+//  Eigen::PlainObjectBase<DerivedI> & I)
+//{
+//  using namespace Eigen;
+//  using namespace igl;
+//  using namespace std;
+//  // Put model, projection, and viewport matrices into double arrays
+//  Matrix4d MV;
+//  Matrix4d P;
+//  glGetDoublev(GL_MODELVIEW_MATRIX,  MV.data());
+//  glGetDoublev(GL_PROJECTION_MATRIX, P.data());
+//  if(V.cols() == 3)
+//  {
+//    Matrix<typename DerivedV::Scalar, DerivedV::RowsAtCompileTime,4> hV;
+//    hV.resize(V.rows(),4);
+//    hV.block(0,0,V.rows(),V.cols()) = V;
+//    hV.col(3).setConstant(1);
+//    return sort_triangles_robust(hV,F,MV,P,FF,I);
+//  }else
+//  {
+//    return sort_triangles_robust(V,F,MV,P,FF,I);
+//  }
+//}
+
 #ifndef IGL_HEADER_ONLY
 // Explicit template instanciation
+//template void igl::sort_triangles_robust<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::sort_triangles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::sort_triangles_slow<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif

+ 24 - 0
include/igl/sort_triangles.h

@@ -48,6 +48,30 @@ namespace igl
     const Eigen::PlainObjectBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedFF> & FF,
     Eigen::PlainObjectBase<DerivedI> & I);
+  //template <
+  //  typename DerivedV,
+  //  typename DerivedF,
+  //  typename DerivedMV,
+  //  typename DerivedP,
+  //  typename DerivedFF,
+  //  typename DerivedI>
+  //IGL_INLINE void sort_triangles_robust(
+  //  const Eigen::PlainObjectBase<DerivedV> & V,
+  //  const Eigen::PlainObjectBase<DerivedF> & F,
+  //  const Eigen::PlainObjectBase<DerivedMV> & MV,
+  //  const Eigen::PlainObjectBase<DerivedP> & P,
+  //  Eigen::PlainObjectBase<DerivedFF> & FF,
+  //  Eigen::PlainObjectBase<DerivedI> & I);
+  //template <
+  //  typename DerivedV,
+  //  typename DerivedF,
+  //  typename DerivedFF,
+  //  typename DerivedI>
+  //IGL_INLINE void sort_triangles_robust(
+  //  const Eigen::PlainObjectBase<DerivedV> & V,
+  //  const Eigen::PlainObjectBase<DerivedF> & F,
+  //  Eigen::PlainObjectBase<DerivedFF> & FF,
+  //  Eigen::PlainObjectBase<DerivedI> & I);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 11 - 0
include/igl/unproject.cpp

@@ -38,10 +38,21 @@ IGL_INLINE int igl::unproject(
   return ret;
 }
 
+template <typename Derivedwin>
+IGL_INLINE Eigen::PlainObjectBase<Derivedwin> igl::unproject(
+  const Eigen::PlainObjectBase<Derivedwin> & win)
+{
+  Eigen::PlainObjectBase<Derivedwin> obj;
+  unproject(win,obj);
+  return obj;
+}
+
+
 #ifndef IGL_HEADER_ONLY
 // Explicit template instanciation
 template int igl::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
 template int igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
+template Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
 #endif
 
 #endif

+ 3 - 0
include/igl/unproject.h

@@ -22,6 +22,9 @@ namespace igl
   IGL_INLINE int unproject(
     const Eigen::PlainObjectBase<Derivedwin> & win,
     Eigen::PlainObjectBase<Derivedobj> & obj);
+  template <typename Derivedwin>
+  IGL_INLINE Eigen::PlainObjectBase<Derivedwin> unproject(
+    const Eigen::PlainObjectBase<Derivedwin> & win);
 }
 
 #ifdef IGL_HEADER_ONLY