[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