Posts Tagged ‘mesh’

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

Common mesh energies, sum notation and matrix notation

Monday, June 20th, 2011

I’m always re-deriving the matrix notation of common triangle mesh energies like the Dirichlet energy, Laplacian energy, or local rigidity energy. Here’s my usual strategy. I’ll assume that if your energy came from a continuous integral you can at least get it to a sum over mesh elements. Here I write my sums over vertices and their neighbors, but surely you could also sum over triangles.

mesh energies sum to matrix form
Pretty-printed pdf document

Uglier plain text, unicode version:


∑i∑j∈N(i) vi  = ∑i * #N(i) * v = VT * D * 1, 
  where D is diagonal with Dii = #N(i)
∑i∑j∈N(i) vj  = VT * A * 1, where A is the adjacency matrix
∑i∑j∈N(i) vi - vj = VT * D * 1 - VT * A * 1 = VT * (D-A) * 1

∑i∑j∈N(i) wij  = 1 * Aw * 1, where Aw adjacency with Awij = wij, if j∈N(i)
∑i∑j∈N(i) wij*vi  = ∑i vi * ∑j∈N(i) wij  = VT * Dw * 1, 
  where Dw diagonal with Dwii = ∑j∈N(i) wij
∑i∑j∈N(i) wij*vj  = VT * Aw * 1

∑i mi * ∑j∈N(i) wij vi = ∑i mi * vi * ∑j∈N(i) wij = VT * M * Dw * 1,
  where M is diagonal with Mii = wi
∑i mi * ∑j∈N(i) wij vj = VT * Aw * M * 1

∑i∑j∈N(i) vi² = VT * D * V
∑i∑j∈N(i) vivj = VT * A * V
∑i∑j∈N(i) vj² = VT * RD * V, where RD is diagonal, RDjj = ∑i 1 if j∈N(i)
  if j∈N(i) implies i∈N(j) then
  D = RD
  so ∑i∑j∈N(i) vj² = ∑i∑j∈N(i) vi² = VT * D * V
∑i∑j∈N(i) (vi - vj)² = ∑i∑j∈N(i) vi² - 2 * ∑i∑j∈N(i) vivj + ∑i∑j∈N(i) vj²
                     = 2 * ∑i∑j∈N(i) vi² - 2 * ∑i∑j∈N(i) vivj
                     = 2 * VT * D * V - 2 * VT * A * V
                     = 2 * VT * (D - A) * V
                     = 2 * VT * L * V

∑i∑j∈N(i) wij*vi²  = ∑i vi² * ∑j∈N(i) wij = VT * Dw * V
∑i∑j∈N(i) wij*vivj = VT * Aw * V
∑i∑j∈N(i) wij*vj² = VT * RDw * V, where DW is diagonal, RDwjj = ∑i wij if j∈N(i)
  if j∈N(i) implies i∈N(j) and wij = wji then 
  Dw = RDw
  so ∑i∑j∈N(i) wij*vj² = ∑i∑j∈N(i) wij*vi² = VT * Dw * V
∑i∑j∈N(i) wij(vi - vj)² = 
  = ∑i∑j∈N(i) wij*vi² - 2 * ∑i∑j∈N(i) wij*vivj + ∑i∑j∈N(i) wij*vj²
  = 2 * ∑i∑j∈N(i) wij*vi² - 2 * ∑i∑j∈N(i) wij*vivj
  = 2 * VT * Dw * V - 2 * VT * Aw * V
  = 2 * VT * (Dw - Aw) * V
  = 2 * VT * Lw * V

∑i mi * ∑j∈N(i) wij vi² = ∑i mi * vi² * ∑j∈N(i) wij = VT * M * Dw * V
∑i mi * ∑j∈N(i) wij vj² = VT * RDw * M * V
∑i mi * ∑j∈N(i) wij vivj = VT * Aw * M * V
∑i mi * ∑j∈N(i) wij(vi - vj)² = 
  = ∑i mi * ∑j∈N(i) wij*vi² 
    - 2 * ∑i mi * ∑j∈N(i) wij*vivj 
    + ∑i mi *∑j∈N(i) wij*vj²
  = 2 * ∑i mi * ∑j∈N(i) wij*vi² - 2 * ∑i mi * ∑j∈N(i) wij*vivj
  = 2 * VT * M * Dw * V - 2 * VT * Aw * M * V
  = 2 * VT * M * (Dw - Aw) * V
  = 2 * VT * M * Lw * V
  Note: let wij = cwij = cot(αij) + cot(βij) / mi and let mi = voronoi area at 
  vi, then the familar cotangent form of the discrete Dirichlet energy is
  EDirichlet = 2 * VT * M * Lcw * V

