Abstract : The goal of this lecture is to manipulate a 3D mesh. This includes the loading and display of a 3D mesh and then the processing of the mesh. This processing is based on computations involving various kinds of Laplacians. These Laplacians are extensions of the classical second order derivatives to 3D meshes. They can be used to perform heat diffusion (smoothing), compression and parameterization of the mesh.
Note : this lecture is a Scilab variant of my original Matlab lectures. If you want to have access to more functionalities for mesh processing (including parameterization and vizualisation), you should check the Matlab lectures.
// for large meshes, you can try 'bunny', 'elephant-50kv'
// for small meshes, you can try 'mushroom', 'nefertiti'
name = 'mushroom';
// load from file
[vertex,face] = read_off(strcat([name '.off']));
// display the mesh
plot_mesh(vertex,face);
// add the light to the display
options.lighting = 1;
options.faceted = 1;
plot_mesh(vertex,face, options);
// set a color for display
options.face_vertex_color = vertex(2,:);
options.lighting = 0; // you can try also with 1
options.faceted = 0;
plot_mesh(vertex,face, options);
// try to rotate the camera, change the color of display, etc
...
// try to morph the mesh (using handcraft deformation of vertex, and using the normal)
normal = compute_normal(vertex,face);
...
![]()
|
|||
| Exemple of a rendered triangle meshe (interp and faceted). |
| L0 = D + W | (symmetric, non-normalized) | |
| L1 = D^{-1}*L0 = Id + D^{-1}*W | (non-symmetric, normalized) | |
| L2 = D^{-1/2}*L0*D^{-1/2} = Id + D^{-1/2}*W*D^{-1/2} | (symmetric, normalized) |
| W(i,j)=1 | (combinatorial) | |
| W(i,j)=1/|vi-vj|^2 | (distance) | |
| W(i,j)=cot(alpha_ij)+cot(beta_ij) | (harmonic) |
// kind of laplacian, can be 'combinatorial', 'distance' or 'conformal' (slow)
laplacian_type = ...;
// load two different kind of laplacian and check the gradient factorization
options.symmetrize = 1;
options.normalize = 0;
L0 = compute_mesh_laplacian(vertex,face,laplacian_type,options);
// check that the laplacian is symmetric, test if L*1=0 or not
...
options.symmetrize=0;
options.normalize=1;
L = compute_mesh_weight(vertex,face,'combinatorial',options);
vertex1 = (W*vertex')'; // do you understand the role of ' ?
// display the mesh
...
// iterate the smoothing and display - relate this with the theory (convergence, etc)
...
// try with other kind of weights
...
// compute the un-symmetric laplacian
options.symmetrize = 0;
options.normalize = 1;
L = compute_mesh_laplacian(vertex,face,laplacian_type,options);
// the time step should be small enough
dt = 0.1;
// stopping time
Tmax = 5;
// number of steps
niter = round(Tmax/dt);
// initialize the 3 vectors at time t=0
vertex1 = vertex;
// solve the diffusion
for i=1:niter
// update the position by solving the PDE
vertex1 = vertex1 + ...;
end
|
| Heat diffusion on a 3D mesh, at times t=0, t=10, t=40, t=200. |
nvert = size(vertex,2);
// compute the normals
normals = compute_normal(vertex,face)';
// add some noise to the vertices
sigma = .01; // noise level
rho = randn(1,nvert)*sigma;
vertex1 = vertex + (ones(3,1)*rho).*normals;
// solve the heat equation
for i=1:niter
vertex1 = ...;
// record the denoising error
error(i) = ...;
end
// display the error decay
...
// compute the optimal diffusion time t as a function of the noise sigma
[errmin,topt] = min(error);
// compute the evolution of topt as a function of the noise level sigma
...
// display the denoised mesh - comments ?
...
![]()
|
| Mesh denoising with several stopping times Tmax. |
// solve the equation
vertex1 = ...;
// display
...
// Warning: use this code on a SMALL mesh (e.g. mushroom or nefertiti)
// combinatorial laplacian computation
options.symmetrize = 1;
options.normalize = 0;
L0 = compute_mesh_laplacian(vertex,face,'combinatorial',options);
// Performing eigendecomposition
[U,lambda] = spec(full(L));
// display the spectrum lambda - comments ?
plot(lambda);
// extract one of the eigenvectors
c = U(:,end-10); // you can try with other vector with higher frequencies
// assign a color to each vertex
options.face_vertex_color = c;
// display
clf;
plot_mesh(vertex,face, options);
// try for other eigenvectors - comments ?
![]()
|
| Eigenvectors of the combinatorial laplacian with increasing frequencies from left to right. |
// load a small mesh (like 'venus')
...
// warning : vertex should be of size 3 x nvert
keep = 5; // number of percents of coefficients kept
pf = (U'*vertex'); // projection of the vector in the laplacian basis
// display the spectrum pf
...
// set to zero high pass coefficients
q = round(keep/100*nvert); // number of zeros
pf(q+1:end,:) = 0;
vertex1 = (U*pf)';
// display the reconstructed mesh - comments ?
...
|
| Spectral mesh compression performed by decomposition on the eigenvectors of the laplacian. |
// try first this method on 'nefertiti' mesh
// compute the laplacian (must be symmetric)
L = ...;
// compute eigendecomposition
pf = (U'*vertex');
// exctact the correct component from the eigenvectors
vertex1 = ...;
// display the flattened mesh
plot_graph(triangulation2adjacency(face),vertex1);
// do the flattening with the conformal laplacian - comment
...
// try on manequin
...
// try on a sphere with a hole of increasing size
...
![]()
|
Comparison of the flattening obtained with the combinatorial
laplacian, |
// load a mesh, e.g. bunny, compute normalized laplacian
...
// the time step should be small enough
dt = 0.2;
// stopping time
Tmax = 20;
// number of steps
niter = round(Tmax/dt);
// initialize the vectors at time t=0
n = size(vertex,2);
f = ...; // set random +1/-1
// solve the equation
fprev = f;
for i=1:niter
// update the position by solving the PDE
fsvg = f;
f = 2*f - ...;
fprev = f;
end
// display
...
// use another f (gaussian bumps)
...
|
| Wave propagation with several stopping times Tmax. The initial condition f is a collection of little gaussian bumps. |
This requires :
1) identifying the vertex of the mesh that are on the boundary.
2) computing for these vertex a 2D position (x0,y0) on a circle (or any convex
curve).
3) computing the laplacian.
4) for each index i on the boundary, set L(i,:)=0 and then L(i,i)=1.
5) compute a right hand size vector b=0 with b(i)=x0(i) for those i on the
boundary. Solve for x=L\b.
6) same thing but for y.
![]()
|
| The first row shows parameterization using the combinatorial
laplacian (with various boundary conditions). This assumes that the edge lengths is 1. To take into account the geometry of the mesh, the second row uses the conformal laplacian. The last row shows another example of parameterization with a conformal laplacian. |
Copyright © 2008 Gabriel Peyré