/*========================================================================= Program: Visualization Toolkit Module: vtkHAVSVolumeMapper.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /* Copyright 2005, 2006 by University of Utah. */ /** * @class vtkHAVSVolumeMapper * @brief Hardware-Assisted Visibility Sorting unstructured grid mapper * * * * vtkHAVSVolumeMapper is a class that renders polygonal data * (represented as an unstructured grid) using the Hardware-Assisted * Visibility Sorting (HAVS) algorithm. First the unique triangles are sorted * in object space, then they are sorted in image space using a fixed size * A-buffer implemented on the GPU called the k-buffer. The HAVS algorithm * excels at rendering large datasets quickly. The trade-off is that the * algorithm may produce some rendering artifacts due to an insufficient k * size (currently 2 or 6 is supported) or read/write race conditions. * * A built in level-of-detail (LOD) approach samples the geometry using one of * two heuristics (field or area). If LOD is enabled, the amount of geometry * that is sampled and rendered changes dynamically to stay within the target * frame rate. The field sampling method generally works best for datasets * with cell sizes that don't vary much in size. On the contrary, the area * sampling approach gives better approximations when the volume has a lot of * variation in cell size. * * The HAVS algorithm uses several advanced features on graphics hardware. * The k-buffer sorting network is implemented using framebuffer objects * (FBOs) with multiple render targets (MRTs). Therefore, only cards that * support these features can run the algorithm (at least an ATI 9500 or an * NVidia NV40 (6600)). * * * @attention * Several issues had to be addressed to get the HAVS algorithm working within * the vtk framework. These additions forced the code to forsake speed for * the sake of compliance and robustness. * * @attention * The HAVS algorithm operates on the triangles that compose the mesh. * Therefore, before rendering, the cells are decomposed into unique triangles * and stored on the GPU for efficient rendering. The use of GPU data * structures is only recommended if the entire geometry can fit in graphics * memory. Otherwise this feature should be disabled. * * @attention * Another new feature is the handling of mixed data types (eg., polygonal * data with volume data). This is handled by reading the z-buffer from the * current window and copying it into the framebuffer object for off-screen * rendering. The depth test is then enabled so that the volume only appears * over the opaque geometry. Finally, the results of the off-screen rendering * are blended into the framebuffer as a transparent, view-aligned texture. * * @attention * Instead of using a preintegrated 3D lookup table for storing the ray * integral, this implementation uses partial pre-integration. This improves * the performance of dynamic transfer function updates by avoiding a costly * preprocess of the table. * * @attention * A final change to the original algorithm is the handling of non-convexities * in the mesh. Due to read/write hazards that may create undesired artifacts * with non-convexities when using a inside/outside toggle in the fragment * program, another approach was employed. To handle non-convexities, the * fragment shader determines if a ray-gap is larger than the max cell size * and kill the fragment if so. This approximation performs rather well in * practice but may miss small non-convexities. * * @attention * For more information on the HAVS algorithm see: * * @attention * "Hardware-Assisted Visibility Sorting for Unstructured Volume * Rendering" by S. P. Callahan, M. Ikits, J. L. D. Comba, and C. T. Silva, * IEEE Transactions of Visualization and Computer Graphics; May/June 2005. * * @attention * For more information on the Level-of-Detail algorithm, see: * * @attention * "Interactive Rendering of Large Unstructured Grids Using Dynamic * Level-of-Detail" by S. P. Callahan, J. L. D. Comba, P. Shirley, and * C. T. Silva, Proceedings of IEEE Visualization '05, Oct. 2005. * * * @par Acknowledgments: * This code was developed by Steven P. Callahan under the supervision * of Prof. Claudio T. Silva. The code also contains contributions * from Milan Ikits, Linh Ha, Huy T. Vo, Carlos E. Scheidegger, and * Joao L. D. Comba. * * @par Acknowledgments: * The work was supported by grants, contracts, and gifts from the * National Science Foundation, the Department of Energy, the Army * Research Office, and IBM. * * @par Acknowledgments: * The port of HAVS to VTK and ParaView has been primarily supported * by Sandia National Labs. * */ #ifndef vtkHAVSVolumeMapper_h #define vtkHAVSVolumeMapper_h #include "vtkRenderingVolumeModule.h" // For export macro #include "vtkUnstructuredGridVolumeMapper.h" #define VTK_KBUFFER_SIZE_2 0 #define VTK_KBUFFER_SIZE_6 1 #define VTK_FIELD_LEVEL_OF_DETAIL 0 #define VTK_AREA_LEVEL_OF_DETAIL 1 class vtkUnstructuredGrid; class vtkDepthRadixSortUnstructuredGrid; class vtkHAVSSortedFace; class VTKRENDERINGVOLUME_EXPORT vtkHAVSVolumeMapper : public vtkUnstructuredGridVolumeMapper { public: static vtkHAVSVolumeMapper *New(); vtkTypeMacro(vtkHAVSVolumeMapper, vtkUnstructuredGridVolumeMapper); void PrintSelf(ostream& os, vtkIndent indent) override; //@{ /** * regions by removing ray segments larger than the max cell size. */ vtkSetMacro(PartiallyRemoveNonConvexities, bool); vtkGetMacro(PartiallyRemoveNonConvexities, bool); //@} //@{ /** * Set/get the desired level of detail target time measured in frames/sec. */ vtkSetMacro(LevelOfDetailTargetTime, float); vtkGetMacro(LevelOfDetailTargetTime, float); //@} //@{ /** * Turn on/off level-of-detail volume rendering */ vtkSetMacro(LevelOfDetail, bool); vtkGetMacro(LevelOfDetail, bool); //@} //@{ /** * Set/get the current level-of-detail method */ void SetLevelOfDetailMethod(int); vtkGetMacro(LevelOfDetailMethod, int); void SetLevelOfDetailMethodField() {this->SetLevelOfDetailMethod(VTK_FIELD_LEVEL_OF_DETAIL);} void SetLevelOfDetailMethodArea() {this->SetLevelOfDetailMethod(VTK_AREA_LEVEL_OF_DETAIL);} //@} //@{ /** * Set the kbuffer size */ vtkSetMacro(KBufferSize,int); vtkGetMacro(KBufferSize,int); void SetKBufferSizeTo2() {this->SetKBufferSize(VTK_KBUFFER_SIZE_2);} void SetKBufferSizeTo6() {this->SetKBufferSize(VTK_KBUFFER_SIZE_6);} //@} /** * Check hardware support for the HAVS algorithm. Necessary * features include off-screen rendering, 32-bit fp textures, multiple * render targets, and framebuffer objects. * Subclasses must override this method to indicate if supported by Hardware. */ virtual bool SupportedByHardware(vtkRenderer *vtkNotUsed(r)) {return false; } //@{ /** * Set/get whether or not the data structures should be stored on the GPU * for better peformance. */ virtual void SetGPUDataStructures(bool) = 0; vtkGetMacro(GPUDataStructures, bool); //@} protected: vtkHAVSVolumeMapper(); ~vtkHAVSVolumeMapper() override; virtual void Initialize(vtkRenderer *ren, vtkVolume *vol) = 0; void InitializePrimitives(vtkVolume *vol); void InitializeScalars(); void InitializeLevelOfDetail(); void InitializeLookupTables(vtkVolume *vol); void FRadixSort(vtkHAVSSortedFace *array, vtkHAVSSortedFace *temp, int lo, int up); void FRadix(int byte, int len, vtkHAVSSortedFace *source, vtkHAVSSortedFace *dest, int *count); void UpdateLevelOfDetail(float targetTime); void PartialVisibilitySort(float *eye); bool CheckInitializationError(); enum { NO_INIT_ERROR=0, NON_TETRAHEDRA=1, UNSUPPORTED_EXTENSIONS=2, NO_SCALARS=3, CELL_DATA=4, NO_CELLS=5 }; // Mesh float *Vertices; float *Scalars; double ScalarRange[2]; unsigned int *Triangles; unsigned int *OrderedTriangles; vtkHAVSSortedFace *SortedFaces; vtkHAVSSortedFace *RadixTemp; float *Centers; unsigned int NumberOfVertices; unsigned int NumberOfCells; unsigned int NumberOfScalars; unsigned int NumberOfTriangles; // Level-Of-Detail unsigned int NumberOfBoundaryTriangles; unsigned int NumberOfInternalTriangles; unsigned int *BoundaryTriangles; unsigned int *InternalTriangles; unsigned int LevelOfDetailTriangleCount; float CurrentLevelOfDetail; float LevelOfDetailTargetTime; bool LevelOfDetail; int LevelOfDetailMethod; // K-Buffer int KBufferState; float MaxEdgeLength; float LevelOfDetailMaxEdgeLength; float UnitDistance; bool GPUDataStructures; float Diagonal; bool PartiallyRemoveNonConvexities; int KBufferSize; // Lookup Tables float *TransferFunction; int TransferFunctionSize; // State and Timing Stats bool Initialized; int InitializationError; int FrameNumber; float TotalRenderTime; vtkTimeStamp ColorTransferFunctionMTime; vtkTimeStamp AlphaTransferFunctionMTime; vtkTimeStamp UnstructuredGridMTime; vtkTimeStamp ScalarsMTime; vtkVolume *LastVolume; private: vtkHAVSVolumeMapper(const vtkHAVSVolumeMapper&) = delete; void operator=(const vtkHAVSVolumeMapper&) = delete; }; #endif