3 Holes, Cracks, Gaps and T-Junctions
Tải bản đầy đủ - 0trang
12.3 Holes, Cracks, Gaps, and T-junctions
485
t-junction
crack
gap
t-vertex
(a)
(b)
(c)
Figure 12.9 (a) A (nonhole) crack. (b) A gap. (c) A t-junction (and its corresponding t-vertex).
Several methods can be employed for detecting the presence of t-junctions. A
straightforward approach is to loop over all vertices of the mesh and for each vertex
test its connected edges, pairwise, for (near) collinearity. If two collinear edges are
found, the edges are part of a crack. The crack can be resolved by merging the endpoint
of one edge onto the other edge. Because vertices may be visited in any order, for
this approach to correctly resolve cracks that involve an arbitrary number of vertices
it is important that the endpoint vertices of the two merged edges be recursively
revisited after the merge to locate all vertices on the edge-chain of the crack. If the
mesh under repair is known to be 2-manifold, it is possible to limit the process
to examining only those edges that have exactly one face connected to them. This
method is simple to implement and it deals with all cracks correctly. However, it does
not address gaps, in that gaps by deﬁnition cannot be found by a local examination
of the geometry.
Resolving gaps correctly requires a more sophisticated, global method. Given an
edge, this method must be able to ﬁnd all mesh vertices lying on or nearly on the
edge. Alternatively, given a vertex the method must be able to locate all edges the
vertex is near. A practical solution is to insert all mesh edges into a hierarchical
structure like an hgrid or a loose octree, which can then be queried for each vertex
of the mesh.
As crack- or gap-induced t-junctions are found, they must be resolved. There are
three main approaches to resolving t-junctions (illustrated in Figure 12.10).
●
Vertex collapse. The t-vertex is displaced along the edge opposing it, toward either
endpoint of the edge, and collapsed with that endpoint.
●
Edge cracking. A more general solution is to split the edge opposing the t-vertex
in half and connect the two new endpoints to the t-vertex. This increases the
vertex count of all faces connected to the opposing edge by one.
486
Chapter 12 Geometrical Robustness
(a)
(b)
(c)
Figure 12.10 Three alternative methods for resolving a t-junction. (a) Collapsing the t-vertex
with a neighboring vertex on the opposing edge. (b) Cracking the opposing edge in two,
connecting the two new edge endpoints to the t-vertex. (c) Snapping the vertex onto the
opposing edge and inserting it, by edge cracking, into the edge.
●
Vertex snapping. Similar to edge cracking, this approach ﬁrst snaps the t-vertex
to lie on the opposing edge, after which the edge is cracked as in the previous
alternative.
Vertex collapsing is not applicable in all situations, but when it is it is often preferable
because it reduces the vertex count by one. It also effectively removes one edge from
one of the faces connected to the t-vertex and the vertex into which the t-vertex is
collapsed. When this face is a triangle, it becomes degenerate and can be removed.
Note that all three approaches can create nonplanar or nonconvex faces. Subsequent
triangulation of the involved faces may therefore be required.
When working with nonmanifold geometry, gaps may also appear as one face sits
slightly above another face; for example, a small face upright in the middle of a large
horizontal face (as shown in Figure 12.11). To resolve this, the second larger face must
be split up to incorporate the edge of the ﬁrst face. This face cracking can be handled
by the same hierarchical data structure used for edge cracking if mesh faces instead
of mesh edges are inserted into the data structure.
For some intersection queries, such as ray-versus-mesh tests, interpenetrating
surfaces do not pose a problem to the queries. If this is the case, the face cracking
12.4 Merging Co-planar Faces
(a)
487
(b)
Figure 12.11 (a) A face meeting another face edge-on, forming a gap. (b) The gap resolved
by face cracking.
does not have to be performed when the vertices of the edge lie in the negative
halfspace of the supporting plane of the other face.
12.4 Merging Co-planar Faces
Edge and face cracking may introduce a fair number of extra faces to the collision.
Because collision detection speed decreases as the number of faces increases, it is
worthwhile incorporating an optimization step into the generation of robust collision
geometry to help reduce the number of faces.
Many methods have been suggested for model simpliﬁcation. Thorough reviews
of the ﬁeld are given in [Luebke02] and [Puppo97]. For collision detection, it is
very important to preserve both shape and volume to prevent the collision geometry
from “shrinking”inside the visual representation, allowing objects to interpenetrate
visually even though they may not actually be touching in a collision sense. Out
of the huge library of simpliﬁcation methods, one approach particularly suitable for
collision detection geometry is that of merging (near) co-planar faces. Face merging also helps to remove sliver-like and other degenerate faces, which are usually a
source of robustness problems (see Chapter 11).
In addition to two faces being co-planar up to some given tolerance, some other
criteria generally must be fulﬁlled for two faces to be mergeable. Speciﬁcally, the faces
must:
●
both be either double or single sided, and face in the same general direction
when single sided,
●
have the same associated surface properties (footstep sounds, friction attributes,
or similar attributes), and
●
share one or more boundary edges.
488
Chapter 12 Geometrical Robustness
In this text, when two or more faces are said to be co-planar it is assumed that the
faces are mergeable under these criteria.
Because the result of preprocessing is likely a triangle or quad mesh, one alternative
is to merge two or more co-planar faces as long as the resulting face is a triangle or
a quad. This straightforward approach is simple to implement. However, for it to
produce a near-optimal result large clusters of faces would have to be considered for
simultaneous merging. For example, for the spiral-like mesh given in Figure 12.12 no
combination of faces other than all nine faces together form a convex face. Thus, a
combinatorial number of face combinations would have to be tested for merging in
the worst case, which is impractical.
A more involved method, but which promises much better results, is to merge all
co-planar neighboring faces into a single (concave) polygon in a ﬁrst pass. In a subsequent second pass, these polygons are then triangulated or otherwise decomposed
into the type of convex pieces desired for the end result.
If adjacency information is available, it is straightforward to merge neighboring
co-planar faces simply by visiting neighboring faces through the provided adjacency
links. For example, given an edge-face table the merging process is linear in the
number of edges, proceeding by looping over the edges and merging the faces connected to the edge if co-planar. If no adjacency information is available, instead of
ﬁrst computing adjacency information and then proceeding as described previously
an alternative option is to ﬁnd nearly co-planar faces through a scheme similar to
environment cube mapping [Akenine-Möller02].
Figure 12.12 If two (or more) faces are only considered for merging when the resulting face
is convex, no merging can be done for this spiral-like mesh. If concave faces are allowed
during merging, this mesh can be merged into a single (quadrilateral) face.
12.4 Merging Co-planar Faces
489
c
c1
c2
n
n±e
(a)
(b)
Figure 12.13 (a) The normal n hits cell c (dashed) on the top face of the cube inscribed in
the unit sphere. (b) The perturbed normal n ± e hits cells c1 and c2 . The contents of these
cells must be tested for co-planarity with the polygon having the normal n.
Each polygon normal can be seen as describing a position of the surface of the
unit sphere. Let a cube be inscribed in the unit sphere, each cube face divided into a
number of cells of a ﬁxed uniform size. Each polygon normal will intersect some cube
face cell (Figure 12.13a). Let polygons be associated with the face cell their normals
intersect.
Near co-planar polygons will now largely map to the same cell, allowing them to
be further processed after their co-planarity has been veriﬁed. However, due to the
arbitrary discretization into cells, two plane normals arbitrarily close may still end up
in different cells. A simple solution to this problem is to test all eight neighboring
face cells of the cell the polygon normal intersected. Some care must be taken near
the cube edges to make sure the correct cells are visited.
To cut down on the number of neighboring cells to test, the polygon normal n can
be perturbed slightly in the plane of the intersected face, giving a rectangular region
in the face, describing the area for which normals would be considered coplanar to
n. All cells overlapped by the rectangular region would then be tested, similar to
before (Figure 12.13b). Typically, the number of cells overlapped by this region would
be smaller than eight. Again, care must be taken to visit the correct cells when the
rectangular region extends over a cube edge.
The presented method has an expected complexity of O(n). An alternative but
less efﬁcient O(n log n) tree-based sorting method is given in [Salesin92]. Alternative solutions to the problem of merging (near) co-planar faces are presented in
[Hinker93] and [Kalvin96].
12.4.1 Testing Co-planarity of Two Polygons
One approach to testing if two polygons are co-planar is to compute the angle
between their plane normals. If the angle is less than some given tolerance, the
490
Chapter 12 Geometrical Robustness
polygons are considered co-planar and can be merged. This method works for many
applications, such as general model simpliﬁcation [Hinker93]. However, for collision
detection purposes this approach is fundamentally ﬂawed. Consider two polygons,
A1 and B1 , at a ﬁxed angle θ to each other, requiring a plane thickness of d1 of
a representative plane for all vertices to be included in the plane, as illustrated in
Figure 12.14. Let the polygons be scaled up in size, giving A2 and B2 . Even though θ
remains constant, the required thickness d2 of the new representative plane increases
without bound as the polygons are scaled up in size.
Clearly, the angle between the polygon normals is only a relative measurement of
the co-planarity of the polygons. For an absolute error measurement, the thickness
of the representative plane must be considered. A better solution to testing two
polygons for co-planarity is therefore to perform the merging of the two polygons,
conceptually, and see if the resulting polygon is considered planar by a polygon
planarity test (presented in the next section). This approach directly extends to the
merging of an arbitrary number of polygons.
To use a relative measurement of co-planarity for controlling merging of polygons
for use with a collision detection system, the vertices of the merged polygons must be
snapped to the representative plane of the merged polygon. This bounds the deviation
of the polygon vertices from the plane, allowing the distance error to remain less than
the tolerance value used to enforce thickness of the polygon for robust intersection
tests.
However, with welded vertices snapping the vertices of one or more polygons to a
representative plane inevitably introduces nonplanarity errors in faces sharing vertices
with these polygons. Trying to address this would likely cause a ripple effect involving
all vertices of the object. A reasonable solution is to let a subsequent triangulation
pass take care of triangulating any faces that have been made more nonplanar than
the given tolerance allows. Unfortunately, nothing guarantees that there are not more
faces created during this triangulation than are removed through the initial merging
process!
A1
A2
B1
d1
B2
d2
Figure 12.14 Testing the angle between the normals of the planes of two polygons is a
relative measurement of their co-planarity, unaffected by scaling up the polygons. Testing
the thickness required for the best-ﬁt plane to contain all polygon vertices is an absolute
measurement of the co-planarity of the polygons.
12.4 Merging Co-planar Faces
491
Figure 12.15 The upper illustration shows how an absolute merging tolerance smaller than
the plane thickness tolerance (in gray) avoids cracks from appearing between neighboring
faces. The lower illustration shows how a crack may appear when the merging tolerance
exceeds the plane thickness tolerance.
Worse, if vertices are unwelded and are allowed to move during merging cracks can
appear at the edges between neighboring faces unless the absolute merging tolerance
is kept smaller than the plane thickness tolerance. Figure 12.15 illustrates how a crack
may appear between a face and a merged face when the merging tolerance exceeds
the plane thickness tolerance. To avoid tolerance issues that would cause robustness
problems and to guarantee the reduction of faces due to merging, it is important
to use an absolute error measurement for merging geometry for use with collision
detection.
12.4.2 Testing Polygon Planarity
A polygon is deﬁned by a set of vertices in the plane. Testing the polygon for planarity
then involves making sure all deﬁning vertices lie in a plane. This can be done by
computing a plane equation for the supporting plane of the polygon and then testing
all vertices to make sure they are within some tolerance of the plane. The plane
equation for the supporting plane is obtained through computing a polygon normal
and selecting a reference point on the polygon.
This sounds simple enough, but there is a hidden subtlety: how to compute the
polygon normal n = (nx , ny , nz ). A ﬁrst approach to computing the polygon normal might involve computing the cross product of two coincident polygon edges.
However, this is not robust because the edges may be (near) collinear, causing the
492
Chapter 12 Geometrical Robustness
cross product result to be the zero vector (and making the computation suffer large
cancellation errors well before becoming zero).
Even if the angle between the edges is large, there is still a problem. Assume all
vertices lie on a plane, except for the vertex V shared by the two edges. Let V deviate
from the plane by some distance d. If the polygon is scaled up in the plane, V will
remain at a distance d from the plane and the absolute planarity of the polygon
should not be affected. However, because the cross product of those two edges was
chosen as the representative plane normal, all vertices but the three coincident with
the two edges will move arbitrarily far from the chosen plane as the polygon is
scaled up.
It seems clear that all vertices should somehow be involved in the normal computation. One common approach is to compute the normal ni at each vertex Vi
(as the cross product of the edges incident at the vertex) and then average the
normals:
n=
1
n
ni ,
where ni = (Vi+1 − Vi ) × (Vi−1 − Vi ).
0≤i
It is here assumed that Vn = V0 and V−1 = Vn−1 . Because the magnitude of n is
unimportant, the normals can be summed rather than averaged.
Although this works well for convex polygons, it is unfortunately ﬂawed for nonconvex polygons. Normals computed at concave vertices will point in the opposite
direction of those computed at convex vertices. For example, consider the class of
star-shaped polygons shown in Figure 12.16. The normals at the even-numbered
vertices point out of the page, whereas the normals of the odd-numbered vertices
point into the page.
K=1
K=4
V0 = (1, 1, 1)
V1 = (6, 6 – K, 1)
V2 = (11, 1, 1)
V3 = (6 + K, 6, 1)
V4 = (11, 11, 1)
V5 = (6, 6 + K, 1)
V6 = (1, 11, 1)
V7 = (6 – K, 6, 1)
Figure 12.16 A class of star-shaped polygons, parameterized by K, 0 < K < 5.
12.4 Merging Co-planar Faces
493
When normals of opposing direction are summed, the result may point in either
direction, depending on the relative magnitudes of the inputs. Speciﬁcally, in this case
the following (unnormalized) normals are obtained for a few different values of K:
K
n
1
(0, 0, −124)
2
(0, 0, −56)
3
(0, 0, 4)
4
(0, 0, 56)
As the table indicates, the normal changes direction between K = 2 and K = 3.
In fact, at about K = 2. 928932 the normal becomes the zero vector and the method
fails catastrophically!
It turns out that a much better and robust approach to computing normals is one
commonly known as Newell’s method [Tampieri92]. Newell’s method uses the fact
that the components of a polygon normal are proportional to the signed areas of
the projections of the polygon onto the yz, xz, and xy planes. n can therefore be
computed as:
nx =
(Vi,y − Vi+1,y )(Vi,z + Vi+1,z )
0≤i
ny =
(Vi,z − Vi+1,z )(Vi,x + Vi+1,x )
0≤i
nz =
(Vi,x − Vi+1,x )(Vi,y + Vi+1,y )
0≤i
The terms being summed correspond to twice the signed area of the trapezoids
formed, in each principal plane, by the current polygon edge and its projection onto
the corresponding axis. The ﬁrst term is the width of the trapezoid; the second term
is twice its height. By rearranging terms, it can be seen that Newell’s method is
equivalent to computing the normal through the sum:
n=
mi ,
0≤i
where mi = Vi × Vi+1 .
494
Chapter 12 Geometrical Robustness
For the star-shaped polygon used earlier, Newell’s method consistently produces
the expected normal (pointing out of the page):
K
n
1
(0, 0, 40)
2
(0, 0, 80)
3
(0, 0, 120)
4
(0, 0, 160)
The following code illustrates how Newell’s method can be implemented to compute a robust representative plane for a polygon. Here, the polygon centroid — that
is, the average of all vertices — is used as the representative point on the plane when
computing the plane equation.
// Given n-gon specified by points v[], compute a good representative plane p
void NewellPlane(int n, Point v[], Plane *p)
{
// Compute normal as being proportional to projected areas of polygon onto the yz,
// xz, and xy planes. Also compute centroid as representative point on the plane
Vector centroid(0.0f, 0.0f, 0.0f), normal(0.0f, 0.0f, 0.0f);
for (int i = n - 1, j = 0; j < n; i = j, j++) {
normal.x += (v[i].y - v[j].y) * (v[i].z + v[j].z); // projection on yz
normal.y += (v[i].z - v[j].z) * (v[i].x + v[j].x); // projection on xz
normal.z += (v[i].x - v[j].x) * (v[i].y + v[j].y); // projection on xy
centroid += v[j];
}
// Normalize normal and fill in the plane equation fields
p->n = Normalize(normal);
p->d = Dot(centroid, p->n) / n; // “centroid / n” is the true centroid point
}
Newell’s method can be seen as computing a “best-ﬁt” plane, using all vertices.
Yet another alternative approach is to ﬁt a plane to the polygon vertices using the
method of least-squares ﬁt (see [Eberly01] for details).
Computing plane equations using Newell’s method is clearly more expensive than
just taking the cross product of two coincident edges. Storing plane equations with
the polygons is one option, but this is unattractive memory-wise. A compromise is
still computing normals and plane equations at runtime using a cross product, but
after having made sure the polygon is output so that the ﬁrst three stored vertices of
12.5 Triangulation and Convex Partitioning
495
the polygon give the best representative result. It is also possible to simplify Newell’s
method for speciﬁc primitives. For example, given a quadrilateral ABCD the normal
obtained by Newell’s method can be reduced to that of computing the cross product
of the two diagonals AC and DB because
2(AC × DB) = (AB × AD) + (BC × BA) + (CD × CB) + (DA × DC).
The right-hand side of the expression corresponds to the summing of the cross
product normals at each vertex. Interestingly, it is thus actually cheaper to compute
a robust normal for a quadrilateral than it is to do the same for a triangle!
After having computed a good representative plane for a polygon, it is ﬁnally
possible to test the planarity of the polygon by putting each of its vertices, in turn,
through the computed plane equation to see by how much each vertex deviates from
the plane. If they are all within a preset tolerance distance from the plane, the polygon
is considered planar. An implementation of this test follows.
// Test if n-gon specified by vertices v[] is planar
int IsPlanar(int n, Point v[])
{
// Compute a representative plane for the polygon
Plane p;
NewellPlane(n, v, &p);
// Test each vertex to see if it is farther from plane than allowed max distance
for (int i = 0; i < n; i++) {
float dist = Dot(p.n, v[i]) - p.d;
if (Abs(dist) > PLANARITY_EPSILON) return 0;
}
// All points passed distance test, so polygon is considered planar
return 1;
}
In [Sunday02], the author addresses how to reduce the number of arithmetic
operations needed to compute Newell normals and polygon areas.
12.5 Triangulation and Convex Partitioning
Although it would be possible to perform collision detection directly against the
merged faces, tests involving convex faces only are often simpler, faster, and more
robust. It therefore makes sense to decompose nonconvex faces into two or more
convex pieces, a process known as convex partitioning. One alternative is simply to