Spherical Mesh Parameterization¶


This tour explores parameterization of 3D surfaces onto a sphere.

We use a simple minimization of the Dirichlet energy under spherical constraints. There is no theoritical guarantee, but for some meshes, it seems to work correctly.

In [2]:
addpath('toolbox_signal')


Smoothing Operator¶

We start by creating a smoothing operator.

First load a mesh.

In [3]:
name = 'horse';
n = size(vertex,2);
m = size(faces,2);
clear options; options.name = name;


Display the mesh.

In [4]:
clf;
options.lighting = 1;
plot_mesh(vertex,faces,options);


Compute the weights. The weights should be positive for the method to work.

In [5]:
weight = 'conformal';
weight = 'combinatorial';
switch weight
case 'conformal'
W = make_sparse(n,n);
for i=1:3
i1 = mod(i-1,3)+1;
i2 = mod(i  ,3)+1;
i3 = mod(i+1,3)+1;
pp = vertex(:,faces(i2,:)) - vertex(:,faces(i1,:));
qq = vertex(:,faces(i3,:)) - vertex(:,faces(i1,:));
% normalize the vectors
pp = pp ./ repmat( sqrt(sum(pp.^2,1)), [3 1] );
qq = qq ./ repmat( sqrt(sum(qq.^2,1)), [3 1] );
% compute angles
ang = acos(sum(pp.*qq,1));
a = max(1 ./ tan(ang),1e-1); % this is *very* important
W = W + make_sparse(faces(i2,:),faces(i3,:), a, n, n );
W = W + make_sparse(faces(i3,:),faces(i2,:), a, n, n );
end
case 'combinatorial'
E = [faces([1 2],:) faces([2 3],:) faces([3 1],:)];
E = unique_rows([E E(2:-1:1,:)]')';
W = make_sparse( E(1,:), E(2,:), ones(size(E,2),1) );
end


Compute the normalized weight matrix |tW| such that its rows sums to 1.

In [6]:
d = full( sum(W,1) );
D = spdiags(d(:), 0, n,n);
iD = spdiags(d(:).^(-1), 0, n,n);
tW = iD * W;


Spherical Relaxation¶

It is possible to smooth the positions of the mesh on the sphere by performing an averaging according to |W|, and projecting back on the sphere.

Compute an initial mapping on the sphere. This simply a radial projection.

In [7]:
vertex1 = vertex;
vertex1 = vertex1 - repmat( mean(vertex1,2), [1 n] );
vertex1 = vertex1 ./ repmat( sqrt(sum(vertex1.^2,1)), [3 1] );


Check which faces have the correct orientation.

normal to faces

In [8]:
[normal,normalf] = compute_normal(vertex1,faces);


center of faces

In [9]:
C = squeeze(mean(reshape(vertex1(:,faces),[3 3 m]), 2));


inner product

In [10]:
I = sum(C.*normalf);


Ratio of inverted triangles. For a bijective mapping, there should not be any inverted triangle.

In [11]:
disp(['Ratio of inverted triangles:' num2str(sum(I(:)<0)/m, 3) '%']);

Ratio of inverted triangles:0.224%


Display on the sphere.

In [12]:
options.name = 'none';
clf;
options.face_vertex_color = double(I(:)>0);
plot_mesh(vertex1,faces,options);
colormap gray(256); axis tight;


Perform smoothing and projection.

In [13]:
vertex1 = vertex1*tW';
vertex1 = vertex1 ./ repmat( sqrt(sum(vertex1.^2,1)), [3 1] );


Exercise 1

Perform iterative smoothing and projection. Record the evolution of the number of inverted triangle in |ninvert|. Record also the evolution of the Dirichlet energy in |Edir|.

In [14]:
exo1()