GPU-Accelerated Adaptively Sampled Distance Fields ... Department of Computer Science, PUC-Rio, Brazil .... varying degrees of complexity and efficiency.
GPU-Accelerated Adaptively Sampled Distance Fields Thiago Bastos Waldemar Celes TecGraf – Computer Graphics Technology Group Department of Computer Science, PUC-Rio, Brazil {tbastos, celes}@tecgraf.puc-rio.br
Abstract Adaptively Sampled Distance Fields (ADFs) are a volumetric shape representation that supports a broad range of applications within the areas of computer graphics, computer vision and physics. ADFs are specially advantageous for representing shapes with features at very diverse scales. In this paper, we propose a strategy to represent and reconstruct ADFs on modern graphics hardware (GPUs). We employ a 3D hashing scheme to store the underlying data structure and try to balance the tradeoff between memory requirements and reconstruction efficiency. To render ADFs on the GPU, we use a technique based on sphere tracing, which guarantees the reconstruction of fine details. We also present a way to overcome the C 1 discontinuities inherent to ADFs and efficiently reconstruct smooth surface normals across cell boundaries. The effectiveness of our proposal is demonstrated for isosurface rendering and morphing.
1. Introduction Given a set of solid objects in the 3D Euclidean space, a continuous distance field determines the distance from an arbitrary point to the closest point on the surface of any object in the represented set. A signed distance field is even more effective because the sign denotes whether a point is inside or outside of an object. Given a signed distance field, several properties can be derived. The surface of the represented objects are implicitly defined by the set of points where the value of the distance field is zero. For points on the surface, the gradient of the distance field yields the surface normal, while for points off the surface the gradient yields the direction to the closest surface point. Applications such as rendering, morphing, surface offsetting, collision detection, and path planning can all benefit from such a representation. In this paper, we aim at interactive applications and focus on the reconstruction of signed distance fields on modern GPUs.
Since continuous distance fields of arbitrary shapes are difficult to represent, a discrete representation is generally employed. Discrete distance fields store distance samples at a finite set of points and, from these samples, reconstruct the distance at any other given point. The simplest strategy to represent discrete distance fields is to use regularly sampled distance fields stored in regular voxel grids. Due to their simplicity, regularly sampled distance fields are at first good candidates for GPU-based applications. However, such models require large amounts of memory and their resolution is limited by the sampling rate [4]. To represent shapes with features at very diverse scales, a more interesting approach is the use of adaptively sampled distance fields (ADFs), as proposed by Frisken et al. [5]. ADFs use high sampling rates in regions where the distance field contains fine detail, and low sampling rates where the field varies smoothly, allowing both efficient memory usage and arbitrary accuracy in the reconstructed field. The original ADF as introduced by Frisken et al. [5] stores distance samples at cell vertices of an octree and uses trilinear interpolation for distance reconstruction and gradient estimation. Reportedly, this approach is both simple and efficient and, as we shall demonstrate, can be effectively implemented on GPUs. In this paper, we propose a strategy to represent and reconstruct ADFs on modern GPUs. We narrow the scope to static ADFs, focusing on efficient support for interactive applications. The effectiveness of our proposal is demonstrated for isosurface rendering, yet our model is generic enough to support applications such as proximity detection, volume rendering, hypertexturing and others [8]. We also propose an approach to work around the C 1 discontinuities of ADFs and reconstruct smooth surface normals. Figure 1 illustrates some of the achieved results: (a) shows a sparse level-8 ADF octree; in (b) the surface of the model is colored to reveal the hierarchical level of the cells used for reconstruction, thus emphasizing the advantage of adaptive sampling rates; (c) shows the model rendered using celllocalized gradient estimations; and (d) shows the model rendered using our method to reconstruct smooth normals.
Cell Level 5 6 7 8 (a) The underlying octree;
(b) color-coded surface showing the level of the cells used for reconstruction;
(c) model rendered with Phong shading using the standard ADF estimation of normals;
(d) model rendered using our approach to reconstruct smooth normals.
Figure 1. GPU-based rendering of a level-8 ADF generated from a mesh of the statue of Eros. The main contributions of this paper are the following: • a hash-based approach to represent and efficiently reconstruct ADFs on the GPU; • a technique to render ADFs, based on sphere tracing, which guarantees the reconstruction of fine details and is less sensitive to octree complexity; • an efficient way to overcome the C 1 discontinuities present in the original ADFs and render smoothly shaded isosurfaces. The next section discusses related work and provides further background on ADFs. Section 3 describes our method to represent and reconstruct ADFs on the GPU. In Section 4 we present a technique to render ADFs with sphere tracing and smooth surface normals. We depict some applications and show the achieved results in Section 5. Finally, in Section 6 we draw concluding remarks.
2. Background and related work ADFs, as introduced by Frisken et al. [5], store distance samples at cell vertices of an octree and use trilinear interpolation for distance reconstruction and gradient estimation. Given a distance function, an ADF may be constructed using either a bottom-up or a top-down approach. The bottom-up approach starts with a complete octree and then tries to discard cells upwards whenever a block of eight children is unnecessary to guarantee the prescribed reconstruction accuracy. The top-down approach starts with a root cell and then recursively subdivides the octree while the reconstruction error within the cells is larger than the prescribed reconstruction accuracy. The resulting octrees are full by construction, i.e. all cells have either zero or eight children. For maximum precision the distance field is reconstructed at leaf cells, but higher-level cells can be used
when a coarser level of detail is acceptable. ADFs contain C 0 discontinuities where cells of different size abut, and C 1 discontinuities at cell boundaries. Frisken et al. argue [5] that cracks due to C 0 discontinuity are easy to workaround for most applications, and that C 1 discontinuities are not noticeable with sufficient subdivision, though this may impose a prohibitive memory cost. Bærentzen [2] proposed a scheme very similar to ADFs and brought two contributions that are worth mentioning. First, in order to eliminate redundant sample data, he opted for decoupling the storage of cells from the storage of samples: the octree is represented with pointers, as usual, but distance values are stored in a 3D hash table indexed by vertex position. This approach completely eliminates redundancy in ADFs, at the cost of eight hash lookups (instead of direct memory accesses) for retrieving cell data. Bærentzen also questioned the use of cell-localized gradient estimations to compute surface normals, since shading discontinuities are unavoidable when zooming-in (as shown in Figure 1c). He proposed a method to reconstruct smooth surface normals: gradients are computed at cell corners using the closest neighboring voxels, and then estimated within cells using trilinear interpolation. Although conceptually simple, this method is expensive as it requires 48 nearest-voxel searches per reconstructed gradient. ADFs can be of two different kinds [4]: complete and superficial. A complete ADF guarantees the reconstruction of a distance field within a prescribed accuracy at all points of its domain. When only the reconstruction of a specific isosurface is needed, one can devise a more memoryefficient ADF by discarding cells that do not intersect the isosurface. In this case the ADF is superficial, and reconstruction accuracy is guaranteed only at points close to the isosurface of interest. Comparatively, complete ADFs have denser octrees and require more memory, while superficial ADFs have sparser octrees but limited applicability. For instance, superficial ADFs are sufficient for
surface rendering, collision detection and CSG operations, but applications such as morphing, surface offsetting and path planning require complete ADFs. There are three basic approaches for rendering ADFs, as described in [12]: ray-casting, point-based rendering and tessellation. Ray-casting is expensive, but it supports many applications and usually offers the best rendering quality. Point-based rendering is very fast, but it offers the poorest quality. The triangulation technique presented by Perry and Frisken [12] balances performance and rendering quality, but is improper for applications such as morphing. In this work, we exploit the parallel architecture of GPUs to implement a fast, general-purpose renderer based on raycasting. GPU ray-casting has been used in several works for rendering implicit surfaces [14, 10, 6]. Particularly, in [6] the authors use a two-level hierarchical grid structure to represent a regularly sampled distance field, and render isosurfaces on the GPU using advanced shading techniques.
3. Representing ADFs on the GPU The original ADF structure [12, 8] consisted of a pointerbased octree with eight stored voxels per cell, each voxel corresponding to a distance sample taken at one of the cell’s corners. This approach has two major problems: 1. since octree vertices are generally shared by many cells, the structure contains a lot of redundancy; 2. traversing pointer-based octrees on the GPU is both complex and inefficient. Because GPUs lack recursion and scattering operations, stack-based traversals are unfeasible; and if they were not, performance would suffer due to the lack of coherence. In the following sections we shall see how these problems can be addressed in order to take full advantage of the GPU’s massive parallel processing power.
3.1. The voxel texture Voxel replication may cause minimally complex ADFs to exceed the memory capacity of modern GPUs. To control it we must decouple the storage of voxels from the octree. There are several approaches to this problem, each with varying degrees of complexity and efficiency. A very simple solution that eliminates all redundancy has been suggested by Bærentzen [2]: to use a 3D hash to store the voxels indexed by position. Unfortunately the cost of eight hash lookups per reconstructed cell is too great to bear. Since the access to voxels plays a crucial part in the performance of the system, it must be trivial and coherent. An alternative approach is to store voxels into a separate texture and have the cells hold pointers to their voxels.
7
14
11
12
(0, 3) 4
8
(1, 4)
(0, 4)
13
10
5
9
Voxel Texture
17
11 12 13 13 16 17 4 10 5
5 15 6
6
7
8
9
-
-
-
4
5
6
-
-
-
1
2
3
-
-
-
(4, 4) 16
(3, 3)
(1, 3)
7 14 8
(4, 3) 15
(1, 0)
(0, 0) 1
18
(3, 4)
2
3
8 18 9
First appearance of a voxel. Replicated voxel.
Figure 2. A quadtree and its voxel texture.
This may sound like an obvious solution, but in fact it is very difficult to pack all voxels into a tight texture without replication. Naturally, it makes no sense to store eight pointers per cell, as that would take roughly the same amount of memory as storing eight distance samples. Voxels belonging to the same cell must be organized in blocks, so that cells can store only one pointer – to their voxel block – instead of eight. Ultimately, our goals are to: i) pack voxels into a compact, one-component floatingpoint 3D texture; ii) guarantee that voxels belonging to the same cell are adjacent in a 2x2x2 block; iii) minimize voxel replication by packing neighboring voxels together whenever possible. The construction of this voxel texture is a non-trivial task. Although packing algorithms based on heuristics often yield results with little redundancy, the optimal solution is known to be a NP-hard problem. For simplicity, our current solution only eliminates voxel replication between sibling cells. This is done by taking every group of eight sibling cells and storing their voxels in 3x3x3 blocks. Since ADF octrees are full trees, all cells but the root cell belong to a group of eight sibs. Redundancies still remain among adjacent blocks (e.g. cousin cells) and descendant cells, but this simple solution considerably reduces the amount of redundant voxels and is enough to allow reasonably complex ADFs to fit in video memory. Moreover, since cell voxels are organized in blocks, we can exploit the GPU’s native texture-filtering capabilities to obtain trilinearly interpolated distance values virtually for free. Figure 2 illustrates this solution in 2D, with a quadtree on the left and its corresponding voxel texture on the right. Voxels are numbered from one to eighteen and replicated voxels are shaded in gray. At each cell, the position of the corresponding voxel block is indicated within parentheses.
3.2. Hash-based octrees
S(ℓ, p)
ADF octrees are typically implemented with pointers. However, on GPU architectures, traversing pointer-based octrees is generally complex and inefficient. To overcome these limitations we devised an octree representation that enables random access to cells: given an octree level ` and a point p, the level-` cell containing p can be accessed in constant time. This representation allows for stackless traversals of the octree and improved coherence. Our approach is based on the idea of implicitly defining an octree in a 3D texture. Similarly to how a complete binary tree can be implicitly represented in a 1D array, a complete octree can be implicitly represented in a 3D array. It is possible then to formulate a function that computes in O (1) time the position of a given cell within the 3D array. Evidently we cannot afford to represent ADFs with complete octrees, since ADFs are inherently sparse and complete octrees require exponential space in the octree depth. Therefore we use a 3D hash structure to compress the sparse 3D array where the implicit octree is defined. 3 Given a complete octree on the cube C = [0, 1) , an octree level ` and a point p ∈ C, the function S (`, p) = 2` + 2` p (1) yields the 3D index of the level-` cell containing p, and thus implicitly defines the octree in the 3D array U h i3 U = 1, 2(sup `+1) − 1 (2) A hash-based octree follows from combining the function S (`, p) with a 3D hash function H (k ∈ U ). The access to any cell is done by first using S (`, p) to generate a cell key, and then using H (k) to check if the cell really exists and to obtain its position. Since S (`, p) is O (1), the access to any cell is done in constant time if H (k) is also O (1). Figure 3 illustrates the steps required to access voxels at the vertices of an octree cell. First, function S (`, p) generates a key k ∈ U for the level-` cell containing p. This key is passed to the 3D hash function H (k), which uses an auxiliary “hash texture” to compute the cell’s position in the tightly packed “cell texture”. From the cell’s texel we obtain the position v of the cell’s voxel block. Finally, access to voxels is represented by the function A (v). Given a current position p and a current level ` within the octree, we may either: a) move to an adjacent cell, by adding ±2−` to one or more components of p; or b) ascend or descend the hierarchy by decrementing or incrementing `, respectively. For instance, S `, p + (−2−` , 0, 0)
yields the key for the cell on the left of the current cell.
k
Domain U
Hash Texture
Voxel Texture
q
H(k)
v Cell Texture
A(v) A(H(S(ℓ, p)))
Figure 3. Access to voxels at the vertices of a hash-based octree cell (represented in 2D).
3.3. GPU spatial hashing The efficiency of a hash-based octree is defined by its 3D hashing scheme. Unfortunately, traditional hashing techniques are inappropriate for massively parallel SIMD architectures such as the GPU. Lefebvre and Hoppe [9] pointed out that hashing algorithms typically resolve collisions by performing a sequence of probes into the hash table, where the number of probes varies per query. This is inefficient, as SIMD parallelism makes data (e.g. pixels) in the same block wait for the worst-case number of probes. To take full advantage of SIMD parallelism, all hash lookups should perform the same number of probes. We have achieved this by using a perfect hash function based on the scheme proposed in [9]. Our hash function H (k) is thus precomputed for a static set of octree cells to have no collision. It takes only a fixed number of operations and a single access to the “hash texture” (Figure 3). However, in this scheme the hash function does not check if the input key is valid. If the key does not correspond to an existing cell, a “random” cell is returned. In order to check if the returned cell is really the cell being looked for, we store 32-bit cell identifiers alongside cell data in the “cell texture”.
3.4. Reconstruction The first step in order to reconstruct the distance field at a given point p is to find the smallest octree cell containing p. Once this cell is found, reconstructing a distance value is a matter of trilinearly interpolating the cell voxels. This can be done by GPU at virtually no cost if linear filtering is enabled for the voxel texture. The following algorithm performs a na¨ıve linear search for the smallest cell containing p. Notice that it does not take advantage of random access to octree cells. function QUERY(p) . find the smallest cell containing p v←∅ . pointer to the voxel block of the smallest cell
for ` ← 0, ∞ do . descend the octree from the root k ← S(`, p) . key for the level-` cell containing p v0 ← H(k) . access the cell if id(v0 ) = id(k) then . check if the cell exists break . stop if there is no cell end if v ← v0 . keep track of the smallest cell end for return v . return the voxel block of the smallest cell end function
We have experimented with a few other search strategies, such as binary search. However, as ADF octrees are usually no deeper than 12 levels, we found the best strategy is to use a linear search with coherence. For instance, a ray-casting algorithm that samples the distance field at many points along a ray may keep track of the ` value used by the last query and resume the next query from that level. For raycasting we found this strategy yields a speedup of roughly 30% over the na¨ıve linear search algorithm. GLSL code for the query with coherence is provided in the appendix.
4. Rendering ADFs on the GPU We build on the framework described in Section 3 to develop a fragment program for rendering ADF isosurfaces directly on the GPU. Our ray-casting technique is based on sphere tracing [7], an iterative algorithm naturally suited for traversing signed distance fields. Sphere tracing uses the distance field to march along the ray in steps guaranteed not to penetrate the isosurface. A ray is assumed to intersect the surface when it finds a distance value smaller than a predefined tolerance . Otherwise, the algorithm stops when the ray leaves the ADF’s axisaligned bounding box (AABB). Convergence is generally fast, except for rays that pass close to the edges of the surface (see Figure 4). The use of sphere tracing demands
rigorous control of the reconstruction error of the distance field, since large errors may cause rays to miss the surface.
4.1. Sphere tracing for complete ADFs Sphere tracing works as long as the intersection tolerance is greater than the reconstruction error of the distance field. Generally this is not a problem for complete ADFs, since they guarantee an absolute upper bound on the error. The following is pseudo-code for our sphere tracing algorithm. A ray is defined by an origin r0 and a direction rd . The scalar c corresponds to the isovalue of the surface that should be drawn, and is the intersection tolerance. function CAST RAY(r0 , rd , c, ) (tnear , tf ar ) ← INTERSECT AABB(r0 , rd ) t ← tnear `←1 p ← r0 + trd while t < tf ar do (v, `) ← QUERY(`, p) d ← GET DISTANCE(v, p) −c if d < then . has the ray hit the isosurface? n ← GET NORMAL(v, p) return SHADE(p, n, −rd ) end if t←t+d . step along the ray p ← r0 + trd end while discard . ray does not intersect the isosurface end function
Notice that this function explores spatial coherence along the ray, since queries resume from the level they stopped at in the previous iteration. Once the ray hits the surface, a normal is reconstructed and the surface is lit using Phong shading. The actual implementation of this algorithm is in GLSL (see the appendix). It is used in a fragment program that is triggered by drawing the ADF’s AABB.
4.2. Sphere tracing for superficial ADFs
Figure 4. Sphere tracing: rays close to the edges require many more iterations.
In contrast with complete ADFs, a superficial ADF does not provide an upper bound on error for points outside the cells that intersect its isosurface. Points far-off the surface, especially those close to the faces of the ADF’s AABB, contain large amounts of error. Therefore sphere tracing is always exposed to large errors at the first iterations. We propose a simple change to superficial ADFs which keeps most of their efficiency while adding error bounds for all points. During construction, a cell that does not intersect the isosurface of interest is discarded only if the reconstruction error of its parent is smaller than a percentage of the smallest distance stored at its voxels. This ensures that the reconstruction error is proportional to the reconstructed distance. Our current implementation uses an
error tolerance of 10%. This results in an increase of about 25% in the number of cells, which is still only a fraction compared to the size of complete ADFs. Sphere tracing will work in this scenario if distances are scaled down to a safety margin. For instance, to cope with errors of up to 10% we must scale reconstructed distances by 90%. This is illustrated in Figure 4: actual reconstructed distances are represented by dashed circles, while the distances used to step along the ray are represented by solid circles. Using this solution, our results show a loss of almost 15% in frame rate, but no noticeable difference in image quality when compared to complete ADFs.
4.3. Solving shading discontinuities ADFs have two sources of discontinuities: cracks arise where cells of different size abut [12], while the use of trilinear reconstruction results in C 1 discontinuities at cell boundaries. In order to efficiently render smoothly shaded surfaces, we store precomputed smooth normals in a second voxel texture. Normals are encoded in 24-bit, resulting in an increase of 75% in memory usage. Then again, normals can be reconstructed using trilinear interpolation, which is faster than estimating cell-localized gradients. The construction of the normal texture takes place in a preprocessing phase. In a first step, normals are estimated at cell vertices using the closest neighboring distance samples, as shown in Figure 5a. Then, in a second step, a top-down breadth-first traversal of the octree re-estimates normals laying on the edges and faces of leaf cells. This is required to smooth the transition between normals of different levels. Re-estimation consists in linearly interpolating the normals based on those of the leaf cell, as illustrated in Figure 5b.
75% 50%
(a) the central normal is computed from the voxels marked with solid circles, using central differences;
25%
50%
(b) normals at marked positions are re-estimated by interpolating the normals of the leaf cells;
Figure 5. Construction of the normal texture.
5. Results We next demonstrate a couple of simple GPU programs that render ADFs using the techniques described in this paper. All results are obtained at a resolution of 5122 using OpenGL 2.1 and an NVIDIA GeForce 8800 GTX 768MB. ADFs are generated from closed 2-manifold triangle meshes. Distances are calculated using two approaches: an exact method based on kd-trees is used to generate complete ADFs, while a faster method based on distance transforms [13] is used for superficial ADFs. Signs are determined using angle-weighted pseudo-normals [1]. Rendering of solid shapes. One of the simplest uses of our system is to render solid shapes, implicitly represented as the zero-valued isosurfaces of an ADF. As an example, Figure 6 shows the Stanford Thai Statue, rendered on the GPU, with smooth normals, from a level-9 superficial ADF.
Figure 6. GPU rendering of the Thai Statue. Quantitative results for the ADFs depicted in this paper are shown in Table 1. The columns entitled “maximum depth” and “maximum error” indicate the parameters used to generate the ADF. The resulting number of cells and the dimensions of the voxel texture are presented in the following columns. Generation time (in seconds) is the sum of the times taken to: i) generate an ADF from the mesh model; ii) compute a smooth normal texture; iii) pack the voxel texture; and iv) generate a perfect hash function for the octree. The last column displays the average frame rate obtained when rendering the zero-valued isosurface of the model with the techniques described in Section 4. In all cases, we have used an intersection tolerance of 10−3 and limited sphere tracing to 64 iterations. Surface offsetting. Distance volumes are commonly used to compute offset surfaces. Complete ADFs provide high accuracy for this kind of application, and our ray-casting algorithm can trivially render offset surfaces through simple manipulation of the isovalue variable (see Figure 7).
Model
Fig.
Triangles
Eros
1
394K
Thai Statue
6
10M
Armadillo
7
346K
Ramses
8
387K
Red Circular Box
9
361K
Magali’s Hand
9
397K
Kind of ADF complete superficial complete superficial complete complete superficial complete complete superficial
Max. Depth 8 9 8 9 8 8 9 8 8 9
Maximum Error 10−4
3× 1 × 10−4 3 × 10−4 1 × 10−4 3 × 10−4 3 × 10−4 1 × 10−4 3 × 10−4 3 × 10−4 1 × 10−4
Num. of Cells 187,297 400,997 187,448 319,669 489,315 246,661 214,712 740,718 235,906 282,673
Voxel Tex. Dimensions 1712
× 174 2223 2 171 × 174 204 × 2072 2373 1893 1803 270 × 2732 1863 1982 × 195
Generation Time (sec) 790 479 21442 738 562 686 428 774 1101 431
Frame rate 76 Hz 68 Hz 108 Hz 92 Hz 76 Hz 104 Hz 89 Hz 71 Hz 95 Hz 82 Hz
Table 1. Quantitative results for GPU-accelerated ADFs.
Negative Isovalue
Zero
Positive Isovalue
Figure 7. Isosurfaces of the Armadillo model. Level 5
Level 6
Level 7
Level 8
Figure 8. Ramses at four levels of detail.
Levels of detail. A simple approach to levels of detail in ADFs consists of truncating the ADF at fixed levels in the octree [5]. Figure 8 shows the result of truncating a level-8 ADF at four different levels, during rendering. Since our renderer is based on ray-casting, changes in the level of detail do not significantly affect the frame rate. With this approach, transitions between levels are sharp and visually distracting unless the involved levels are very refined (greater than 9). To achieve smoother transitions, Frisken et al. [5] suggest an alternative method that truncates ADF cells based on their estimated error.
Hand”. Unfortunately, in most cases simple interpolation is unable to provide convincing metamorphoses, as it does not preserve or blend corresponding shape features. In order to improve morphing quality, we could use a warp function to guide the distance field interpolation, as proposed by Cohen-Or et al. [3].
Morphing. Distance fields are also commonly used for shape metamorphosis. Compared to mesh-based morphing techniques, volume-based morphing is easier to implement and can naturally morph surfaces of different genus. We have implemented a very simple morphing application that interpolates two distance fields, as originally suggested by Payne and Toga [11]. The application loads two complete ADFs simultaneously on the GPU, and uses a variation of our ray-casting function to render a linear interpolation of both distance fields. Normals are obtained by linearly interpolating the reconstructed smooth normals of both ADFs. Figure 9 illustrates some results with a morphing sequence from the model “Red Circular Box” to the model “Magali’s
We have proposed an efficient method to represent and reconstruct static ADFs on modern GPUs. We use a novel octree representation that enables random access to cells, allowing for stackless traversals of the octree and improved coherence. We reduce voxel replication by packing voxels in a separate texture, and exploit the GPU’s texture filtering units to obtain trilinearly interpolated values at virtually no cost. To render ADFs, we use a general-purpose raycasting algorithm based on sphere tracing. We show how sphere tracing can be used to render superficial ADFs, and how smooth normals can be precomputed and efficiently reconstructed to solve shading discontinuities. We demonstrate the effectiveness of our approach with simple
6. Conclusion and future work
Figure 9. Simple ADF interpolation rendered in real-time on the GPU. rendering applications. In particular, we render a distance field interpolation from two ADF models, directly on the GPU, at reasonable frame rates. Topics for future work include: • Real-time collision detection and other applications using GPU-accelerated ADFs; • Adaptive ray-casting and other rendering strategies, such as dynamic meshing using the geometry shader; • Improve the packing algorithm to further reduce voxel replication; • Adapt our approach to support dynamic ADFs (required for applications such as sculpting).
graphics and interactive techniques, pages 249–254, New York, NY, USA, 2000. ACM Press. [6] M. Hadwiger, C. Sigg, H. Scharsach, K. Bhler, and M. Gross. Real-time ray-casting and advanced shading of discrete isosurfaces. In Proceedings of Eurographics 2005, pages 303–312, 2005. [7] J. C. Hart. Sphere tracing: A geometric method for the antialiased ray tracing of implicit surfaces. The Visual Computer, 12(10):527–545, 1996. [8] M. W. Jones, J. A. Baerentzen, and M. Sramek. 3D Distance Fields: A Survey of Techniques and Applications. IEEE Transactions on Visualization and Computer Graphics, 12(4):581–599, 2006.
Acknowledgements We thank the support provided by the TecGraf laboratory at PUC-Rio, which is mainly funded by the Brazilian oil company, Petrobras.
References [1] J. Bærentzen and H. Aanæs. Signed distance computation using the angle weighted pseudo-normal. IEEE Transactions on Visualization and Computer Graphics, 11(3):243– 253, may 2005. [2] J. A. Bærentzen. Manipulation of volumetric solids with applications to sculpting. PhD thesis, Informatics and Mathematical Modelling, Technical University of Denmark, DTU, 2002. [3] D. Cohen-Or, A. Solomovic, and D. Levin. Threedimensional distance field metamorphosis. ACM Trans. Graph., 17(2):116–141, 1998. [4] L. H. de Figueiredo, L. Velho, and J. B. D. Oliveira. Revisiting adaptively sampled distance fields. In SIBGRAPI ’01: Proceedings of the XIV Brazilian Symposium on Computer Graphics and Image Processing (SIBGRAPI’01), page 377, Washington, DC, USA, 2001. IEEE Computer Society. [5] S. F. Frisken, R. N. Perry, A. P. Rockwood, and T. R. Jones. Adaptively sampled distance fields: a general representation of shape for computer graphics. In SIGGRAPH ’00: Proceedings of the 27th annual conference on Computer
[9] S. Lefebvre and H. Hoppe. Perfect spatial hashing. In SIGGRAPH ’06: Proceedings of the 33th annual conference on Computer graphics and interactive techniques, pages 579–588, New York, NY, USA, 2006. ACM Press. [10] C. Loop and J. Blinn. Real-time GPU rendering of piecewise algebraic surfaces. In SIGGRAPH ’06: ACM SIGGRAPH 2006 Papers, pages 664–670, New York, NY, USA, 2006. ACM Press. [11] B. A. Payne and A. W. Toga. Distance field manipulation of surface models. IEEE Computer Graphics and Applications, 12(1):65–71, 1992. [12] R. N. Perry and S. F. Frisken. Kizamu: a system for sculpting digital characters. In SIGGRAPH ’01: Proceedings of the 28th annual conference on Computer graphics and interactive techniques, pages 47–56, New York, NY, USA, 2001. ACM Press. [13] R. Satherley and M. W. Jones. Vector-city vector distance transform. In Computer Vision and Image Understanding, volume 82, pages 238–254, June 2001. [14] R. Toledo and B. Levy. Extending the graphic pipeline with new gpu-accelerated primitives. In International gOcad Meeting, Nancy, France, 2004.
Appendix: GLSL code vec3 query( inout int level, const vec3 p ) { // check if a cell exists at the current ‘level’ and position ‘p’ vec3 k = S(level, p); // generate a key for the cell ivec2 cell = texture3D( cellTex, H(k) ).ra; // fetch cell int voxels = cell.y; // save the address of the cell’s voxel block if( computeId(k) == cell.x ) { // is this the right cell? while( level 0 ) { // ascend the octree until we find a valid cell k = S( --level, p ); // generate key for the parent cell cell = texture3D( cellTex, H(k) ).ra; // fetch cell if( computeId(k) == cell.x ) { // is this the right cell? voxels = cell.y; // the first cell we find upwards is the smallest break; // so we are done } } } // map 1D address of the cell’s voxel block to an unnormalized 3D texture coord return map1Dto3D( voxels, voxelTexDim ) + 0.5; } float reconstructDist( const vec3 vb, const vec3 cp ) { return texture3D(voxelTex, (vb + cp) / voxelTexDim).a; } // Fragment Program: uniform vec3 eye; uniform float isovalue; uniform float tolerance; varying vec3 fragment pos;
// ray origin in world space // value of the isosurface; usually 0 // intersection tolerance for sphere-tracing // from the vertex program, in world space
void main() { // ray starts at the fragment’s position, on the surface of the ADF’s AABB vec3 pos = fragment pos; // current position along the ray vec3 dir = normalize( pos - eye ); // ray direction // compute the distances at which the ray enters and leaves the ADF’s AABB float rayLength, maxRayLength; intersectAABB( eye, dir, rayLength, maxRayLength ); // traverse the distance field until we hit the isosurface or leave the AABB int level = 1; // initial level for queries for( int i = 0; i < MAX ITERATIONS; ++i ) { vec3 vb = query( level, pos ); // locate the cell’s voxel block vec3 cp = toCellSpace( pos, level ); // pos into cell space float d = reconstructDist( vb, cp ) - isovalue; rayLength += d; // step along the ray pos = eye + dir * rayLength; // update the current position if( d < tolerance ) { // did we hit the isosurface? vec3 normal = reconstructNormal( vb, cp ); gl FragColor = shade( pos, normal, -dir ); return; } if( rayLength >= maxRayLength ) // did we leave the AABB? discard; // ray does not intersect the isosurface } discard; // we have exceeded MAX ITERATIONS }