Split triangular prism into three tetrahedra

Wednesday, June 15th, 2011

triangular prism split into three tetrahedra small

Recently I began looking into tet-meshes again. Some colleagues and I were trying to wrap our heads around how many tetrahedra result from splitting up a triangular prism. we were trying to draw out the cases on the white board. Occasionally some one would say, “I’m sure it’s 3.” Then somebody else would draw another set of pictures and’d say “No, I’m sure it’s 4″.

Well, to have a definitive answer, a triangular prism may be split into three tetrahedra. If you don’t believe me, see the nice description (which actually lists all possible splits) in “How to Subdivide Pyramids, Prisms and Hexahedra into Tetrahedra” by J. Dompierre et al. in 1999. There is another interesting discussion in “Space-filling Tetrahedra in Euclidean Space” by D.M.Y. Sommerville in 1923, in which they consider the conditions under which these tetrahedra are congruent.

Convert .vert/.tri pairs into obj with simple bash script

Friday, May 13th, 2011

Here’s a tiny bash script you can save in verttri2obj.sh to convert .vert/.tri pairs like those of the TOSCA mesh repository:


#!/bin/bash
cat $1 | sed -e "s/^/v /g" > $3
cat $2 | sed -e "s/^/f /g" >> $3

And call it with:


./verttri2obj.sh mesh.vert mesh.tri mesh.obj

Update: Here’s a little bash oneliner that uses the script above to convert all the .vert/.tri pairs in a directory to objs:


ls -1 *.vert | sed -e "s/\(.*\).vert/~\/path\/to\/verttri2obj.sh \1.vert \1.tri \1.obj/g" | bash

Converting the entire TASCO repository above took about a minute and a half on my computer.

Bounded biharmonic weights project page

Wednesday, May 4th, 2011


The Alligator is deformed using a skeleton on the jaws, a cage on the belly and points on the tail.

My colleagues, Ilya Baran, Jovan Popović, Olga Sorkine, and I have just submitted the camera ready version of paper “Bounded Biharmonic Weights for Real-Time Deformation” to be presented at ACM SIGGRAPH 2011. I’ve put up a bounded biharmonic weights project page where you can find the preprint version of the article, videos and more to come.

Bounded biharmonic weights are featured in the official SIGGRAPH 2011 Technical Papers Advance Preview. The Technical Papers Chair, Hugues Hoppe, writes:

“An elegant UI framework that unifies cages, skeletons, and point constraints for 2D and 3D deformations.”

Abstract

Object deformation with linear blending dominates practical use as the fastest approach for transforming raster images, vector graphics, geometric models and animated characters. Unfortunately, linear blending schemes for skeletons or cages are not always easy to use because they may require manual weight painting or modeling closed polyhedral envelopes around objects. Our goal is to make the design and control of deformations simpler by allowing the user to work freely with the most convenient combination of handle types. We develop linear blending weights that produce smooth and intuitive deformations for points, bones and cages of arbitrary topology. Our weights, called bounded biharmonic weights, minimize the Laplacian energy subject to bound constraints. Doing so spreads the influences of the controls in a shape-aware and localized manner, even for objects with complex and concave boundaries. The variational weight optimization also makes it possible to customize the weights so that they preserve the shape of specified essential object features. We demonstrate successful use of our blending weights for real-time deformation of 2D and 3D shapes.

Update: I have released a 2D matlab demo, with complete source code.

Determine boundary faces from tetrahedral mesh

Wednesday, April 20th, 2011

Here’s a matlab function that takes a list of tetrahedron indices (4 indices to a row) and finds the triangles that are on the surface of the volume. It does this simply by finding all of the faces that only occur once.


