Solid angle at mesh vertices

Alec Jacobson

February 03, 2016

weblog/

The solid angle (aka generalized winding number) at a point lying on a surface can be defined to be the signed area of the surface of the mesh projected onto the unit sphere centered at that point.

For triangle meshes, we can always theoretically compute this as sum of the signed solid angles of each individual triangle. Since the point lies on the mesh, we should be careful about possible numerical pitfalls. In particular, we should ignore any (potentially erroneous) contribution from faces incident on the point. For example, if summing solid angles for the barycenter of some face f we should omit the contribution of f since we know its projection ought to be exactly zero: it projects to a curve on the sphere. Theoretically we only need to ignore contributions from faces intersecting the evaluation point, but one could play it safe and ignore each face for which the evaluation point lies on its plane.

If the mesh is a closed, embedded manifold then the solid angle is a local computation involving the dihedral angles of the incident faces.

For points in the middle of a face f (i.e., not at an edge or vertex), the solid angle is as the face's plane cuts the sphere in half. Anything projecting on the outside half must double-back on itself to cancel out since the surface is closed and embedded. For points along the middle of the edge between two faces f and g (i.e., not at a vertex) the solid angle is proportional to dihedral angle. The incident faces cut a wedge from the sphere with surface area (assuming Φ runs from 0 to . Finally, for the solid angle at a vertex, we can utilize the spherical excess formula, stating that the solid angle :

      N
Ω = ( ∑ Φi ) - (N-2)π
     i=1

Or using gptoolbox

[AD,C] = adjacency_dihedral_angle_matrix(V,F);
AF = AD~=0;
[AFI,~,AFV] = find(AF);
[~,~,CV] = find(C);
[ADI,~,ADV] = find(AD);
D = sparse( F(sub2ind(size(F),[ADI;ADI],mod([CV;CV+1],3)+1)), 1, 1*repmat(ADV,2,1),size(V,1),1)/2;
N = sparse(F,1,1,size(V,1),1);
SD = D - (N-2)*pi;

Pseudocoloring the solid angle per-vertex has an interesting effect: one can interpret the solid angle as a sort of cheap-o local ambient occlusion. Indeed it's revealing how much of the immediate surface is occluding any incoming light.

knight solid angle ambient occlusion

Of course it only works at edges and vertices (where there could be any curvature).