[vtkusers] Minecraft-style volume rendering
Tim Hutton
tim.hutton at gmail.com
Mon Apr 2 06:22:54 EDT 2012
A follow-up question: Is there a way to do this as a VTK pipeline? At
the moment it needs a manual call to pad->Update() and
pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars())
every time the image changes (full code below). This is a problem for
my application where I've been keeping the rendering pipeline separate
from the image-updating code, and where the user can choose how the
pipeline is set up.
// Adapted from GenerateCubesFromLabels.cxx (can use the same CMakeLists.txt)
#include <vtkImageWrapPad.h>
#include <vtkThreshold.h>
#include <vtkTransformFilter.h>
#include <vtkGeometryFilter.h>
#include <vtkSmartPointer.h>
#include <vtkTransform.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyDataMapper.h>
int* vtk_at(int* origin,int x,int y,int z,int X,int Y)
{
// single-component vtkImageData scalars are stored as:
int,int,... for consecutive x, then y, then z
return origin + x + X*(y + Y*z);
}
int main ()
{
const int X=30,Y=25,Z=20;
vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New();
image->SetExtent(0,X-1,0,Y-1,0,Z-1);
image->SetScalarTypeToInt();
image->SetNumberOfScalarComponents(1);
image->AllocateScalars();
int* image_data = static_cast<int*>(image->GetScalarPointer());
// add 4 cubes in a simple pattern
for(int i=0;i<X*Y*Z;i++) image_data[i] = 0; // (clear the image)
*vtk_at(image_data,10,10,10,X,Y) = 1;
*vtk_at(image_data,15,10,10,X,Y) = 1;
*vtk_at(image_data,10,15,10,X,Y) = 1;
*vtk_at(image_data,10,10,15,X,Y) = 1;
// Pad the volume so that we can change the point data into cell data.
int *extent = image->GetExtent();
vtkSmartPointer<vtkImageWrapPad> pad =
vtkSmartPointer<vtkImageWrapPad>::New();
pad->SetInput(image);
pad->SetOutputWholeExtent(extent[0], extent[1] + 1,
extent[2], extent[3] + 1,
extent[4], extent[5] + 1);
pad->Update();
// Copy the scalar point data of the volume into the scalar cell data
pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars());
vtkSmartPointer<vtkThreshold> selector =
vtkSmartPointer<vtkThreshold>::New();
selector->SetInputArrayToProcess(0, 0, 0,
vtkDataObject::FIELD_ASSOCIATION_CELLS,
vtkDataSetAttributes::SCALARS);
selector->SetInputConnection(pad->GetOutputPort());
selector->ThresholdByUpper(0.5);
selector->Update();
// Shift the geometry by 1/2
vtkSmartPointer<vtkTransform> transform =
vtkSmartPointer<vtkTransform>::New();
transform->Translate (-.5, -.5, -.5);
vtkSmartPointer<vtkTransformFilter> transformModel =
vtkSmartPointer<vtkTransformFilter>::New();
transformModel->SetTransform(transform);
transformModel->SetInputConnection(selector->GetOutputPort());
vtkSmartPointer<vtkGeometryFilter> geometry =
vtkSmartPointer<vtkGeometryFilter>::New();
geometry->SetInputConnection(transformModel->GetOutputPort());
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(geometry->GetOutputPort());
mapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor
= vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->SetBackground(.1, .2, .3);
renderWindow->Render();
renderWindowInteractor->Start(); // we'll start the animation
after the user hits 'q'
// test whether we can change the underlying image and just update
the pipeline
for(int iFrame=0;iFrame<X;iFrame++)
{
// add 4 cubes in a simple pattern that moves each frame
for(int i=0;i<X*Y*Z;i++) image_data[i] = 0; // (clear the image)
*vtk_at(image_data,(10+iFrame)%X,10,10,X,Y) = 1;
*vtk_at(image_data,(15+iFrame)%X,10,10,X,Y) = 1;
*vtk_at(image_data,(10+iFrame)%X,15,10,X,Y) = 1;
*vtk_at(image_data,(10+iFrame)%X,10,15,X,Y) = 1;
image->Modified();
// PROBLEM: need these two lines else the pipeline doesn't work
pad->Update();
pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars());
renderer->ResetCameraClippingRange();
renderWindow->Render();
}
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
On 29 March 2012 18:03, Tim Hutton <tim.hutton at gmail.com> wrote:
> Thanks Bill,
>
> Yes, vtkImageData -> vtkThreshold -> vtkGeometryFilter was what I was
> looking for.
>
> On 29 March 2012 17:15, Bill Lorensen <bill.lorensen at gmail.com> wrote:
>> Tim,
>>
>> Take a look at this example:
>> http://www.vtk.org/Wiki/VTK/Examples/Cxx/Medical/GenerateCubesFromLabels
>>
>> The output of transformModel may be what you want.
>>
>> Bill
>>
>> On Thu, Mar 29, 2012 at 8:40 AM, Tim Hutton <tim.hutton at gmail.com> wrote:
>>> Hello,
>>>
>>> I've got a 3d images (vtkImageData) containing values 0 and 1. I'd
>>> like to render this as blocky voxels - rendered with cubes like in
>>> Minecraft.
>>>
>>> I've tried vtkContourFilter and vtkDiscreteMarchingCubes but these
>>> both show angled surfaces - e.g. an octahedron for an isolated voxel.
>>>
>>> I tried vtkGeometryFilter but this just gives me the outer surface of
>>> the volume. And vtkImageThreshold just changes the pixel values.
>>>
>>> I tried vtkImageDataGeometryFilter but this doesn't seem to support
>>> thresholding in 3D?
>>>
>>> Thanks for your help,
>>>
>>> Tim
>>>
>>> --
>>> Tim Hutton - http://www.sq3.org.uk - http://profiles.google.com/tim.hutton/
>>> _______________________________________________
>>> Powered by www.kitware.com
>>>
>>> Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html
>>>
>>> Please keep messages on-topic and check the VTK FAQ at: http://www.vtk.org/Wiki/VTK_FAQ
>>>
>>> Follow this link to subscribe/unsubscribe:
>>> http://www.vtk.org/mailman/listinfo/vtkusers
>>
>>
>>
>> --
>> Unpaid intern in BillsBasement at noware dot com
>
>
>
> --
> Tim Hutton - http://www.sq3.org.uk - http://profiles.google.com/tim.hutton/
--
Tim Hutton - http://www.sq3.org.uk - http://profiles.google.com/tim.hutton/
More information about the vtkusers
mailing list