function F = boundary_faces(T)
  % BOUNDARY_FACES
  % F = boundary_faces(T)
  % Determine boundary faces of tetrahedra stored in T
  %
  % Input:
  %  T  tetrahedron index list, m by 4, where m is the number of tetrahedra
  %
  % Output:
  %  F  list of boundary faces, n by 3, where n is the number of boundary faces
  %

  % get all faces
  allF = [ ...
    T(:,1) T(:,2) T(:,3); ...
    T(:,1) T(:,3) T(:,4); ...
    T(:,1) T(:,4) T(:,2); ...
    T(:,2) T(:,4) T(:,3)];
  % sort rows so that faces are reorder in ascending order of indices
  sortedF = sort(allF,2);
  % determine uniqueness of faces
  [u,m,n] = unique(sortedF,'rows');
  % determine counts for each unique face
  counts = accumarray(n(:), 1);
  % extract faces that only occurred once
  sorted_exteriorF = u(counts == 1,:);
  % find in original faces so that ordering of indices is correct
  F = allF(ismember(sortedF,sorted_exteriorF,'rows'),:);
end

With this you can easily determine the vertices of a tetmesh that are on the boundary:


% V are your vertex positions, T are your tet indices
% get boundary faces
F = boundary_faces(T);
% get boundary vertices
b = unique(F(:));
subplot(1,2,1);
% plot boundary positions
plot3(V(b,1),V(b,2),V(b,3),'.');
subplot(1,2,2);
% plot just  boundary faces
trisurf(F,V(:,1),V(:,2),V(:,3),'FaceAlpha',0.3)

Mesh animation with MATLAB

Thursday, December 30th, 2010

Here’s a small piece of code demonstration how to animate a triangle mesh using matlab. Assuming your mesh vertices are stored in V and your face indices in F then issue:


t = trisurf(F,V(:,1),V(:,2),V(:,3));
view(2)
axis equal
axis tight
ax = axis;
axis([ax(:,1)-10, ax(:,2)+10, ax(:,3), ax(:,4)+10]);
then = now;
while(true)
x = 10*sin(100000*(now-then));
y = abs(10*cos(100000*(now-then)));
set(t,'Vertices',[V(:,1)+x V(:,2)+y V(:,3)]);
drawnow;
pause(0.1);
end

matlab mesh animation

It’s a pretty slow animation, but any faster on a 800-vertices mesh MATLAB drops frames. The pause helps but of course makes it slower, as a side effect though the my CPU is only at 20%.

Mouse interaction with meshes in matlab

Thursday, December 30th, 2010

Here’s a small piece of code illustrating how to receive mouse clicks on a mesh plotted with trisurf in matlab. Assuming your mesh is stored with vertices in V and face indices in F, then have onmeshdown be the function you want to be called when the mesh is clicked and onvoiddown be the function you want to be called when the void in the plot outside the mesh is clicked (the white and the grey parts).


tsh = trisurf(F,V(:,1),V(:,2),V(:,3),'tag','trisurf','ButtonDownFcn',@onmeshdown);
p = get(tsh,'Parent');
set(p,'ButtonDownFcn',@onvoiddown);

Here’s a little demo showing you what you can do with that:


function dragdemo(V,F)
  figure 
  tsh = trisurf(F,V(:,1),V(:,2),V(:,3),'ButtonDownFcn',@onmeshdown);
  p = get(tsh,'Parent');
  set(p,'ButtonDownFcn',@onvoiddown);
  view(2);
  axis equal
  axis manual
  down_pos = [];
  drag_pos = [];
  down_V = [];

    function onvoiddown(src,ev)
      % do nothing
    end

    function onmeshdown(src,ev)
      down_pos=get(gca,'currentpoint'); 
      title(sprintf('(%1.0f,%1.0f)',down_pos(1,1,1),down_pos(1,2,1)));
      set(gcf,'windowbuttonmotionfcn',@drag) 
      set(gcf,'windowbuttonupfcn',@up)
      down_V = get(tsh,'Vertices');
    end

    function drag(src,ev)
      drag_pos=get(gca,'currentpoint'); 
      title( ...
        sprintf( ...
          '(%1.0f,%1.0f) -> (%1.0f,%1.0f)', ...
          down_pos(1,1,1),down_pos(1,2,1), ...
          drag_pos(1,1,1),drag_pos(1,2,1)));
      set( ...
        tsh, ...
        'Vertices', ...
        [ ...
          (drag_pos(1,1,1) - down_pos(1,1,1)) + down_V(:,1), ...
          (drag_pos(1,2,1) - down_pos(1,2,1)) + down_V(:,2), ...
          down_V(:,3) ...
        ]);
    end

    function up(src,ev) 
        set(gcf,'windowbuttonmotionfcn',''); 
        set(gcf,'windowbuttonupfcn',''); 
    end

end

matlab mesh mouse interation