/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkUnstructuredGridBunykRayCastFunction.h,v $ 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. =========================================================================*/ // .NAME vtkUnstructuredGridBunykRayCastFunction - a superclass for ray casting functions // .SECTION Description // vtkUnstructuredGridBunykRayCastFunction is a concrete implementation of a // ray cast function for unstructured grid data. This class was based on the // paper "Simple, Fast, Robust Ray Casting of Irregular Grids" by Paul Bunyk, // Arie Kaufmna, and Claudio Silva. This method is quite memory intensive // (with extra explicit copies of the data) and therefore should not be used // for very large data. This method assumes that the input data is composed // entirely of tetras - use vtkDataSetTriangleFilter before setting the input // on the mapper. // // The basic idea of this method is as follows: // // 1) Enumerate the triangles. At each triangle have space for some // information that will be used during rendering. This includes // which tetra the triangles belong to, the plane equation and the // Barycentric coefficients. // // 2) Keep a reference to all four triangles for each tetra. // // 3) At the beginning of each render, do the precomputation. This // includes creating an array of transformed points (in view // coordinates) and computing the view dependent info per triangle // (plane equations and barycentric coords in view space) // // 4) Find all front facing boundary triangles (a triangle is on the // boundary if it belongs to only one tetra). For each triangle, // find all pixels in the image that intersect the triangle, and // add this to the sorted (by depth) intersection list at each // pixel. // // 5) For each ray cast, traverse the intersection list. At each // intersection, accumulate opacity and color contribution // per tetra along the ray until you reach an exiting triangle // (on the boundary). // // .SECTION See Also // vtkUnstructuredGridVolumeRayCastMapper #ifndef __vtkUnstructuredGridBunykRayCastFunction_h #define __vtkUnstructuredGridBunykRayCastFunction_h #include "vtkUnstructuredGridVolumeRayCastFunction.h" class vtkRenderer; class vtkVolume; class vtkUnstructuredGridVolumeRayCastMapper; class vtkMatrix4x4; class vtkPiecewiseFunction; class vtkColorTransferFunction; class vtkUnstructuredGrid; class vtkIdList; class vtkDoubleArray; class vtkDataArray; // We manage the memory for the list of intersections ourself - this is the // storage used. We keep 10,000 elements in each array, and we can have up to // 1,000 arrays. #define VTK_BUNYKRCF_MAX_ARRAYS 10000 #define VTK_BUNYKRCF_ARRAY_SIZE 10000 class VTK_VOLUMERENDERING_EXPORT vtkUnstructuredGridBunykRayCastFunction : public vtkUnstructuredGridVolumeRayCastFunction { public: static vtkUnstructuredGridBunykRayCastFunction *New(); vtkTypeRevisionMacro(vtkUnstructuredGridBunykRayCastFunction,vtkUnstructuredGridVolumeRayCastFunction); virtual void PrintSelf(ostream& os, vtkIndent indent); //BTX // Description: // Called by the ray cast mapper at the start of rendering virtual void Initialize( vtkRenderer *ren, vtkVolume *vol ); // Description: // Called by the ray cast mapper at the end of rendering virtual void Finalize(); virtual vtkUnstructuredGridVolumeRayCastIterator *NewIterator(); // Used to store each triangle - made public because of the // templated function class Triangle { public: vtkIdType PointIndex[3]; vtkIdType ReferredByTetra[2]; double P1X, P1Y; double P2X, P2Y; double Denominator; double A, B, C, D; Triangle *Next; }; // Used to store each intersection for the pixel rays - made // public because of the templated function class Intersection { public: Triangle *TriPtr; double Z; Intersection *Next; }; // Description: // Is the point x, y, in the given triangle? Public for // access from the templated function. int InTriangle( double x, double y, Triangle *triPtr ); // Description: // Access to an internal structure for the templated method. double *GetPoints() {return this->Points;} // Description: // Access to an internal structure for the templated method. vtkGetObjectMacro( ViewToWorldMatrix, vtkMatrix4x4 ); // Description: // Access to an internal structure for the templated method. vtkGetVectorMacro( ImageOrigin, int, 2 ); // Description: // Access to an internal structure for the templated method. vtkGetVectorMacro( ImageViewportSize, int, 2 ); // Description: // Access to an internal structure for the templated method. Triangle **GetTetraTriangles () {return this->TetraTriangles;} // Description: // Access to an internal structure for the templated method. Intersection *GetIntersectionList( int x, int y ) { return this->Image[y*this->ImageSize[0] + x]; } //ETX protected: vtkUnstructuredGridBunykRayCastFunction(); ~vtkUnstructuredGridBunykRayCastFunction(); // These are cached during the initialize method so that they do not // need to be passed into subsequent CastRay calls. vtkRenderer *Renderer; vtkVolume *Volume; vtkUnstructuredGridVolumeRayCastMapper *Mapper; // Computed during the initialize method - if something is // wrong (no mapper, no volume, no input, etc.) then no rendering // will actually be performed. int Valid; // These are the transformed points int NumberOfPoints; double *Points; // This is the matrix that will take a transformed point back // to world coordinates vtkMatrix4x4 *ViewToWorldMatrix; // This is the intersection list per pixel in the image Intersection **Image; // This is the size of the image we are computing (which does // not need to match the screen size) int ImageSize[2]; // Since we may only be computing a subregion of the "full" image, // this is the origin of the region we are computing. We must // subtract this origin from any pixel (x,y) locations before // accessing the pixel in this->Image (which represents only the // subregion) int ImageOrigin[2]; // This is the full size of the image int ImageViewportSize[2]; // These are values saved for the building of the TriangleList. Basically // we need to check if the data has changed in some way. vtkUnstructuredGrid *SavedTriangleListInput; vtkTimeStamp SavedTriangleListMTime; //BTX // This is a memory intensive algorithm! For each tetra in the // input data we create up to 4 triangles (we don't create duplicates) // This is the TriangleList. Then, for each tetra we keep track of // the pointer to each of its four triangles - this is the // TetraTriangles. We also keep a duplicate list of points // (transformed into view space) - these are the Points. Triangle **TetraTriangles; Triangle *TriangleList; // Compute whether a boundary triangle is front facing by // looking at the fourth point in the tetra to see if it is // in front (triangle is backfacing) or behind (triangle is // front facing) the plane containing the triangle. int IsTriangleFrontFacing( Triangle *triPtr, vtkIdType tetraIndex ); // The image contains lists of intersections per pixel - we // need to clear this during the initialization phase for each // render. void ClearImage(); // This is the memory buffer used to build the intersection // lists. We do our own memory management here because allocating // a bunch of small elements during rendering is too slow. Intersection *IntersectionBuffer[VTK_BUNYKRCF_MAX_ARRAYS]; int IntersectionBufferCount[VTK_BUNYKRCF_MAX_ARRAYS]; // This method replaces new for creating a new element - it // returns one from the big block already allocated (it // allocates another big block if necessary) void *NewIntersection(); // This method is used during the initialization process to // check the validity of the objects - missing information // such as the volume, renderer, mapper, etc. will be flagged // and reported. int CheckValidity(vtkRenderer *ren, vtkVolume *vol); // This method is used during the initialization process to // transform the points to view coordinates void TransformPoints(); // This method is used during the initialization process to // create the list of triangles if the data has changed void UpdateTriangleList(); // This method is used during the initialization process to // update the view dependent information in the triangle list void ComputeViewDependentInfo(); // This method is used during the initialization process to // compute the intersections for each pixel with the boundary // triangles. void ComputePixelIntersections(); //ETX private: vtkUnstructuredGridBunykRayCastFunction(const vtkUnstructuredGridBunykRayCastFunction&); // Not implemented. void operator=(const vtkUnstructuredGridBunykRayCastFunction&); // Not implemented. }; #endif