Posts Tagged ‘mesh’

Porting Marco Attene’s meshfix to mac os x

Wednesday, November 14th, 2012

Short notes on porting meshfix to mac.

Follow readme.txt placing downloaded OpenNL and JMeshLib directories in the mesh fix directory [same as meshfix.cpp]

When compiling JMeshLib be sure in makeconf file to change the lines:


# On 64-bit machines you need to uncomment the following line
# -DIS64BITPLATFORM

MOREFLAGS = $(OPTM) $(STRICTALIAS)

to:


MOREFLAGS = $(OPTM) $(STRICTALIAS) -DIS64BITPLATFORM

When compiling JMeshExt I separated the predicates.cxx file from tetgen’s source to make jrs_predicates.h and jrs_predicates.c. Placing them according to readme.txt. One note is that if jrs_predicates.c is to be a .c file rather than a .cpp file then you need to extern "C"{...} encapsulate the jrs_predicates.h header file or you will get Undefined symbol linker errors.

Finally in JMeshExt and meshfix.cpp there are several casts of pointers to ints. This won’t compile on 64-bit machines. This similar operation was fixed in JMeshLib by the -DIS64BITPLATFORM. Thus, I’ve fixed the following files to use the j_voidint typedef defined by IS64BITPLATFORM in j_mesh.h:


JMeshExt-1.0alpha_src/src/holeFilling.cpp
meshfix.cpp

I’ve zipped up my changes and organization: download package. Then you can just issue:


cd OpenNL3.2.1/
./configure.sh 
cd build/Darwin-Release/
make
cd ../../../JMeshLib-1.2/
make
cd ../JMeshExt-1.0alpha_src/
make
cd ..
make

I imagine a very similar port could be used for Linux.

Update: I started occasionally getting runtime errors:


OpenNL should not have reached this point: file:/Users/ajx/Downloads/MeshFix/OpenNL3.2.1/src/NL/nl_superlu.c, line:223
Abort trap: 6

Seems this comes from compiling OpenNL without SuperLU support. SuperLU is fairly straightforward to install and so is following the OpenNL instructions for compiling with OpenNL support.

GL_COMPILE_AND_EXECUTE is slow (but apparently everybody knew that)

Thursday, October 11th, 2012

Although it doesn’t seem to be deprecated the glNewList() option GL_COMPILE_AND_EXECUTE is not properly supported by nVidia GPUs. On my linux machine, we installed a fancy pants nVidia card. So I was surprised to find out that my code ran slower there than on my dinky mac. After a long debugging session I found that it was all GL_COMPILE_AND_EXECUTE‘s fault. I was displaying a mesh each frame using code that looked like:


  if(!display_list_compiled)
  {
    dl_id = glGenLists(1);
    glNewList(dl_id,GL_COMPILE_AND_EXECUTE);
    ... //draw mesh
    glEndList();
    display_list_compiled = true;
  }else
  {
    glCallList(dl_id);
  }

I expected that this would be slow for the first time. But in fact it was significantly slower (factor of 100) for every frame! Even though it was using the display list. I guess that passing GL_COMPILE_AND_EXECUTE creates a very badly organized display list and then you’re punished every time you use it.

