[vtkusers] Minecraft-style volume rendering

Tim Hutton tim.hutton at gmail.com
Sat Jun 9 05:26:57 EDT 2012


No, because that filter resamples the scalar values - each cell gets the
average value of its points.
On Jun 9, 2012 1:31 AM, "Darshan Pai" <darshanpai at gmail.com> wrote:

> Hi Tim,
>
> I was wondering .
> since you used vtkRearrangeFields to move the point data to cell data ,
> will you get a similar result if you directly use vtkPointDataToCellData to
> move attributes ?
>
> Regards
> Darshan
>
> On Fri, Jun 8, 2012 at 6:29 PM, Tim Hutton <tim.hutton at gmail.com> wrote:
>
>> I've finally found a way to achieve Minecraft-style voxel rendering in
>> a VTK pipeline. The hard bit is moving the image point data to cell
>> data. One trick is that vtkMergeFilter won't pass data through unless
>> the target geometry is the right size, so use vtkRearrangeFields
>> first. Another trick is that vtkMergeFilter only passes through the
>> active attributes, so use vtkAssignAttribute to set them.
>>
>> I'm not sure if it wouldn't be better if vtkMergeFilter was less strict?
>>
>> Here's the code, for the long tail:
>>
>> 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);
>>
>> // move the pixel values (stored in the point data) to cell data
>> vtkSmartPointer<vtkRearrangeFields> prearrange_fields =
>> vtkSmartPointer<vtkRearrangeFields>::New();
>> prearrange_fields->SetInput(image);
>>
>> prearrange_fields->AddOperation(vtkRearrangeFields::MOVE,vtkDataSetAttributes::SCALARS,
>>    vtkRearrangeFields::POINT_DATA,vtkRearrangeFields::CELL_DATA);
>>
>> // mark the new cell data array as the active attribute
>> vtkSmartPointer<vtkAssignAttribute> assign_attribute =
>> vtkSmartPointer<vtkAssignAttribute>::New();
>> assign_attribute->SetInputConnection(prearrange_fields->GetOutputPort());
>> assign_attribute->Assign("ImageScalars",
>> vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA);
>>
>> vtkSmartPointer<vtkMergeFilter> merge_datasets =
>> vtkSmartPointer<vtkMergeFilter>::New();
>> merge_datasets->SetGeometryConnection(pad->GetOutputPort());
>> merge_datasets->SetScalarsConnection(assign_attribute->GetOutputPort());
>>
>> vtkSmartPointer<vtkThreshold> threshold =
>> vtkSmartPointer<vtkThreshold>::New();
>> threshold->SetInputConnection(merge_datasets->GetOutputPort());
>> threshold->SetInputArrayToProcess(0, 0, 0,
>>    vtkDataObject::FIELD_ASSOCIATION_CELLS,
>>    vtkDataSetAttributes::SCALARS);
>> threshold->ThresholdByUpper(contour_level);
>>
>> vtkSmartPointer<vtkTransform> transform =
>> vtkSmartPointer<vtkTransform>::New();
>> transform->Translate (-.5, -.5, -.5);
>> vtkSmartPointer<vtkTransformFilter> transformModel =
>> vtkSmartPointer<vtkTransformFilter>::New();
>> transformModel->SetTransform(transform);
>> transformModel->SetInputConnection(threshold->GetOutputPort());
>>
>> vtkSmartPointer<vtkGeometryFilter> geometry =
>> vtkSmartPointer<vtkGeometryFilter>::New();
>> geometry->SetInputConnection(transformModel->GetOutputPort());
>> mapper->SetInputConnection(geometry->GetOutputPort());
>>
>>
>> On 2 April 2012 11:22, Tim Hutton <tim.hutton at gmail.com> wrote:
>> > 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/
>>
>>
>>
>> --
>> 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
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20120609/e276fede/attachment.htm>


More information about the vtkusers mailing list