/*========================================================================= Program: Visualization Toolkit Module: vtkGPUVolumeRayCastMapper.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. =========================================================================*/ /** * @class vtkGPUVolumeRayCastMapper * @brief Ray casting performed on the GPU. * * vtkGPUVolumeRayCastMapper is a volume mapper that performs ray casting on * the GPU using fragment programs. * * This mapper supports connections in multiple ports of input 0 (port 0 being * the only required connection). It is up to the concrete implementation * whether additional inputs will be used during rendering. This class maintains * a list of the currently active input ports (Ports) as well as a list of the * ports that have been disconnected (RemovedPorts). RemovedPorts is used the * the concrete implementation to clean up internal structures. * */ #ifndef vtkGPUVolumeRayCastMapper_h #define vtkGPUVolumeRayCastMapper_h #include // For std::unordered_map #include // For std::vector #include "vtkVolumeMapper.h" #include // For export macro class vtkContourValues; class vtkRenderWindow; class vtkVolumeProperty; class VTKRENDERINGVOLUME_EXPORT vtkGPUVolumeRayCastMapper : public vtkVolumeMapper { public: static vtkGPUVolumeRayCastMapper* New(); vtkTypeMacro(vtkGPUVolumeRayCastMapper, vtkVolumeMapper); void PrintSelf(ostream& os, vtkIndent indent) override; //@{ /** * If AutoAdjustSampleDistances is on, the ImageSampleDistance * will be varied to achieve the allocated render time of this * prop (controlled by the desired update rate and any culling in * use). */ vtkSetClampMacro(AutoAdjustSampleDistances, vtkTypeBool, 0, 1); vtkGetMacro(AutoAdjustSampleDistances, vtkTypeBool); vtkBooleanMacro(AutoAdjustSampleDistances, vtkTypeBool); //@} //@{ /** * Compute the sample distance from the data spacing. When the number of * voxels is 8, the sample distance will be roughly 1/200 the average voxel * size. The distance will grow proportionally to numVoxels^(1/3). Off by default. */ vtkSetClampMacro(LockSampleDistanceToInputSpacing, vtkTypeBool, 0, 1); vtkGetMacro(LockSampleDistanceToInputSpacing, vtkTypeBool); vtkBooleanMacro(LockSampleDistanceToInputSpacing, vtkTypeBool); //@} //@{ /** * If UseJittering is on, each ray traversal direction will be * perturbed slightly using a noise-texture to get rid of wood-grain * effect. */ vtkSetClampMacro(UseJittering, vtkTypeBool, 0, 1); vtkGetMacro(UseJittering, vtkTypeBool); vtkBooleanMacro(UseJittering, vtkTypeBool); //@} //@{ /** * If UseDepthPass is on, the mapper will use two passes. In the first * pass, an isocontour depth buffer will be utilized as starting point * for ray-casting hence eliminating traversal on voxels that are * not going to participate in final rendering. UseDepthPass requires * reasonable contour values to be set which can be set by calling * GetDepthPassContourValues() method and using vtkControurValues API. */ vtkSetClampMacro(UseDepthPass, vtkTypeBool, 0, 1); vtkGetMacro(UseDepthPass, vtkTypeBool); vtkBooleanMacro(UseDepthPass, vtkTypeBool); //@} /** * Return handle to contour values container so * that values can be set by the application. Contour values * will be used only when UseDepthPass is on. */ vtkContourValues* GetDepthPassContourValues(); //@{ /** * Set/Get the distance between samples used for rendering * when AutoAdjustSampleDistances is off, or when this mapper * has more than 1 second allocated to it for rendering. * Initial value is 1.0. */ vtkSetMacro(SampleDistance, float); vtkGetMacro(SampleDistance, float); //@} //@{ /** * Sampling distance in the XY image dimensions. Default value of 1 meaning * 1 ray cast per pixel. If set to 0.5, 4 rays will be cast per pixel. If * set to 2.0, 1 ray will be cast for every 4 (2 by 2) pixels. This value * will be adjusted to meet a desired frame rate when AutoAdjustSampleDistances * is on. */ vtkSetClampMacro(ImageSampleDistance, float, 0.1f, 100.0f); vtkGetMacro(ImageSampleDistance, float); //@} //@{ /** * This is the minimum image sample distance allow when the image * sample distance is being automatically adjusted. */ vtkSetClampMacro(MinimumImageSampleDistance, float, 0.1f, 100.0f); vtkGetMacro(MinimumImageSampleDistance, float); //@} //@{ /** * This is the maximum image sample distance allow when the image * sample distance is being automatically adjusted. */ vtkSetClampMacro(MaximumImageSampleDistance, float, 0.1f, 100.0f); vtkGetMacro(MaximumImageSampleDistance, float); //@} //@{ /** * Set/Get the window / level applied to the final color. * This allows brightness / contrast adjustments on the * final image. * window is the width of the window. * level is the center of the window. * Initial window value is 1.0 * Initial level value is 0.5 * window cannot be null but can be negative, this way * values will be reversed. * |window| can be larger than 1.0 * level can be any real value. */ vtkSetMacro(FinalColorWindow, float); vtkGetMacro(FinalColorWindow, float); vtkSetMacro(FinalColorLevel, float); vtkGetMacro(FinalColorLevel, float); //@} //@{ /** * Maximum size of the 3D texture in GPU memory. * Will default to the size computed from the graphics * card. Can be adjusted by the user. */ vtkSetMacro(MaxMemoryInBytes, vtkIdType); vtkGetMacro(MaxMemoryInBytes, vtkIdType); //@} //@{ /** * Maximum fraction of the MaxMemoryInBytes that should * be used to hold the texture. Valid values are 0.1 to * 1.0. */ vtkSetClampMacro(MaxMemoryFraction, float, 0.1f, 1.0f); vtkGetMacro(MaxMemoryFraction, float); //@} //@{ /** * Tells if the mapper will report intermediate progress. * Initial value is true. As the progress works with a GL blocking * call (glFinish()), this can be useful for huge dataset but can * slow down rendering of small dataset. It should be set to true * for big dataset or complex shading and streaming but to false for * small datasets. */ vtkSetMacro(ReportProgress, bool); vtkGetMacro(ReportProgress, bool); //@} /** * Based on hardware and properties, we may or may not be able to * render using 3D texture mapping. This indicates if 3D texture * mapping is supported by the hardware, and if the other extensions * necessary to support the specific properties are available. */ virtual int IsRenderSupported( vtkRenderWindow* vtkNotUsed(window), vtkVolumeProperty* vtkNotUsed(property)) { return 0; } void CreateCanonicalView(vtkRenderer* ren, vtkVolume* volume, vtkImageData* image, int blend_mode, double viewDirection[3], double viewUp[3]); //@{ /** * Optionally, set a mask input. This mask may be a binary mask or a label * map. This must be specified via SetMaskType. * If the mask is a binary mask, the volume rendering is confined to regions * within the binary mask. The binary mask is assumed to have a datatype of * UCHAR and values of 255 (inside) and 0 (outside). * The mask may also be a label map. The label map must have a datatype of * UCHAR i.e. it can have upto 256 labels. The label 0 is reserved as a * special label. In voxels with label value of 0, the default transfer * functions supplied by vtkVolumeProperty are used. * * For voxels with a label values greater than 0, the color transfer functions * supplied using vtkVolumeProperty's label API are used. * * For voxels with a label value greater than 0, the color transfer function * is blended with the default color transfer function, with the blending * weight determined by MaskBlendFactor. */ void SetMaskInput(vtkImageData* mask); vtkGetObjectMacro(MaskInput, vtkImageData); //@} enum { BinaryMaskType = 0, LabelMapMaskType }; //@{ /** * Set the mask type, if mask is to be used. See documentation for * SetMaskInput(). The default is a LabelMapMaskType. */ vtkSetMacro(MaskType, int); vtkGetMacro(MaskType, int); void SetMaskTypeToBinary(); void SetMaskTypeToLabelMap(); //@} //@{ /** * Tells how much mask color transfer function is used compared to the * standard color transfer function when the mask is true. This is relevant * only for the label map mask. * 0.0 means only standard color transfer function. * 1.0 means only mask color transfer function. * The default value is 1.0. */ vtkSetClampMacro(MaskBlendFactor, float, 0.0f, 1.0f); vtkGetMacro(MaskBlendFactor, float); //@} //@{ /** * Enable or disable setting output of volume rendering to be * color and depth textures. By default this is set to 0 (off). * It should be noted that it is possible that underlying API specific * mapper may not supoport RenderToImage mode. * \warning * \li This method ignores any other volumes / props in the scene. * \li This method does not respect the general attributes of the * scene i.e. background color, etc. It always produces a color * image that has a transparent white background outside the * bounds of the volume. * \sa GetDepthImage(), GetColorImage() */ vtkSetMacro(RenderToImage, vtkTypeBool); vtkGetMacro(RenderToImage, vtkTypeBool); vtkBooleanMacro(RenderToImage, vtkTypeBool); //@} //@{ /** * Set/Get the scalar type of the depth texture in RenderToImage mode. * By default, the type if VTK_FLOAT. * \sa SetRenderToImage() */ vtkSetMacro(DepthImageScalarType, int); vtkGetMacro(DepthImageScalarType, int); void SetDepthImageScalarTypeToUnsignedChar(); void SetDepthImageScalarTypeToUnsignedShort(); void SetDepthImageScalarTypeToFloat(); //@} //@{ /** * Enable or disable clamping the depth value of the fully * transparent voxel to the depth of the back-face of the * volume. This parameter is used when RenderToImage mode is * enabled. When ClampDepthToBackFace is false, the fully transparent * voxels will have a value of 1.0 in the depth image. When * this is true, the fully transparent voxels will have the * depth value of the face at which the ray exits the volume. * By default, this is set to 0 (off). * \sa SetRenderToImage(), GetDepthImage() */ vtkSetMacro(ClampDepthToBackface, vtkTypeBool); vtkGetMacro(ClampDepthToBackface, vtkTypeBool); vtkBooleanMacro(ClampDepthToBackface, vtkTypeBool); //@} /** * Low level API to export the depth texture as vtkImageData in * RenderToImage mode. * Should be implemented by the graphics API specific mapper (GL or other). * \sa SetRenderToImage() */ virtual void GetDepthImage(vtkImageData*) {} /** * Low level API to export the color texture as vtkImageData in * RenderToImage mode. * Should be implemented by the graphics API specific mapper (GL or other). * \sa SetRenderToImage() */ virtual void GetColorImage(vtkImageData*) {} /** * Initialize rendering for this volume. * \warning INTERNAL METHOD - NOT INTENDED FOR GENERAL USE */ void Render(vtkRenderer*, vtkVolume*) override; /** * Handled in the subclass - the actual render method * \pre input is up-to-date. */ virtual void GPURender(vtkRenderer*, vtkVolume*) {} /** * Release any graphics resources that are being consumed by this mapper. * The parameter window could be used to determine which graphic * resources to release. * \warning INTERNAL METHOD - NOT INTENDED FOR GENERAL USE */ void ReleaseGraphicsResources(vtkWindow*) override {} /** * Return how much the dataset has to be reduced in each dimension to * fit on the GPU. If the value is 1.0, there is no need to reduce the * dataset. * \pre the calling thread has a current OpenGL context. * \pre mapper_supported: IsRenderSupported(renderer->GetRenderWindow(),0) * The computation is based on hardware limits (3D texture indexable size) * and MaxMemoryInBytes. * \post valid_i_ratio: ratio[0]>0 && ratio[0]<=1.0 * \post valid_j_ratio: ratio[1]>0 && ratio[1]<=1.0 * \post valid_k_ratio: ratio[2]>0 && ratio[2]<=1.0 */ virtual void GetReductionRatio(double ratio[3]) = 0; enum TFRangeType { SCALAR = 0, // default NATIVE }; //@{ /** * Set whether to use the scalar range or the native transfer function range * when looking up transfer functions for color and opacity values. When the * range is set to TransferFunctionRange::SCALAR, the function is distributed * over the entire scalar range. If it is set to * TransferFunctionRange::NATIVE, the scalar values outside the native * transfer function range will be truncated to native range. By * default, the volume scalar range is used. * * \note The native range of the transfer function is the range returned by * vtkColorTransferFunction::GetRange() or vtkPiecewiseFunction::GetRange(). * * \note There is no special API provided for 2D transfer functions * considering that they are set as a pre-generated vtkImageData on this * class i.e. the range is already encoded. */ vtkSetMacro(ColorRangeType, int); vtkGetMacro(ColorRangeType, int); vtkSetMacro(ScalarOpacityRangeType, int); vtkGetMacro(ScalarOpacityRangeType, int); vtkSetMacro(GradientOpacityRangeType, int); vtkGetMacro(GradientOpacityRangeType, int); //@} vtkImageData* GetInput() override { return this->GetInput(0); }; //@{ /** * Add/Remove input connections. Active and removed ports are cached in * Ports and RemovedPorts respectively. */ void RemoveInputConnection(int port, vtkAlgorithmOutput* input) override; void RemoveInputConnection(int port, int idx) override; void SetInputConnection(int port, vtkAlgorithmOutput* input) override; void SetInputConnection(vtkAlgorithmOutput* input) override { this->SetInputConnection(0, input); } //@} /** * Number of currently active ports. */ int GetInputCount(); vtkImageData* GetTransformedInput(const int port = 0); double* GetBoundsFromPort(const int port) VTK_SIZEHINT(6); protected: vtkGPUVolumeRayCastMapper(); ~vtkGPUVolumeRayCastMapper() override; /** * Handle inputs. This mapper provides an interface to support multiple * inputs but it is up to the OpenGL implementation use them during rendering. * Currently, only VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper makes use * of these inputs. * * \sa vtkOpenGLGPUVolumeRayCastMapper vtkMultiVolume */ int FillInputPortInformation(int port, vtkInformation* info) override; /** * A transformation is applied (translation) to the input. The resulting * data is stored in TransformedInputs. Takes as an argumet the port of an * input connection. * * ///TODO Elaborate on why this is an issue, texture coords (?) * @TODO: This is the workaround to deal with GPUVolumeRayCastMapper * not able to handle extents starting from non zero values. * There is not a easy fix in the GPU volume ray cast mapper hence * this fix has been introduced. */ void TransformInput(const int port); //@{ /** * This method is used by the Render() method to validate everything before * attempting to render. This method returns 0 if something is not right - * such as missing input, a null renderer or a null volume, no scalars, etc. * In some cases it will produce a vtkErrorMacro message, and in others * (for example, in the case of cropping planes that define a region with * a volume or 0 or less) it will fail silently. If everything is OK, it will * return with a value of 1. */ int ValidateRender(vtkRenderer*, vtkVolume*); int ValidateInputs(); int ValidateInput(vtkVolumeProperty* property, const int port); //@} //@{ /** * Shallow-copy the inputs into a transform-adjusted clone. * \sa vtkGPUVolumeRayCastMapper::TransformInput */ void CloneInputs(); void CloneInput(vtkImageData* input, const int port); //@} // Special version of render called during the creation // of a canonical view. void CanonicalViewRender(vtkRenderer*, vtkVolume*); // Methods called by the AMR Volume Mapper. virtual void PreRender(vtkRenderer* ren, vtkVolume* vol, double datasetBounds[6], double scalarRange[2], int numberOfScalarComponents, unsigned int numberOfLevels) = 0; // \pre input is up-to-date virtual void RenderBlock(vtkRenderer* ren, vtkVolume* vol, unsigned int level) = 0; virtual void PostRender(vtkRenderer* ren, int numberOfScalarComponents) = 0; vtkImageData* GetInput(const int port) override; /** * Called by the AMR Volume Mapper. * Set the flag that tells if the scalars are on point data (0) or * cell data (1). */ void SetCellFlag(int cellFlag); void RemovePortInternal(const int port); vtkTypeBool LockSampleDistanceToInputSpacing; vtkTypeBool AutoAdjustSampleDistances; float ImageSampleDistance; float MinimumImageSampleDistance; float MaximumImageSampleDistance; // Render to texture mode flag vtkTypeBool RenderToImage; // Depth image scalar type int DepthImageScalarType; // Clamp depth values to the depth of the face at which the ray // exits the volume vtkTypeBool ClampDepthToBackface; // Enable / disable stochastic jittering vtkTypeBool UseJittering; // Enable / disable two pass rendering vtkTypeBool UseDepthPass; vtkContourValues* DepthPassContourValues; // The distance between sample points along the ray float SampleDistance; int SmallVolumeRender; double BigTimeToDraw; double SmallTimeToDraw; float FinalColorWindow; float FinalColorLevel; // 1 if we are generating the canonical image, 0 otherwise int GeneratingCanonicalView; vtkImageData* CanonicalViewImageData; //@{ /** * Set the mapper in AMR Mode or not. Initial value is false. * Called only by the vtkKWAMRVolumeMapper */ vtkSetClampMacro(AMRMode, vtkTypeBool, 0, 1); vtkGetMacro(AMRMode, vtkTypeBool); vtkBooleanMacro(AMRMode, vtkTypeBool); //@} vtkImageData* MaskInput; float MaskBlendFactor; int MaskType; vtkTypeBool AMRMode; // Transfer function range type int ColorRangeType; int ScalarOpacityRangeType; int GradientOpacityRangeType; // Point data or cell data (or field data, not handled) ? int CellFlag; /** * Compute the cropping planes clipped by the bounds of the volume. * The result is put into this->ClippedCroppingRegionPlanes. * NOTE: IT WILL BE MOVED UP TO vtkVolumeMapper after bullet proof usage * in this mapper. Other subclasses will use the ClippedCroppingRegionsPlanes * members instead of CroppingRegionPlanes. * \pre volume_exists: this->GetInput()!=0 * \pre valid_cropping: this->Cropping && * this->CroppingRegionPlanes[0]CroppingRegionPlanes[1] && * this->CroppingRegionPlanes[2]CroppingRegionPlanes[3] && * this->CroppingRegionPlanes[4]CroppingRegionPlanes[5]) */ virtual void ClipCroppingRegionPlanes(); using DataMap = std::unordered_map; void SetTransformedInput(vtkImageData*); vtkImageData* FindData(int port, DataMap& container); double ClippedCroppingRegionPlanes[6]; vtkIdType MaxMemoryInBytes; float MaxMemoryFraction; bool ReportProgress; std::vector Ports; std::vector RemovedPorts; DataMap TransformedInputs; /** * This is needed only to check if the input data has been changed since the last * Render() call. */ DataMap LastInputs; private: vtkGPUVolumeRayCastMapper(const vtkGPUVolumeRayCastMapper&) = delete; void operator=(const vtkGPUVolumeRayCastMapper&) = delete; }; #endif