Work on CubicSurfaceExtractor documentation.
This commit is contained in:
parent
9d6124d390
commit
39f7bb851c
BIN
documentation/diagrams/CubicSurfaceExtractor1.dia
Normal file
BIN
documentation/diagrams/CubicSurfaceExtractor1.dia
Normal file
Binary file not shown.
BIN
documentation/diagrams/CubicSurfaceExtractor2.dia
Normal file
BIN
documentation/diagrams/CubicSurfaceExtractor2.dia
Normal file
Binary file not shown.
BIN
documentation/images/CubicSurfaceExtractor1.png
Normal file
BIN
documentation/images/CubicSurfaceExtractor1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -34,13 +34,23 @@ namespace PolyVox
|
|||||||
{
|
{
|
||||||
/// The CubicSurfaceExtractor creates a mesh in which each voxel appears to be rendered as a cube
|
/// The CubicSurfaceExtractor creates a mesh in which each voxel appears to be rendered as a cube
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Introduction
|
||||||
|
/// ------------
|
||||||
/// Games such as Minecraft and Voxatron have a unique graphical style in which each voxel in the world appears to be rendered as a single cube. Actually rendering a cube for each voxel would be very expensive, but in practice the only faces which need to be drawn are those which lie on the boundary between solid and empty voxels. The CubicSurfaceExtractor can be used to create such a mesh from PolyVox volume data. As an example, images from Minecraft and Voxatron are shown below:
|
/// Games such as Minecraft and Voxatron have a unique graphical style in which each voxel in the world appears to be rendered as a single cube. Actually rendering a cube for each voxel would be very expensive, but in practice the only faces which need to be drawn are those which lie on the boundary between solid and empty voxels. The CubicSurfaceExtractor can be used to create such a mesh from PolyVox volume data. As an example, images from Minecraft and Voxatron are shown below:
|
||||||
///
|
///
|
||||||
/// \image html MinecraftAndVoxatron.jpg
|
/// \image html MinecraftAndVoxatron.jpg
|
||||||
///
|
///
|
||||||
/// Before we get into the specifics of the CubicSurfaceExtractor, it is useful to understand the principles which apply to *all* PolyVox surface extractors and which are described in the Surface Extraction document (ADD LINK). From here on, it is assumed that you are familier with PolyVox regions and how they are used to limit surface extraction to a particular part of the volume.
|
/// Before we get into the specifics of the CubicSurfaceExtractor, it is useful to understand the principles which apply to *all* PolyVox surface extractors and which are described in the Surface Extraction document (ADD LINK). From here on, it is assumed that you are familier with PolyVox regions and how they are used to limit surface extraction to a particular part of the volume. The principles of allowing dynamic terrain are also common to all surface extractors and are described here (ADD LINK).
|
||||||
///
|
///
|
||||||
/// The images shown above shoulld hopefully make it clear how the resulting mesh should look, but the process is more easily explained in 2D. Hopefully you will find that the extension to 3D is intuitive.
|
/// Basic Operation
|
||||||
|
/// ---------------
|
||||||
|
/// At its core, the CubicSurfaceExtractor works by by looking at pairs of adjacent voxels and determining whether a quad should be placed between then. The most simple situation to imagine is a binary volume where every voxel is either solid or empty. In this case a quad should be generated when ever a solid voxel is next to an empty voxel as this represent part of the surface of the solid object. there is no need to generate a quad between two solid voxels (this quad would never be seen as it is inside the object) and there is no need to generate a quad between two empty voxels (there is no object here). PolyVox allows the principle to be extended far beyond such simple binary volumes but they provide a useful starting point for understanding how the algorithm works.
|
||||||
|
///
|
||||||
|
/// As an example, lets consider the part of a volume shown below. We are going to explain the principles in only two dimentions as this makes it much simpler to illustrate, so you will need to mentally extend the process into the third dimension. Hopefully you will find this intuitive. The diagram below shows a small part of a larger volume (as indicated by the voxel coordinate on the axes) which contains only solid and empty voxels represented by solid and hollow circles respectively. The region on which we are running the surface extractor is marked in pink, and for the purpose of this example it corresponds to the whole of the diagram.
|
||||||
|
///
|
||||||
|
/// \image html CubicSurfaceExtractor1.png
|
||||||
|
///
|
||||||
|
/// The output of the surface extractor is the mesh marked in red. As you can see, this forms a closed object which corrsponds to the shape of the underlying voxel data. We won't describe the rendering of such meshes here - for details of this please see (SOME LINK HERE).
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
template<typename VolumeType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> >
|
template<typename VolumeType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> >
|
||||||
class CubicSurfaceExtractor
|
class CubicSurfaceExtractor
|
||||||
|
@ -50,7 +50,8 @@ namespace PolyVox
|
|||||||
/// We use the LargeVolume class to store our data in an efficient way, and it is the input to many of the algorithms (such as the surface
|
/// We use the LargeVolume class to store our data in an efficient way, and it is the input to many of the algorithms (such as the surface
|
||||||
/// extractors) which form the heart of PolyVox. The LargeVolume class is templatised so that different types of data can be stored within each voxel.
|
/// extractors) which form the heart of PolyVox. The LargeVolume class is templatised so that different types of data can be stored within each voxel.
|
||||||
///
|
///
|
||||||
/// <b> Basic usage</b>
|
/// Basic usage
|
||||||
|
/// -----------
|
||||||
///
|
///
|
||||||
/// The following code snippet shows how to construct a volume and demonstrates basic usage:
|
/// The following code snippet shows how to construct a volume and demonstrates basic usage:
|
||||||
///
|
///
|
||||||
@ -75,8 +76,8 @@ namespace PolyVox
|
|||||||
/// Lastly the example prints out some properties of the LargeVolume. Note that the dimentsions getWidth(), getHeight(), and getDepth() are inclusive, such
|
/// Lastly the example prints out some properties of the LargeVolume. Note that the dimentsions getWidth(), getHeight(), and getDepth() are inclusive, such
|
||||||
/// that the width is 64 when the range of valid x coordinates goes from 0 to 63.
|
/// that the width is 64 when the range of valid x coordinates goes from 0 to 63.
|
||||||
///
|
///
|
||||||
/// <b>Data Representaion</b>
|
/// Data Representaion
|
||||||
///
|
/// ------------------
|
||||||
/// If stored carelessly, volume data can take up a huge amount of memory. For example, a volume of dimensions 1024x1024x1024 with
|
/// If stored carelessly, volume data can take up a huge amount of memory. For example, a volume of dimensions 1024x1024x1024 with
|
||||||
/// 1 byte per voxel will require 1GB of memory if stored in an uncompressed form. Natuarally our LargeVolume class is much more efficient
|
/// 1 byte per voxel will require 1GB of memory if stored in an uncompressed form. Natuarally our LargeVolume class is much more efficient
|
||||||
/// than this and it is worth understanding (at least at a high level) the approach which is used.
|
/// than this and it is worth understanding (at least at a high level) the approach which is used.
|
||||||
@ -91,8 +92,8 @@ namespace PolyVox
|
|||||||
/// is touched a timestamp is updated on the corresponding block. When the cache becomes full the block with the oldest timestamp is
|
/// is touched a timestamp is updated on the corresponding block. When the cache becomes full the block with the oldest timestamp is
|
||||||
/// recompressed and moved out of the cache.
|
/// recompressed and moved out of the cache.
|
||||||
///
|
///
|
||||||
/// <b>Achieving high compression rates</b>
|
/// Achieving high compression rates
|
||||||
///
|
/// --------------------------------
|
||||||
/// The compression rates which can be achieved can vary significantly depending the nature of the data you are storing, but you can
|
/// The compression rates which can be achieved can vary significantly depending the nature of the data you are storing, but you can
|
||||||
/// encourage high compression rates by making your data as homogenous as possible. If you are simply storing a material with each
|
/// encourage high compression rates by making your data as homogenous as possible. If you are simply storing a material with each
|
||||||
/// voxel then this will probably happen naturally. Games such as Minecraft which use this approach will typically involve large areas
|
/// voxel then this will probably happen naturally. Games such as Minecraft which use this approach will typically involve large areas
|
||||||
@ -103,8 +104,8 @@ namespace PolyVox
|
|||||||
/// on the boundary) does not benefit the surface and is very hard to compress effectively. You may wish to apply some thresholding to
|
/// on the boundary) does not benefit the surface and is very hard to compress effectively. You may wish to apply some thresholding to
|
||||||
/// your density values to reduce this problem (this threasholding should only be applied to voxels who don't contribute to the surface).
|
/// your density values to reduce this problem (this threasholding should only be applied to voxels who don't contribute to the surface).
|
||||||
///
|
///
|
||||||
/// <b>Paging large volumes</b>
|
/// Paging large volumes
|
||||||
///
|
/// --------------------
|
||||||
/// The compression scheme described previously will typically allow you to load several billion voxels into a few hundred megabytes of memory,
|
/// The compression scheme described previously will typically allow you to load several billion voxels into a few hundred megabytes of memory,
|
||||||
/// though as explained the exact compression rate is highly dependant on your data. If you have more data than this then PolyVox provides a
|
/// though as explained the exact compression rate is highly dependant on your data. If you have more data than this then PolyVox provides a
|
||||||
/// mechanism by which parts of the volume can be paged out of memory by calling user supplied callback functions. This mechanism allows a
|
/// mechanism by which parts of the volume can be paged out of memory by calling user supplied callback functions. This mechanism allows a
|
||||||
@ -134,8 +135,8 @@ namespace PolyVox
|
|||||||
/// that you don't actually have to do anything with the data - you could simply decide that once it gets removed from memory it doesn't matter
|
/// that you don't actually have to do anything with the data - you could simply decide that once it gets removed from memory it doesn't matter
|
||||||
/// anymore. But you still need to be ready to then provide something to PolyVox (even if it's just default data) in the event that it is requested.
|
/// anymore. But you still need to be ready to then provide something to PolyVox (even if it's just default data) in the event that it is requested.
|
||||||
///
|
///
|
||||||
/// <b>Cache-aware traversal</b>
|
/// Cache-aware traversal
|
||||||
///
|
/// ---------------------
|
||||||
/// You might be suprised at just how many cache misses can occur when you traverse the volume in a naive manner. Consider a 1024x1024x1024 volume
|
/// You might be suprised at just how many cache misses can occur when you traverse the volume in a naive manner. Consider a 1024x1024x1024 volume
|
||||||
/// with blocks of size 32x32x32. And imagine you iterate over this volume with a simple three-level for loop which iterates over x, the y, then z.
|
/// with blocks of size 32x32x32. And imagine you iterate over this volume with a simple three-level for loop which iterates over x, the y, then z.
|
||||||
/// If you start at position (0,0,0) then ny the time you reach position (1023,0,0) you have touched 1024 voxels along one edge of the volume and
|
/// If you start at position (0,0,0) then ny the time you reach position (1023,0,0) you have touched 1024 voxels along one edge of the volume and
|
||||||
@ -148,8 +149,8 @@ namespace PolyVox
|
|||||||
/// and (31,31,31), then process all the voxels between (32,0,0) and (63,0,0), and so forth. Using this approach you will have no cache misses even
|
/// and (31,31,31), then process all the voxels between (32,0,0) and (63,0,0), and so forth. Using this approach you will have no cache misses even
|
||||||
/// is your cache sise is only one. Of course the logic is more complex, but writing code in such a cache-aware manner may be beneficial in some situations.
|
/// is your cache sise is only one. Of course the logic is more complex, but writing code in such a cache-aware manner may be beneficial in some situations.
|
||||||
///
|
///
|
||||||
/// <b>Threading</b>
|
/// Threading
|
||||||
///
|
/// ---------
|
||||||
/// The LargeVolume class does not make any guarentees about thread safety. You should ensure that all accesses are performed from the same thread.
|
/// The LargeVolume class does not make any guarentees about thread safety. You should ensure that all accesses are performed from the same thread.
|
||||||
/// This is true even if you are only reading data from the volume, as concurrently reading from different threads can invalidate the contents
|
/// This is true even if you are only reading data from the volume, as concurrently reading from different threads can invalidate the contents
|
||||||
/// of the block cache (amoung other problems).
|
/// of the block cache (amoung other problems).
|
||||||
|
@ -59,7 +59,7 @@ namespace PolyVox
|
|||||||
/// of the RaycastResult structure and the intersectionFound flag is set to true, otherwise
|
/// of the RaycastResult structure and the intersectionFound flag is set to true, otherwise
|
||||||
/// the intersectionFound flag is set to false.
|
/// the intersectionFound flag is set to false.
|
||||||
///
|
///
|
||||||
/// <b>Important Note:</b> These has been confusion in the past with people not realising
|
/// **Important Note:** These has been confusion in the past with people not realising
|
||||||
/// that the length of the direction vector is important. Most graphics API can provide
|
/// that the length of the direction vector is important. Most graphics API can provide
|
||||||
/// a camera position and view direction for picking purposes, but the view direction is
|
/// a camera position and view direction for picking purposes, but the view direction is
|
||||||
/// usually normalised (i.e. of length one). If you use this view direction directly you
|
/// usually normalised (i.e. of length one). If you use this view direction directly you
|
||||||
|
Loading…
x
Reference in New Issue
Block a user