/*========================================================================= Program: Visualization Toolkit Module: vtkOpenGLHAVSVolumeMapper.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 vtkOpenGLHAVSVolumeMapper * @brief Hardware-Assisted * Visibility Sorting unstructured grid mapper, OpenGL implementation * * * * 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 vtkOpenGLHAVSVolumeMapper_h #define vtkOpenGLHAVSVolumeMapper_h #include "vtkRenderingVolumeOpenGLModule.h" // For export macro #include "vtkHAVSVolumeMapper.h" #include "vtkWeakPointer.h" // to cache the vtkRenderWindow class vtkRenderer; class vtkRenderWindow; class VTKRENDERINGVOLUMEOPENGL_EXPORT vtkOpenGLHAVSVolumeMapper : public vtkHAVSVolumeMapper { public: static vtkOpenGLHAVSVolumeMapper *New(); vtkTypeMacro(vtkOpenGLHAVSVolumeMapper, vtkHAVSVolumeMapper); void PrintSelf(ostream& os, vtkIndent indent) override; /** * Render the volume */ void Render(vtkRenderer *ren, vtkVolume *vol) override; /** * Release any graphics resources that are being consumed by this volume * renderer. */ void ReleaseGraphicsResources(vtkWindow *) override; /** * Set/get whether or not the data structures should be stored on the GPU * for better peformance. */ void SetGPUDataStructures(bool) override; /** * 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. */ bool SupportedByHardware(vtkRenderer *r) override; protected: vtkOpenGLHAVSVolumeMapper(); ~vtkOpenGLHAVSVolumeMapper() override; int FillInputPortInformation(int port, vtkInformation* info) override; void Initialize(vtkRenderer *ren, vtkVolume *vol) override; virtual void InitializeLookupTables(vtkVolume *vol); void InitializeGPUDataStructures(); void InitializeShaders(); void DeleteShaders(); void InitializeFramebufferObject(); void RenderHAVS(vtkRenderer *ren); void SetupFBOZBuffer(int screenWidth, int screenHeight, float depthNear, float depthFar, float *zbuffer); void SetupFBOMRT(); void DrawFBOInit(int screenWidth, int screenHeight, float depthNear, float depthFar); void DrawFBOGeometry(); void DrawFBOFlush(int screenWidth, int screenHeight, float depthNear, float depthFar); void DrawBlend(int screenWidth, int screenHeight, float depthNear, float depthFar); void CheckOpenGLError(const char *str); // GPU unsigned int VBOVertexName; unsigned int VBOTexCoordName; unsigned int VBOVertexIndexName; unsigned int VertexProgram; unsigned int FragmentProgramBegin; unsigned int FragmentProgram; unsigned int FragmentProgramEnd; unsigned int FramebufferObject; int FramebufferObjectSize; unsigned int FramebufferTextures[4]; unsigned int DepthTexture; // Lookup Tables unsigned int PsiTableTexture; unsigned int TransferFunctionTexture; vtkWeakPointer RenderWindow; private: vtkOpenGLHAVSVolumeMapper(const vtkOpenGLHAVSVolumeMapper&) = delete; void operator=(const vtkOpenGLHAVSVolumeMapper&) = delete; }; #endif