1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkUnstructuredGridVolumeRayCastMapper.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkUnstructuredGridVolumeRayCastMapper.h"
16
17 #include "vtkCamera.h"
18 #include "vtkEncodedGradientEstimator.h"
19 #include "vtkEncodedGradientShader.h"
20 #include "vtkFiniteDifferenceGradientEstimator.h"
21 #include "vtkUnstructuredGrid.h"
22 #include "vtkMath.h"
23 #include "vtkMultiThreader.h"
24 #include "vtkObjectFactory.h"
25 #include "vtkPlaneCollection.h"
26 #include "vtkPointData.h"
27 #include "vtkRenderWindow.h"
28 #include "vtkRenderer.h"
29 #include "vtkTimerLog.h"
30 #include "vtkTransform.h"
31 #include "vtkVolumeProperty.h"
32 #include "vtkUnstructuredGridBunykRayCastFunction.h"
33 #include "vtkUnstructuredGridVolumeRayCastIterator.h"
34 #include "vtkUnstructuredGridPreIntegration.h"
35 #include "vtkUnstructuredGridPartialPreIntegration.h"
36 #include "vtkUnstructuredGridHomogeneousRayIntegrator.h"
37 #include "vtkRayCastImageDisplayHelper.h"
38 #include "vtkDoubleArray.h"
39 #include "vtkIdList.h"
40
41 #include <cmath>
42
43 VTK_THREAD_RETURN_TYPE UnstructuredGridVolumeRayCastMapper_CastRays( void *arg );
44
45
46 vtkStandardNewMacro(vtkUnstructuredGridVolumeRayCastMapper);
47
48 vtkCxxSetObjectMacro(vtkUnstructuredGridVolumeRayCastMapper, RayCastFunction,
49 vtkUnstructuredGridVolumeRayCastFunction);
50 vtkCxxSetObjectMacro(vtkUnstructuredGridVolumeRayCastMapper, RayIntegrator,
51 vtkUnstructuredGridVolumeRayIntegrator);
52
53 // Construct a new vtkUnstructuredGridVolumeRayCastMapper with default values
vtkUnstructuredGridVolumeRayCastMapper()54 vtkUnstructuredGridVolumeRayCastMapper::vtkUnstructuredGridVolumeRayCastMapper()
55 {
56 this->ImageSampleDistance = 1.0;
57 this->MinimumImageSampleDistance = 1.0;
58 this->MaximumImageSampleDistance = 10.0;
59 this->AutoAdjustSampleDistances = 1;
60
61 this->ImageMemorySize[0] = 0;
62 this->ImageMemorySize[1] = 0;
63
64 this->Threader = vtkMultiThreader::New();
65 this->NumberOfThreads = this->Threader->GetNumberOfThreads();
66
67 this->Image = nullptr;
68
69 this->RenderTimeTable = nullptr;
70 this->RenderVolumeTable = nullptr;
71 this->RenderRendererTable = nullptr;
72 this->RenderTableSize = 0;
73 this->RenderTableEntries = 0;
74
75 this->ZBuffer = nullptr;
76 this->ZBufferSize[0] = 0;
77 this->ZBufferSize[1] = 0;
78 this->ZBufferOrigin[0] = 0;
79 this->ZBufferOrigin[1] = 0;
80
81 this->IntermixIntersectingGeometry = 1;
82
83 this->ImageDisplayHelper = vtkRayCastImageDisplayHelper::New();
84
85 this->RayCastFunction = vtkUnstructuredGridBunykRayCastFunction::New();
86 this->RayIntegrator = nullptr;
87 this->RealRayIntegrator = nullptr;
88 }
89
90 // Destruct a vtkUnstructuredGridVolumeRayCastMapper - clean up any memory used
~vtkUnstructuredGridVolumeRayCastMapper()91 vtkUnstructuredGridVolumeRayCastMapper::~vtkUnstructuredGridVolumeRayCastMapper()
92 {
93 this->Threader->Delete();
94
95 delete [] this->Image;
96
97 if ( this->RenderTableSize )
98 {
99 delete [] this->RenderTimeTable;
100 delete [] this->RenderVolumeTable;
101 delete [] this->RenderRendererTable;
102 }
103
104 this->ImageDisplayHelper->Delete();
105
106 this->SetRayCastFunction(nullptr);
107 this->SetRayIntegrator(nullptr);
108 if (this->RealRayIntegrator)
109 {
110 this->RealRayIntegrator->UnRegister(this);
111 }
112 }
113
RetrieveRenderTime(vtkRenderer * ren,vtkVolume * vol)114 float vtkUnstructuredGridVolumeRayCastMapper::RetrieveRenderTime( vtkRenderer *ren,
115 vtkVolume *vol )
116 {
117 int i;
118
119 for ( i = 0; i < this->RenderTableEntries; i++ )
120 {
121 if ( this->RenderVolumeTable[i] == vol &&
122 this->RenderRendererTable[i] == ren )
123 {
124 return this->RenderTimeTable[i];
125 }
126 }
127
128 return 0.0;
129 }
130
StoreRenderTime(vtkRenderer * ren,vtkVolume * vol,float time)131 void vtkUnstructuredGridVolumeRayCastMapper::StoreRenderTime( vtkRenderer *ren,
132 vtkVolume *vol,
133 float time )
134 {
135 int i;
136 for ( i = 0; i < this->RenderTableEntries; i++ )
137 {
138 if ( this->RenderVolumeTable[i] == vol &&
139 this->RenderRendererTable[i] == ren )
140 {
141 this->RenderTimeTable[i] = time;
142 return;
143 }
144 }
145
146
147 // Need to increase size
148 if ( this->RenderTableEntries >= this->RenderTableSize )
149 {
150 if ( this->RenderTableSize == 0 )
151 {
152 this->RenderTableSize = 10;
153 }
154 else
155 {
156 this->RenderTableSize *= 2;
157 }
158
159 float *oldTimePtr = this->RenderTimeTable;
160 vtkVolume **oldVolumePtr = this->RenderVolumeTable;
161 vtkRenderer **oldRendererPtr = this->RenderRendererTable;
162
163 this->RenderTimeTable = new float [this->RenderTableSize];
164 this->RenderVolumeTable = new vtkVolume *[this->RenderTableSize];
165 this->RenderRendererTable = new vtkRenderer *[this->RenderTableSize];
166
167 for (i = 0; i < this->RenderTableEntries; i++ )
168 {
169 this->RenderTimeTable[i] = oldTimePtr[i];
170 this->RenderVolumeTable[i] = oldVolumePtr[i];
171 this->RenderRendererTable[i] = oldRendererPtr[i];
172 }
173
174 delete [] oldTimePtr;
175 delete [] oldVolumePtr;
176 delete [] oldRendererPtr;
177 }
178
179 this->RenderTimeTable[this->RenderTableEntries] = time;
180 this->RenderVolumeTable[this->RenderTableEntries] = vol;
181 this->RenderRendererTable[this->RenderTableEntries] = ren;
182
183 this->RenderTableEntries++;
184 }
185
ReleaseGraphicsResources(vtkWindow *)186 void vtkUnstructuredGridVolumeRayCastMapper::ReleaseGraphicsResources(vtkWindow *)
187 {
188 }
189
Render(vtkRenderer * ren,vtkVolume * vol)190 void vtkUnstructuredGridVolumeRayCastMapper::Render( vtkRenderer *ren, vtkVolume *vol )
191 {
192 int i;
193
194 // Check for input
195 if ( this->GetInput() == nullptr )
196 {
197 vtkErrorMacro(<< "No Input!");
198 return;
199 }
200
201 int inputAlgPort;
202 vtkAlgorithm* inputAlg = this->GetInputAlgorithm(0, 0, inputAlgPort);
203 inputAlg->UpdateWholeExtent();
204
205 this->Scalars = this->GetScalars(this->GetInput(), this->ScalarMode,
206 this->ArrayAccessMode,
207 this->ArrayId, this->ArrayName,
208 this->CellScalars);
209
210 if (this->Scalars == nullptr)
211 {
212 vtkErrorMacro("Can't use the ray cast mapper without scalars!");
213 return;
214 }
215
216 // Check to make sure we have an appropriate integrator.
217 if (this->RayIntegrator)
218 {
219 if (this->RealRayIntegrator != this->RayIntegrator)
220 {
221 if (this->RealRayIntegrator)
222 {
223 this->RealRayIntegrator->UnRegister(this);
224 }
225 this->RealRayIntegrator = this->RayIntegrator;
226 this->RealRayIntegrator->Register(this);
227 }
228 }
229 else
230 {
231
232 #define ESTABLISH_INTEGRATOR(classname) \
233 if ( !this->RealRayIntegrator \
234 || (!this->RealRayIntegrator->IsA(#classname)) ) \
235 { \
236 if (this->RealRayIntegrator) this->RealRayIntegrator->UnRegister(this); \
237 this->RealRayIntegrator = classname::New(); \
238 this->RealRayIntegrator->Register(this); \
239 this->RealRayIntegrator->Delete(); \
240 } \
241
242 if (this->CellScalars)
243 {
244 ESTABLISH_INTEGRATOR(vtkUnstructuredGridHomogeneousRayIntegrator);
245 }
246 else
247 {
248 if (vol->GetProperty()->GetIndependentComponents())
249 {
250 ESTABLISH_INTEGRATOR(vtkUnstructuredGridPreIntegration);
251 }
252 else
253 {
254 ESTABLISH_INTEGRATOR(vtkUnstructuredGridPartialPreIntegration);
255 }
256 }
257 }
258
259 #undef ESTABLISH_INTEGRATOR
260
261 // Start timing now. We didn't want to capture the update of the
262 // input data in the times
263 this->Timer->StartTimer();
264
265 int oldImageMemorySize[2];
266 oldImageMemorySize[0] = this->ImageMemorySize[0];
267 oldImageMemorySize[1] = this->ImageMemorySize[1];
268
269 // If we are automatically adjusting the size to achieve a desired frame
270 // rate, then do that adjustment here. Base the new image sample distance
271 // on the previous one and the previous render time. Don't let
272 // the adjusted image sample distance be less than the minimum image sample
273 // distance or more than the maximum image sample distance.
274 float oldImageSampleDistance = this->ImageSampleDistance;
275 if ( this->AutoAdjustSampleDistances )
276 {
277 float oldTime = this->RetrieveRenderTime( ren, vol );
278 float newTime = vol->GetAllocatedRenderTime();
279 this->ImageSampleDistance *= sqrt(oldTime / newTime);
280 this->ImageSampleDistance =
281 (this->ImageSampleDistance>this->MaximumImageSampleDistance)?
282 (this->MaximumImageSampleDistance):(this->ImageSampleDistance);
283 this->ImageSampleDistance =
284 (this->ImageSampleDistance<this->MinimumImageSampleDistance)?
285 (this->MinimumImageSampleDistance):(this->ImageSampleDistance);
286 }
287
288 // The full image fills the viewport. First, compute the actual viewport
289 // size, then divide by the ImageSampleDistance to find the full image
290 // size in pixels
291 int width, height;
292 ren->GetTiledSize(&width, &height);
293 this->ImageViewportSize[0] =
294 static_cast<int>(width/this->ImageSampleDistance);
295 this->ImageViewportSize[1] =
296 static_cast<int>(height/this->ImageSampleDistance);
297
298 this->ImageInUseSize[0] = this->ImageViewportSize[0];
299 this->ImageInUseSize[1] = this->ImageViewportSize[1];
300 this->ImageOrigin[0] = 0;
301 this->ImageOrigin[1] = 0;
302
303 // What is a power of 2 size big enough to fit this image?
304 this->ImageMemorySize[0] = 32;
305 this->ImageMemorySize[1] = 32;
306 while ( this->ImageMemorySize[0] < this->ImageInUseSize[0] )
307 {
308 this->ImageMemorySize[0] *= 2;
309 }
310 while ( this->ImageMemorySize[1] < this->ImageInUseSize[1] )
311 {
312 this->ImageMemorySize[1] *= 2;
313 }
314
315 // If the old image size is much too big (more than twice in
316 // either direction) then set the old width to 0 which will
317 // cause the image to be recreated
318 if ( oldImageMemorySize[0] > 2*this->ImageMemorySize[0] ||
319 oldImageMemorySize[1] > 2*this->ImageMemorySize[1] )
320 {
321 oldImageMemorySize[0] = 0;
322 }
323
324 // If the old image is big enough (but not too big - we handled
325 // that above) then we'll bump up our required size to the
326 // previous one. This will keep us from thrashing.
327 if ( oldImageMemorySize[0] >= this->ImageMemorySize[0] &&
328 oldImageMemorySize[1] >= this->ImageMemorySize[1] )
329 {
330 this->ImageMemorySize[0] = oldImageMemorySize[0];
331 this->ImageMemorySize[1] = oldImageMemorySize[1];
332 }
333
334 // Do we already have a texture big enough? If not, create a new one and
335 // clear it.
336 if ( !this->Image ||
337 this->ImageMemorySize[0] > oldImageMemorySize[0] ||
338 this->ImageMemorySize[1] > oldImageMemorySize[1] )
339 {
340 // If there is an image there must be row bounds
341 delete [] this->Image;
342
343 this->Image = new unsigned char[(this->ImageMemorySize[0] *
344 this->ImageMemorySize[1] * 4)];
345
346 unsigned char *ucptr = this->Image;
347
348 for ( i = 0; i < this->ImageMemorySize[0]*this->ImageMemorySize[1]; i++ )
349 {
350 *(ucptr++) = 0;
351 *(ucptr++) = 0;
352 *(ucptr++) = 0;
353 *(ucptr++) = 0;
354 }
355 }
356
357 // Capture the zbuffer if necessary
358 if ( this->IntermixIntersectingGeometry &&
359 ren->GetNumberOfPropsRendered() )
360 {
361 int x1, x2, y1, y2;
362 double *viewport = ren->GetViewport();
363 int *renWinSize = ren->GetRenderWindow()->GetSize();
364
365 // turn this->ImageOrigin into (x1,y1) in window (not viewport!)
366 // coordinates.
367 x1 = static_cast<int> (
368 viewport[0] * static_cast<float>(renWinSize[0]) +
369 static_cast<float>(this->ImageOrigin[0]) * this->ImageSampleDistance );
370 y1 = static_cast<int> (
371 viewport[1] * static_cast<float>(renWinSize[1]) +
372 static_cast<float>(this->ImageOrigin[1]) * this->ImageSampleDistance);
373
374 // compute z buffer size
375 this->ZBufferSize[0] = static_cast<int>(
376 static_cast<float>(this->ImageInUseSize[0]) * this->ImageSampleDistance);
377 this->ZBufferSize[1] = static_cast<int>(
378 static_cast<float>(this->ImageInUseSize[1]) * this->ImageSampleDistance);
379
380 // Use the size to compute (x2,y2) in window coordinates
381 x2 = x1 + this->ZBufferSize[0] - 1;
382 y2 = y1 + this->ZBufferSize[1] - 1;
383
384 // This is the z buffer origin (in viewport coordinates)
385 this->ZBufferOrigin[0] = static_cast<int>(
386 static_cast<float>(this->ImageOrigin[0]) * this->ImageSampleDistance);
387 this->ZBufferOrigin[1] = static_cast<int>(
388 static_cast<float>(this->ImageOrigin[1]) * this->ImageSampleDistance);
389
390 // Capture the z buffer
391 this->ZBuffer = ren->GetRenderWindow()->GetZbufferData(x1,y1,x2,y2);
392 }
393
394 this->RayCastFunction->Initialize( ren, vol );
395
396 this->RealRayIntegrator->Initialize(vol, this->Scalars);
397
398 // Save the volume and mapper temporarily so that they can be accessed later
399 this->CurrentVolume = vol;
400 this->CurrentRenderer = ren;
401
402 // Create iterators and buffers here to prevent race conditions.
403 this->RayCastIterators
404 = new vtkUnstructuredGridVolumeRayCastIterator*[this->NumberOfThreads];
405 this->IntersectedCellsBuffer = new vtkIdList*[this->NumberOfThreads];
406 this->IntersectionLengthsBuffer = new vtkDoubleArray*[this->NumberOfThreads];
407 this->NearIntersectionsBuffer = new vtkDataArray*[this->NumberOfThreads];
408 this->FarIntersectionsBuffer = new vtkDataArray*[this->NumberOfThreads];
409 for (i = 0; i < this->NumberOfThreads; i++)
410 {
411 this->RayCastIterators[i] = this->RayCastFunction->NewIterator();
412 this->IntersectionLengthsBuffer[i] = vtkDoubleArray::New();
413 this->IntersectionLengthsBuffer[i]
414 ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
415 this->NearIntersectionsBuffer[i]
416 = vtkDataArray::CreateDataArray(this->Scalars->GetDataType());
417 this->NearIntersectionsBuffer[i]
418 ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
419 if (this->CellScalars)
420 {
421 this->IntersectedCellsBuffer[i] = vtkIdList::New();
422 this->IntersectedCellsBuffer[i]
423 ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
424 this->FarIntersectionsBuffer[i] = this->NearIntersectionsBuffer[i];
425 }
426 else
427 {
428 this->IntersectedCellsBuffer[i] = nullptr;
429 this->FarIntersectionsBuffer[i]
430 = vtkDataArray::CreateDataArray(this->Scalars->GetDataType());
431 this->FarIntersectionsBuffer[i]
432 ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
433 }
434 }
435
436 // Set the number of threads to use for ray casting,
437 // then set the execution method and do it.
438 this->Threader->SetNumberOfThreads( this->NumberOfThreads );
439 this->Threader->SetSingleMethod( UnstructuredGridVolumeRayCastMapper_CastRays,
440 (void *)this);
441 this->Threader->SingleMethodExecute();
442
443 // We don't need these anymore
444 this->CurrentVolume = nullptr;
445 this->CurrentRenderer = nullptr;
446 for (i = 0; i < this->NumberOfThreads; i++)
447 {
448 this->RayCastIterators[i]->Delete();
449 this->IntersectionLengthsBuffer[i]->Delete();
450 this->NearIntersectionsBuffer[i]->Delete();
451 if (this->CellScalars)
452 {
453 this->IntersectedCellsBuffer[i]->Delete();
454 }
455 else
456 {
457 this->FarIntersectionsBuffer[i]->Delete();
458 }
459 }
460 delete[] this->RayCastIterators;
461 delete[] this->IntersectedCellsBuffer;
462 delete[] this->IntersectionLengthsBuffer;
463 delete[] this->NearIntersectionsBuffer;
464 delete[] this->FarIntersectionsBuffer;
465
466 if ( !ren->GetRenderWindow()->GetAbortRender() )
467 {
468 float depth;
469 if ( this->IntermixIntersectingGeometry )
470 {
471 depth = this->GetMinimumBoundsDepth( ren, vol );
472 }
473 else
474 {
475 depth = -1;
476 }
477
478 this->ImageDisplayHelper->
479 RenderTexture( vol, ren,
480 this->ImageMemorySize,
481 this->ImageViewportSize,
482 this->ImageInUseSize,
483 this->ImageOrigin,
484 depth,
485 this->Image );
486
487 this->Timer->StopTimer();
488 this->TimeToDraw = this->Timer->GetElapsedTime();
489 this->StoreRenderTime( ren, vol, this->TimeToDraw );
490 }
491 else
492 {
493 this->ImageSampleDistance = oldImageSampleDistance;
494 }
495
496
497 delete [] this->ZBuffer;
498 this->ZBuffer = nullptr;
499
500 this->UpdateProgress(1.0);
501 }
502
UnstructuredGridVolumeRayCastMapper_CastRays(void * arg)503 VTK_THREAD_RETURN_TYPE UnstructuredGridVolumeRayCastMapper_CastRays( void *arg )
504 {
505 // Get the info out of the input structure
506 int threadID = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
507 int threadCount = ((vtkMultiThreader::ThreadInfo *)(arg))->NumberOfThreads;
508 vtkUnstructuredGridVolumeRayCastMapper *me =
509 (vtkUnstructuredGridVolumeRayCastMapper *)((vtkMultiThreader::ThreadInfo *)arg)->UserData;
510
511 if ( !me )
512 {
513 vtkGenericWarningMacro("The volume does not have a ray cast mapper!");
514 return VTK_THREAD_RETURN_VALUE;
515 }
516
517 me->CastRays( threadID, threadCount );
518
519 return VTK_THREAD_RETURN_VALUE;
520 }
521
522 template<class T>
vtkUGVRCMLookupCopy(const T * src,T * dest,vtkIdType * lookup,int numcomponents,int numtuples)523 inline void vtkUGVRCMLookupCopy(const T *src, T *dest, vtkIdType *lookup,
524 int numcomponents, int numtuples)
525 {
526 for (vtkIdType i = 0; i < numtuples; i++)
527 {
528 const T *srctuple = src + lookup[i] * numcomponents;
529 for (int j = 0; j < numcomponents; j++)
530 {
531 *dest = *srctuple;
532 dest++; srctuple++;
533 }
534 }
535 }
536
CastRays(int threadID,int threadCount)537 void vtkUnstructuredGridVolumeRayCastMapper::CastRays( int threadID, int threadCount )
538 {
539 int i, j;
540 unsigned char *ucptr;
541
542 vtkRenderWindow *renWin = this->CurrentRenderer->GetRenderWindow();
543 vtkUnstructuredGridVolumeRayCastIterator *iterator
544 = this->RayCastIterators[threadID];
545
546 vtkIdList *intersectedCells = this->IntersectedCellsBuffer[threadID];
547 vtkDoubleArray *intersectionLengths=this->IntersectionLengthsBuffer[threadID];
548 vtkDataArray *nearIntersections = this->NearIntersectionsBuffer[threadID];
549 vtkDataArray *farIntersections = this->FarIntersectionsBuffer[threadID];
550
551 for ( j = 0; j < this->ImageInUseSize[1]; j++ )
552 {
553 if ( j%threadCount != threadID )
554 {
555 continue;
556 }
557
558 if ( !threadID )
559 {
560 this->UpdateProgress((double)j/this->ImageInUseSize[1]);
561 if ( renWin->CheckAbortStatus() )
562 {
563 break;
564 }
565 }
566 else if ( renWin->GetAbortRender() )
567 {
568 break;
569 }
570
571 ucptr = this->Image + 4*j*this->ImageMemorySize[0];
572
573 for ( i = 0; i < this->ImageInUseSize[0]; i++ )
574 {
575 int x = i + this->ImageOrigin[0];
576 int y = j + this->ImageOrigin[1];
577
578 double bounds[2] = {0.0,1.0};
579 float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
580
581 if ( this->ZBuffer )
582 {
583 bounds[1] = this->GetZBufferValue( x, y );
584 }
585
586 iterator->SetBounds(bounds);
587 iterator->Initialize(x, y);
588
589 vtkIdType numIntersections;
590 do
591 {
592 if (this->CellScalars)
593 {
594 numIntersections = iterator->GetNextIntersections(intersectedCells,
595 intersectionLengths,
596 nullptr,
597 nullptr, nullptr);
598 nearIntersections
599 ->SetNumberOfComponents(this->Scalars->GetNumberOfComponents());
600 nearIntersections->SetNumberOfTuples(numIntersections);
601 switch (this->Scalars->GetDataType())
602 {
603 vtkTemplateMacro(vtkUGVRCMLookupCopy
604 ((const VTK_TT*)this->Scalars->GetVoidPointer(0),
605 (VTK_TT*)nearIntersections->GetVoidPointer(0),
606 intersectedCells->GetPointer(0),
607 this->Scalars->GetNumberOfComponents(),
608 numIntersections));
609 }
610 }
611 else
612 {
613 numIntersections = iterator->GetNextIntersections(nullptr,
614 intersectionLengths,
615 this->Scalars,
616 nearIntersections,
617 farIntersections);
618 }
619 if (numIntersections < 1) break;
620 this->RealRayIntegrator->Integrate(intersectionLengths,
621 nearIntersections,
622 farIntersections,
623 color);
624 } while (color[3] < 0.99);
625
626 if ( color[3] > 0.0 )
627 {
628 int val;
629 val = static_cast<int>(color[0]*255.0);
630 val = (val > 255)?(255):(val);
631 val = (val < 0)?( 0):(val);
632 ucptr[0] = static_cast<unsigned char>(val);
633
634 val = static_cast<int>(color[1]*255.0);
635 val = (val > 255)?(255):(val);
636 val = (val < 0)?( 0):(val);
637 ucptr[1] = static_cast<unsigned char>(val);
638
639 val = static_cast<int>(color[2]*255.0);
640 val = (val > 255)?(255):(val);
641 val = (val < 0)?( 0):(val);
642 ucptr[2] = static_cast<unsigned char>(val);
643
644 val = static_cast<int>(color[3]*255.0);
645 val = (val > 255)?(255):(val);
646 val = (val < 0)?( 0):(val);
647 ucptr[3] = static_cast<unsigned char>(val);
648 }
649 else
650 {
651 ucptr[0] = 0;
652 ucptr[1] = 0;
653 ucptr[2] = 0;
654 ucptr[3] = 0;
655 }
656 ucptr+=4;
657 }
658 }
659 }
660
661 double vtkUnstructuredGridVolumeRayCastMapper::
GetMinimumBoundsDepth(vtkRenderer * ren,vtkVolume * vol)662 GetMinimumBoundsDepth( vtkRenderer *ren, vtkVolume *vol )
663 {
664 double bounds[6];
665 vol->GetBounds( bounds );
666
667 vtkTransform *perspectiveTransform = vtkTransform::New();
668 vtkMatrix4x4 *perspectiveMatrix = vtkMatrix4x4::New();
669
670 ren->ComputeAspect();
671 double *aspect = ren->GetAspect();
672
673 // Get the view matrix in two steps - there is a one step method in camera
674 // but it turns off stereo so we do not want to use that one
675 vtkCamera *cam = ren->GetActiveCamera();
676 perspectiveTransform->Identity();
677 perspectiveTransform->Concatenate(
678 cam->GetProjectionTransformMatrix(aspect[0]/aspect[1], 0.0, 1.0 ));
679 perspectiveTransform->Concatenate(cam->GetViewTransformMatrix());
680 perspectiveMatrix->DeepCopy(perspectiveTransform->GetMatrix());
681
682 double minZ = 1.0;
683
684 for ( int k = 0; k < 2; k++ )
685 {
686 for ( int j = 0; j < 2; j++ )
687 {
688 for ( int i = 0; i < 2; i++ )
689 {
690 double inPoint[4];
691 inPoint[0] = bounds[ i];
692 inPoint[1] = bounds[2+j];
693 inPoint[2] = bounds[4+k];
694 inPoint[3] = 1.0;
695
696 double outPoint[4];
697 perspectiveMatrix->MultiplyPoint( inPoint, outPoint );
698 double testZ = outPoint[2] / outPoint[3];
699 minZ = ( testZ < minZ ) ? (testZ) : (minZ);
700 }
701 }
702 }
703
704 perspectiveTransform->Delete();
705 perspectiveMatrix->Delete();
706
707 return minZ;
708 }
709
GetZBufferValue(int x,int y)710 double vtkUnstructuredGridVolumeRayCastMapper::GetZBufferValue(int x, int y)
711 {
712 int xPos, yPos;
713
714 xPos = static_cast<int>(static_cast<float>(x) * this->ImageSampleDistance);
715 yPos = static_cast<int>(static_cast<float>(y) * this->ImageSampleDistance);
716
717 xPos = (xPos >= this->ZBufferSize[0])?(this->ZBufferSize[0]-1):(xPos);
718 yPos = (yPos >= this->ZBufferSize[1])?(this->ZBufferSize[1]-1):(yPos);
719
720 return *(this->ZBuffer + yPos*this->ZBufferSize[0] + xPos);
721 }
722
723 // Print method for vtkUnstructuredGridVolumeRayCastMapper
PrintSelf(ostream & os,vtkIndent indent)724 void vtkUnstructuredGridVolumeRayCastMapper::PrintSelf(ostream& os, vtkIndent indent)
725 {
726 this->Superclass::PrintSelf(os,indent);
727
728 os << indent << "Image Sample Distance: "
729 << this->ImageSampleDistance << "\n";
730 os << indent << "Minimum Image Sample Distance: "
731 << this->MinimumImageSampleDistance << "\n";
732 os << indent << "Maximum Image Sample Distance: "
733 << this->MaximumImageSampleDistance << "\n";
734 os << indent << "Auto Adjust Sample Distances: "
735 << this->AutoAdjustSampleDistances << "\n";
736 os << indent << "Intermix Intersecting Geometry: "
737 << (this->IntermixIntersectingGeometry ? "On\n" : "Off\n");
738
739 os << indent << "Number Of Threads: " << this->NumberOfThreads << "\n";
740
741 if (this->RayCastFunction)
742 {
743 os << indent << "RayCastFunction: " <<
744 this->RayCastFunction->GetClassName() << "\n";
745 }
746 else
747 {
748 os << indent << "RayCastFunction: (none)\n";
749 }
750
751 if (this->RayIntegrator)
752 {
753 os << indent << "RayIntegrator: "
754 << this->RayIntegrator->GetClassName() << endl;
755 }
756 else
757 {
758 os << indent << "RayIntegrator: (automatic)" << endl;
759 }
760
761 // Do not want to print this->ImageOrigin, this->ImageViewportSize or
762 // this->ImageInUseSize since these are just internal variables with Get
763 // methods for access from the ray cast function (not part of the public
764 // API)
765 }
766
767