The solution is of course trivial:


  if(!display_list_compiled)
  {
    dl_id = glGenLists(1);
    glNewList(dl_id,GL_COMPILE;
    ... //draw mesh
    glEndList();
    display_list_compiled = true;
  }
  glCallList(dl_id);

but $#%^&*! what a waste of time.

Technical report: A Cotangent Laplacian for Images as Surfaces

Monday, April 23rd, 2012

A Cotangent Laplacian for Images as Surfaces
We decided to write up a quick, 2 page technical report about some ideas we’ve had in the last year.

Abstract
By embedding images as surfaces in a high dimensional coordinate space defined by each pixel’s Cartesian coordinates and color values, we directly define and employ cotangent-based, discrete differential-geometry operators. These operators define discrete energies useful for image segmentation and colorization.

Isoline plots on triangle meshes in Matlab

Friday, March 9th, 2012

I recently posted how to plot nice looking iso intervals of scalar fields on triangle meshes using matlab. Along with the intervals I gave an ad hoc way of also showing isolines. This works ok if your data has fairly uniform gradient but they’re not really isolines.

Here’s a little matlab function to output real isolines. Save it in a file called isoline.m:


function [LS,LD,I] = isolines(V,F,S,iso)
  % ISOLINES compute a list of isolines for a scalar field S defined on the
  % mesh (V,F)
  %
  % [LS,LD,I] = isolines(V,F,S,iso)
  %
  % Inputs:
  %   V  #V by dim list of vertex positions
  %   F  #F by 3 list of triangle indices
  %   S  #V list of scalar values defined on V
  %   iso #iso list of iso values
  % Outputs:
  %   LS  #L by dim list of isoline start positions
  %   LD  #L by dim list of isoline destination positions
  %   I  #L list of indices into iso revealing corresponding iso value
  %
  % alternative: tracing isolines should result in smaller plot data (every
  % vertex only appears once
  %

  % make sure iso is a ROW vector
  iso = iso(:)';
  % number of isolines
  niso = numel(iso);

  % number of domain positions
  n = size(V,1);
  % number of dimensions
  dim = size(V,2);

  % number of faces
  m = size(F,1);

  % Rename for convenience
  S1 = S(F(:,1),:);
  S2 = S(F(:,2),:);
  S3 = S(F(:,3),:);

  % t12(i,j) reveals parameter t where isovalue j falls on the line from
  % corner 1 to corner 2 of face i
  t12 = bsxfun(@rdivide,bsxfun(@minus,iso,S1),S2-S1);
  t23 = bsxfun(@rdivide,bsxfun(@minus,iso,S2),S3-S2);
  t31 = bsxfun(@rdivide,bsxfun(@minus,iso,S3),S1-S3);

  % replace values outside [0,1] with NaNs
  t12( (t12<-eps)|(t12>(1+eps)) ) = NaN;
  t23( (t23<-eps)|(t23>(1+eps)) ) = NaN;
  t31( (t31<-eps)|(t31>(1+eps)) ) = NaN;

  % masks for line "parallel" to 12
  l12 = ~isnan(t23) & ~isnan(t31);
  l23 = ~isnan(t31) & ~isnan(t12);
  l31 = ~isnan(t12) & ~isnan(t23);

  % find non-zeros (lines) from t23 to t31
  [F12,I12,~] = find(l12);
  [F23,I23,~] = find(l23);
  [F31,I31,~] = find(l31);
  % indices directly into t23 and t31 corresponding to F12 and I12
  %ti12 = sub2ind(size(l12),F12,I12);
  %ti23 = sub2ind(size(l23),F23,I23);
  %ti31 = sub2ind(size(l31),F31,I31);
  % faster sub2ind
  ti12 = F12+(I12-1)*size(l12,1);
  ti23 = F23+(I23-1)*size(l23,1);
  ti31 = F31+(I31-1)*size(l31,1);

  % compute actual position values
  LS = [ ...
    ... % average of vertex positions between 2 and 3
    bsxfun(@times,1-t23(ti12), V(F(F12,2),:)) + ...
    bsxfun(@times,  t23(ti12), V(F(F12,3),:)) ...
    ; ... % average of vertex positions between 2 and 3
    bsxfun(@times,1-t31(ti23), V(F(F23,3),:)) + ...
    bsxfun(@times,  t31(ti23), V(F(F23,1),:)) ...
    ;... % average of vertex positions between 2 and 3
    bsxfun(@times,1-t12(ti31), V(F(F31,1),:)) + ...
    bsxfun(@times,  t12(ti31), V(F(F31,2),:)) ...
    ];
  LD = [...
    ... % hcat with average of vertex positions between 3 and 1
    bsxfun(@times,1-t31(ti12), V(F(F12,3),:)) + ...
    bsxfun(@times,  t31(ti12), V(F(F12,1),:)) ...
    ;... % hcat with average of vertex positions between 3 and 1
    bsxfun(@times,1-t12(ti23), V(F(F23,1),:)) + ...
    bsxfun(@times,  t12(ti23), V(F(F23,2),:)) ...
    ;... % hcat with average of vertex positions between 3 and 1
    bsxfun(@times,1-t23(ti31), V(F(F31,2),:)) + ...
    bsxfun(@times,  t23(ti31), V(F(F31,3),:)) ...
    ];

  % I is just concatenation of each I12
  I = [I12;I23;I31];

end

Then if you have a mesh in (V,F) and so scalar data in S. You can display isolines using:


colormap(jet(nin));
trisurf(F,V(:,1),V(:,2),V(:,3),'CData',S,'FaceColor','interp','FaceLighting','phong','EdgeColor','none');
axis equal;
[LS,LD,I] = isolines(V,F,S,linspace(min(S),max(S),nin+1));
hold on;
plot([LS(:,1) LD(:,1)]',[LS(:,2) LD(:,2)]','k','LineWidth',3);
hold off
set(gcf, 'Color', [1,1,1]);
set(gca, 'visible', 'off');
%O = outline(F);
%hold on;
%plot([V(O(:,1),1) V(O(:,2),1)]',[V(O(:,1),2) V(O(:,2),2)]','-k','LineWidth',2);
%hold off

Uncomment the last lines to display the outline of the mesh. This produces:
woody matlab isolines
If you use the my anti-alias script you can get pretty good results, almost good enough for a camera-ready paper:
woody matlab isolines anti-aliased

Get curve sketch (pen tool) from user in MATLAB figure

Thursday, March 1st, 2012

Here’s a little function that asks the user for a curve drawn on the current figure’s current axis. Similar to a pen/pencil tool in Photoshop etc.

Save this in a file called get_pencil_curve.m:


function P = get_pencil_curve(f)
  % GET_PENCIL_CURVE Get a curve (sequence of points) from the user by dragging
  % on the current plot window
  %
  % P = get_pencil_curve()
  % P = get_pencil_curve(f)
  % 
  % Inputs:
  %   f  figure id
  % Outputs:
  %   P  #P by 2 list of point positions
  %
  %

  % Get the input figure or get current one (creates new one if none exist)
  if nargin == 0 || isempty(f)
    f = gcf;
  end
  figure(f);

  % get axes of current figure (creates on if doesn't exist)
  a = gca;

  % set equal axis 
  axis equal;
  % freeze axis
  axis manual;
  % set view to XY plane
  view(2);

  set(gcf,'windowbuttondownfcn',@ondown);
  set(gcf,'keypressfcn',        @onkeypress);
  % living variables
  P = [];
  p = [];

  % loop until mouse up or ESC is pressed
  done = false;
  while(~done)
    drawnow;
  end

  % We've been also gathering Z coordinate, drop it
  P = P(:,1:2);

  % Callback for mouse press
  function ondown(src,ev)
    % Tell window that we'll handle drag and up events
    set(gcf,'windowbuttonmotionfcn', @ondrag);
    set(gcf,'windowbuttonupfcn',     @onup);
    append_current_point();
  end

  % Callback for mouse drag
  function ondrag(src,ev)
    append_current_point();
  end

  % Callback for mouse release
  function onup(src,ev)
    % Tell window to handle down, drag and up events itself
    finish();
  end

  function onkeypress(src,ev)
    % escape character id
    ESC = char(27);
    switch ev.Character
    case ESC
      finish();
    otherwise
      error(['Unknown key: ' ev.Character]);
    end
  end

  function append_current_point()
    % get current mouse position
    cp = get(gca,'currentpoint');
    % append to running list
    P = [P;cp(1,:)];
    if isempty(p)
      % init plot
      hold on;
      p = plot(P(:,1),P(:,2));
      hold off;
    else
      % update plot
      set(p,'Xdata',P(:,1),'Ydata',P(:,2));
    end
  end

  function finish()
    done = true;
    set(gcf,'windowbuttonmotionfcn','');
    set(gcf,'windowbuttonupfcn','');
    set(gcf,'windowbuttondownfcn','');
    set(gcf,'keypressfcn','');
  end

end

Here I’m using the function ask the user to draw a curve (blue) and then immediately simplify it (red), then mesh the interior (green).
matlab mesh sketch

Display wireframe mesh in matlab and save as vector graphics

Saturday, January 14th, 2012

For our siggraph submission I wanted to overlay a 2D image with the wireframe of the mesh we use to deform it. In matlab I can display a 2D mesh (V,F) easily using:


trisurf(F,V(:,1),V(:,2),0*V(:,1));
view(2);
axis equal;

If I save this as .eps then I get a nice vector graphics version of my mesh.

But if I don’t want the filled faces to show up in the vector output, then when I try to save the following figure as a .eps file:


trisurf(F,V(:,1),V(:,2),0*V(:,1),'FaceAlpha',0);
view(2);
axis equal;

matlab just pretends to make a postscript vector file but instead its just a .eps file containing a raster image.

Here’s what I do to get a .eps vector graphics postscript file (which can then be turned into a PDF since output to PDF is broken in matlab):


E = edges(F);
plot([V(E(:,1),1) V(E(:,2),1)]',[V(E(:,1),2) V(E(:,2),2)]','k-');
view(2);
axis equal
set(gcf, 'Color', [1,1,1]);
set(gca, 'visible', 'off');

New ETHZ masters thesis project available: Server-client mesh processing

Sunday, January 1st, 2012

server client mesh processing eth masters project

Olga Sorkine and I will be hosting a master’s thesis project. The project, entitled Server-client mesh processing is now available, and we are eagerly awaiting applications.Many polygon mesh processing techniques are difficult to implement. These techniques often go unseen and unused beyond publication. Others are too computationally intensive for consumer-level laptops, so their use is limited to academic or commercial communities. Fortunately, polygon mesh processing techniques are well-suited for a server-client implementation. Since most techniques need only an input mesh and a few parameters, all computation may be done on a publicly available web server, relying on the client only to upload the input and download the output.

In this project, we will set up the necessary infrastructure on both the server and client end. The client side will be a light-weight, browser-based interface for viewing and uploading 3D surface meshes. The server side will be a clean API to many existing mesh processing implementations (e.g. smooth- ing, curvature computation, tetrahedral volume meshing). With this infrastructure, we will explore geometric data compression specific to each flavor of mesh processing in order to optimize the transfer of output data. We may also use this infrastructure to conduct large scale user-studies via Amazon’s Mechanical Turk. Such large scale user studies are rarely achieved in the mesh processing community. A server-client infrastructure should finally make human evaluation possible. Please don’t hesitate to contact me for more details.

Also, check out the full list of IGL projects.

Note: You will need to be at an ETH IP address to visit these links.

Perceived stretch from partial view of twist

Wednesday, August 31st, 2011

Here’s a twist applied to a bar.

But when the movie is cropped the viewer gets a sense that the bar is also being stretched, to the right.

Putting a texture (here just a the edges of the 3D model’s mesh), helps perceive the true deformation: twist.

It also helps reduce the perceived stretch effect on the original full-view movie.

Pseudo-color a mesh using random colors for multiple (weight) functions

Tuesday, August 23rd, 2011

Often it’s useful to visualize many functions on a mesh at the same time. Here I assign each function a random pseudocolor, then the color at each vertex of the mesh is just a blend of the function colors weighted by their respective function values. This is especially useful if your functions are already weight functions themselves (defined between 0 and 1). So, if your mesh is defined by V and F then you have a set of function values defined on the vertices W: #V by #functions, then you can use a previously posted function for randomly generating a #functions list of colors. Putting it all together with a matrix multiplication you have:


trisurf([F],V(:,1),V(:,2),V(:,3),'FaceVertexCData',W*random_color(size(W,2),'Pastel'));

To make the rendering a little nicer you can use:


light('Position',[-1.0,-1.0,100.0],'Style','infinite');
lighting gouraud
axis equal
shading interp
view(2)

Here’s a visualization of bounded biharmonic weights on the Armadillo.

armadillo bbw pseudo color

And here’s an easy way to visualize segmenting the mesh based on the maximum function value:


% get indices of max value for each row
[~,I]=max(W,[],2);
trisurf([F],V(:,1),V(:,2),V(:,3),'FaceVertexCData',sparse(1:size(W,1),I,1)*random_color(size(W,2),'Pastel'));

which produces something like:
armadillo bbw pseudo color max value segmentation

Bounded Biharmonic Weights: 2D MATLAB Demo

Monday, July 11th, 2011

woody matlab bbw demo I’ve finally released the matlab prototyping codebase for Bounded Biharmonic Weights. The code base runs without any prerequisite libraries on MATLAB 2011a or greater. With earlier versions of matlab, users should install MOSEK (which is available for free to academic users). This matlab package demos computing skinning weights automatically for a 2d shape. To start, add bbw_demo/ to your matlab path and issue:

>> bbw_demo

If you just want to start digging around in the weight computation code, look at:

  • boundary_conditions.m
  • biharmonic_bounded.m

Currently the bbw_demo.m file just shows basic weight computation and linear blend skinning deformation for point handles. The following features are supported in the codebase above, but are undocumented besides their file header comments:

  • Bone handles
  • Cage edges
  • Dual quaternion skinning
  • Automatic rotations at point handles via pseudo-edges
  • 3D weight computation over tetrahedral meshes
  • 2D/3D remeshing along bones and cage edges
  • …and more

The following things are not supported and probably never will be in the MATLAB demo. If I release the C++ demo then of course they will be available:

  • 3D interactive deformation
  • 2D texture mapping

Please
contact me if you find any bugs or have any trouble using the code.

Update: Here’s a new C++ demo