I base my algorithm on the view independent cell projection of Weiler,
Kraus, and Ertl [98,100]. Like the ever-popular
Projected Tetrahedra algorithm [86], view independent cell
projection is a projection-based algorithm that takes advantage of the
optimized rasterizing of graphics hardware. However, view independent cell
projection also takes advantage of programmable vertex hardware so that the
CPU no longer must transform points or classify tetrahedron projections. I
give an overview of this algorithm in
Section 1
starting on
page
.
I build on that review in this section by defining the procedures required.
I first give the procedure for projecting a single tetrahedron. Obviously,
it is the application's responsibility to loop over all tetrahedra and
render each one. A tetrahedron, by definition, has four triangular faces
and four vertices. I assume that each vertex has a scalar associated with
it. Furthermore, I assume that we interpolate the scalars linearly
throughout the tetrahedron. Given these assumptions, the scalar gradient
is constant.
Section 1
discusses how to compute this gradient on
page
.
Models sometimes define scalar data on a per-cell basis. In this case, all four vertices of the tetrahedron have the same scalar value and the gradient is the zero vector. We can optimize the procedures I give for this case, but the optimization is trivial and I will not discuss it. It is possible also for the model to define the scalars with arbitrary parametric functions (in so-called nonlinear cells). The current best method for rendering such cells is to decompose the nonlinear cells into linear pieces [42].
The VICP-ProjectTet procedure formalizes the part of the view independent cell projection algorithm that runs on the CPU.
The VICP-ProjectTet procedure is quite simple. By design, the VICP-ProjectTet procedure does little more than send data to the graphics card. The overhead of this part of the algorithm is not the amount of computation performed on the CPU, which is almost nothing, but rather the amount of data passed to the graphics card. All memory passing from the CPU to the GPU must pass through a bus, which often leads to a bottleneck. I therefore count how much memory VICP-ProjectTet transfers to the graphics card.
Although I show VICP-ProjectTet specifically sending begin and end triangle events in lines 3 and 9, respectively, we more commonly simply specify that every three vertices makes a triangle. Because the begin-triangle and end-triangle events are not specifically sent to the graphics hardware, I will not count them.
In line 8,
VICP-ProjectTet sends
to the graphics
card.
and
are scalars and thus require one component each.
and
are each 3-vectors. A plane equation such as
is often parameterized with four components, but Weiler, Kraus, and Ertl
[98] demonstrate how to parameterize it with only three
components. Therefore, assuming we represent all the components with
floating point values, each call to
line 8 passes 11 floats to
the graphics hardware.
Line 8 is called three
times per triangle, and there are four triangles per tetrahedron, so 132
floats are passed to the graphics hardware per tetrahedron in
all.8
The interesting calculations in view independent cell projection begin in
the vertex program. The vertex program, defined as VICP-VertexProg,
takes the parameters for a single vertex as input (as sent from
VICP-ProjectTet) and returns modified parameters that the
rasterizer interpolates.
VICP-VertexProg generates the vectors
and
. Each
entry in the
vector gives the distance, along the view vector, to
one of the opposite faces (an opposite face being one of the three faces of
the tetrahedron not being projected). Each entry in the
vector
gives the scalar value on the corresponding opposite face. Each vertex
touches three faces. One of the faces is the one being projected and is
not included in the
and
vectors. The other two faces
correspond to 0 entries in
and
entries in
.
Lines 3
and 4 initialize the two
vectors.
In line 6,
VICP-VertexProg computes the intersection of the viewing ray with
the one face not touching the vertex. The procedure
IntersectBackFace performs this intersection. It returns the
distance to the intersection and the scalar value at the intersection, both
of which are placed in the appropriate index of the
and
vectors. I do not specifically give the implementation of
IntersectBackFace, but Equations
1.3 and
1.4 in
Section 1
on page
provide the
mathematics for the operation.
The rasterizer interpolates the values of
and
across
the front face. In other words, the rasterizer is interpolating the
distance to and scalar value of viewing ray intersections to all potential
back faces. It is the job of the fragment program to pick the values for
the actual exit point.
VICP-FragmentProg picks the correct exit point by examining the distance to each face. Specifically, the correct exit point has a distance that is the minimum of all those greater than zero. Once it determines the correct exit point, VICP-FragmentProg needs only perform ray integration. I discuss ray integration in Chapter 1.