source: trunk/packages/vizservers/vtkvis/RpVolume.cpp @ 3191

Last change on this file since 3191 was 3189, checked in by ldelgass, 11 years ago

Adopt API changes for upcoming VTK 6.0

  • Property svn:eol-style set to native
File size: 8.4 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2012  HUBzero Foundation, LLC
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <cassert>
9
10#include <vtkVersion.h>
11#if (VTK_MAJOR_VERSION >= 6)
12#define USE_VTK6
13#endif
14#include <vtkDataSet.h>
15#include <vtkPointData.h>
16#include <vtkImageData.h>
17#include <vtkVolumeProperty.h>
18#include <vtkGPUVolumeRayCastMapper.h>
19#include <vtkVolumeTextureMapper3D.h>
20#include <vtkUnstructuredGrid.h>
21#include <vtkCellType.h>
22#include <vtkUnstructuredGridVolumeMapper.h>
23#include <vtkUnstructuredGridVolumeRayCastMapper.h>
24#include <vtkProjectedTetrahedraMapper.h>
25#include <vtkDataSetTriangleFilter.h>
26#include <vtkGaussianSplatter.h>
27
28#include "RpVolume.h"
29#include "Trace.h"
30
31using namespace Rappture::VtkVis;
32
33Volume::Volume() :
34    VtkGraphicsObject(),
35    _colorMap(NULL)
36{
37}
38
39Volume::~Volume()
40{
41#ifdef WANT_TRACE
42    if (_dataSet != NULL)
43        TRACE("Deleting Volume for %s", _dataSet->getName().c_str());
44    else
45        TRACE("Deleting Volume with NULL DataSet");
46#endif
47}
48
49/**
50 * \brief Create and initialize a VTK Prop to render the Volume
51 */
52void Volume::initProp()
53{
54    if (_prop == NULL) {
55        _prop = vtkSmartPointer<vtkVolume>::New();
56        getVolume()->GetProperty()->SetInterpolationTypeToLinear();
57    }
58}
59
60/**
61 * \brief Get the voxel dimensions (if the volume is not a
62 * uniform grid, unit spacing is returned)
63 */
64void Volume::getSpacing(double spacing[3])
65{
66    spacing[0] = spacing[1] = spacing[2] = 1.0;
67    if (_dataSet == NULL)
68        return;
69    vtkDataSet *ds = _dataSet->getVtkDataSet();
70    if (ds != NULL && vtkImageData::SafeDownCast(ds) != NULL) {
71        vtkImageData::SafeDownCast(ds)->GetSpacing(spacing);
72    } else if (ds != NULL && vtkVolumeMapper::SafeDownCast(_volumeMapper) != NULL) {
73        vtkImageData *imgData = vtkVolumeMapper::SafeDownCast(_volumeMapper)->GetInput();
74        if (imgData != NULL) {
75            imgData->GetSpacing(spacing);
76        }
77    }
78}
79
80/**
81 * \brief Get the average voxel dimension (if the volume is not a
82 * uniform grid, unit spacing is returned)
83 */
84double Volume::getAverageSpacing()
85{
86    double spacing[3];
87    getSpacing(spacing);
88    return (spacing[0] + spacing[1] + spacing[2]) * 0.333;
89}
90
91/**
92 * \brief Internal method to set up pipeline after a state change
93 */
94void Volume::update()
95{
96    if (_dataSet == NULL)
97        return;
98
99    vtkDataSet *ds = _dataSet->getVtkDataSet();
100
101    if (_dataSet->is2D()) {
102        ERROR("Volume requires a 3D DataSet");
103        _dataSet = NULL;
104        return;
105    }
106
107    if (vtkImageData::SafeDownCast(ds) != NULL) {
108        // Image data required for these mappers
109#ifdef USE_GPU_RAYCAST_MAPPER
110        _volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
111        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->AutoAdjustSampleDistancesOff();
112#else
113        _volumeMapper = vtkSmartPointer<vtkVolumeTextureMapper3D>::New();
114#endif
115#ifdef USE_VTK6
116#ifdef USE_GPU_RAYCAST_MAPPER
117        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->SetInputData(ds);
118#else
119        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper)->SetInputData(ds);
120#endif
121#else
122        _volumeMapper->SetInput(ds);
123#endif
124        vtkVolumeMapper::SafeDownCast(_volumeMapper)->SetBlendModeToComposite();
125    } else if (vtkUnstructuredGrid::SafeDownCast(ds) != NULL) {
126        vtkUnstructuredGrid *ugrid = vtkUnstructuredGrid::SafeDownCast(ds);
127        // DataSet is unstructured grid
128        // Only works if cells are all tetrahedra
129        _volumeMapper = vtkSmartPointer<vtkProjectedTetrahedraMapper>::New();
130        // Software raycast rendering - requires all tetrahedra
131        //_volumeMapper = vtkSmartPointer<vtkUnstructuredGridVolumeRayCastMapper>::New();
132        if (ugrid->GetCellType(0) == VTK_TETRA &&
133            ugrid->IsHomogeneous()) {
134#ifdef USE_VTK6
135            vtkProjectedTetrahedraMapper::SafeDownCast(_volumeMapper)->SetInputData(ds);
136#else
137            _volumeMapper->SetInput(ds);
138#endif
139        } else {
140            // Decompose to tetrahedra
141            vtkSmartPointer<vtkDataSetTriangleFilter> filter =
142                vtkSmartPointer<vtkDataSetTriangleFilter>::New();
143#ifdef USE_VTK6
144            filter->SetInputData(ugrid);
145#else
146            filter->SetInput(ugrid);
147#endif
148            filter->TetrahedraOnlyOn();
149            _volumeMapper->SetInputConnection(filter->GetOutputPort());
150        }
151
152        vtkUnstructuredGridVolumeMapper::SafeDownCast(_volumeMapper)->
153            SetBlendModeToComposite();
154    } else if (vtkPolyData::SafeDownCast(ds) != NULL &&
155               vtkPolyData::SafeDownCast(ds)->GetNumberOfLines() == 0 &&
156               vtkPolyData::SafeDownCast(ds)->GetNumberOfPolys() == 0 &&
157               vtkPolyData::SafeDownCast(ds)->GetNumberOfStrips() == 0 ) {
158        // DataSet is a 3D point cloud
159        vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
160#ifdef USE_VTK6
161        splatter->SetInputData(ds);
162#else
163        splatter->SetInput(ds);
164#endif
165        int dims[3];
166        dims[0] = dims[1] = dims[2] = 64;
167        TRACE("Generating volume with dims (%d,%d,%d) from point cloud",
168              dims[0], dims[1], dims[2]);
169        splatter->SetSampleDimensions(dims);
170#ifdef USE_GPU_RAYCAST_MAPPER
171        _volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
172        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->AutoAdjustSampleDistancesOff();
173#else
174        _volumeMapper = vtkSmartPointer<vtkVolumeTextureMapper3D>::New();
175#endif
176        _volumeMapper->SetInputConnection(splatter->GetOutputPort());
177        vtkVolumeMapper::SafeDownCast(_volumeMapper)->SetBlendModeToComposite();
178    } else {
179        ERROR("Unsupported DataSet type: %s", _dataSet->getVtkType());
180        _dataSet = NULL;
181        return;
182    }
183
184    TRACE("Using mapper type: %s", _volumeMapper->GetClassName());
185
186    initProp();
187
188    if (ds->GetPointData() == NULL ||
189        ds->GetPointData()->GetScalars() == NULL) {
190        WARN("No scalar point data in dataset %s", _dataSet->getName().c_str());
191    }
192
193    if (_colorMap == NULL) {
194        setColorMap(ColorMap::getVolumeDefault());
195    }
196
197    setSampleDistance(getAverageSpacing());
198
199    getVolume()->SetMapper(_volumeMapper);
200    _volumeMapper->Update();
201}
202
203void Volume::updateRanges(Renderer *renderer)
204{
205    VtkGraphicsObject::updateRanges(renderer);
206
207    if (getVolume() != NULL) {
208        getVolume()->GetProperty()->SetColor(_colorMap->getColorTransferFunction(_dataRange));
209        getVolume()->GetProperty()->SetScalarOpacity(_colorMap->getOpacityTransferFunction(_dataRange));
210    }
211}
212
213void Volume::updateColorMap()
214{
215    setColorMap(_colorMap);
216}
217
218/**
219 * \brief Assign a color map (transfer function) to use in rendering the Volume
220 */
221void Volume::setColorMap(ColorMap *cmap)
222{
223    if (cmap == NULL)
224        return;
225
226    _colorMap = cmap;
227
228    if (getVolume() != NULL) {
229        getVolume()->GetProperty()->SetColor(_colorMap->getColorTransferFunction(_dataRange));
230        getVolume()->GetProperty()->SetScalarOpacity(_colorMap->getOpacityTransferFunction(_dataRange));
231    }
232}
233
234/**
235 * \brief Return the ColorMap assigned to this Volume
236 */
237ColorMap *Volume::getColorMap()
238{
239    return _colorMap;
240}
241
242/**
243 * \brief Set opacity scaling used to render the Volume
244 */
245void Volume::setOpacity(double opacity)
246{
247    _opacity = opacity;
248    // FIXME: There isn't really a good opacity scaling option that works
249    // across the different mappers/algorithms.  This only works with the
250    // 3D texture mapper, not the GPU raycast mapper
251    if (getVolume() != NULL) {
252        if (opacity < 1.0e-6)
253            opacity = 1.0e-6;
254        getVolume()->GetProperty()->SetScalarOpacityUnitDistance(1.0/opacity);
255    }
256}
257
258/**
259 * \brief Set a group of world coordinate planes to clip rendering
260 *
261 * Passing NULL for planes will remove all cliping planes
262 */
263void Volume::setClippingPlanes(vtkPlaneCollection *planes)
264{
265    if (_volumeMapper != NULL) {
266        _volumeMapper->SetClippingPlanes(planes);
267    }
268}
269
270/**
271 * \brief Set distance between samples along rays
272 */
273void Volume::setSampleDistance(float d)
274{
275    TRACE("Sample distance: %g", d);
276    if (_volumeMapper != NULL &&
277#ifdef USE_GPU_RAYCAST_MAPPER
278        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper) != NULL) {
279        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->SetSampleDistance(d);
280#else
281        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper) != NULL) {
282        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper)->SetSampleDistance(d);
283#endif
284    }
285}
Note: See TracBrowser for help on using the repository browser.