[vtkusers] Minecraft-style volume rendering
Darshan Pai
darshanpai at gmail.com
Fri Jun 8 20:31:51 EDT 2012
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/20120608/b157ccb8/attachment.htm>
More information about the vtkusers
mailing list