Hi Tim,<br><br>I was wondering .<br>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 ?<br><br>Regards<br>Darshan<br>
<br><div class="gmail_quote">On Fri, Jun 8, 2012 at 6:29 PM, Tim Hutton <span dir="ltr">&lt;<a href="mailto:tim.hutton@gmail.com" target="_blank">tim.hutton@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I&#39;ve finally found a way to achieve Minecraft-style voxel rendering in<br>
a VTK pipeline. The hard bit is moving the image point data to cell<br>
data. One trick is that vtkMergeFilter won&#39;t pass data through unless<br>
the target geometry is the right size, so use vtkRearrangeFields<br>
first. Another trick is that vtkMergeFilter only passes through the<br>
active attributes, so use vtkAssignAttribute to set them.<br>
<br>
I&#39;m not sure if it wouldn&#39;t be better if vtkMergeFilter was less strict?<br>
<br>
Here&#39;s the code, for the long tail:<br>
<div class="im"><br>
vtkSmartPointer&lt;vtkImageWrapPad&gt; pad = vtkSmartPointer&lt;vtkImageWrapPad&gt;::New();<br>
pad-&gt;SetInput(image);<br>
pad-&gt;SetOutputWholeExtent(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1);<br>
<br>
</div>// move the pixel values (stored in the point data) to cell data<br>
vtkSmartPointer&lt;vtkRearrangeFields&gt; prearrange_fields =<br>
vtkSmartPointer&lt;vtkRearrangeFields&gt;::New();<br>
prearrange_fields-&gt;SetInput(image);<br>
prearrange_fields-&gt;AddOperation(vtkRearrangeFields::MOVE,vtkDataSetAttributes::SCALARS,<br>
    vtkRearrangeFields::POINT_DATA,vtkRearrangeFields::CELL_DATA);<br>
<br>
// mark the new cell data array as the active attribute<br>
vtkSmartPointer&lt;vtkAssignAttribute&gt; assign_attribute =<br>
vtkSmartPointer&lt;vtkAssignAttribute&gt;::New();<br>
assign_attribute-&gt;SetInputConnection(prearrange_fields-&gt;GetOutputPort());<br>
assign_attribute-&gt;Assign(&quot;ImageScalars&quot;,<br>
vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA);<br>
<br>
vtkSmartPointer&lt;vtkMergeFilter&gt; merge_datasets =<br>
vtkSmartPointer&lt;vtkMergeFilter&gt;::New();<br>
merge_datasets-&gt;SetGeometryConnection(pad-&gt;GetOutputPort());<br>
merge_datasets-&gt;SetScalarsConnection(assign_attribute-&gt;GetOutputPort());<br>
<br>
vtkSmartPointer&lt;vtkThreshold&gt; threshold = vtkSmartPointer&lt;vtkThreshold&gt;::New();<br>
threshold-&gt;SetInputConnection(merge_datasets-&gt;GetOutputPort());<br>
threshold-&gt;SetInputArrayToProcess(0, 0, 0,<br>
    vtkDataObject::FIELD_ASSOCIATION_CELLS,<br>
    vtkDataSetAttributes::SCALARS);<br>
threshold-&gt;ThresholdByUpper(contour_level);<br>
<div class="im"><br>
vtkSmartPointer&lt;vtkTransform&gt; transform = vtkSmartPointer&lt;vtkTransform&gt;::New();<br>
transform-&gt;Translate (-.5, -.5, -.5);<br>
vtkSmartPointer&lt;vtkTransformFilter&gt; transformModel =<br>
vtkSmartPointer&lt;vtkTransformFilter&gt;::New();<br>
transformModel-&gt;SetTransform(transform);<br>
</div>transformModel-&gt;SetInputConnection(threshold-&gt;GetOutputPort());<br>
<div class="im"><br>
vtkSmartPointer&lt;vtkGeometryFilter&gt; geometry =<br>
vtkSmartPointer&lt;vtkGeometryFilter&gt;::New();<br>
geometry-&gt;SetInputConnection(transformModel-&gt;GetOutputPort());<br>
</div>mapper-&gt;SetInputConnection(geometry-&gt;GetOutputPort());<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
On 2 April 2012 11:22, Tim Hutton &lt;<a href="mailto:tim.hutton@gmail.com">tim.hutton@gmail.com</a>&gt; wrote:<br>
&gt; A follow-up question: Is there a way to do this as a VTK pipeline? At<br>
&gt; the moment it needs a manual call to pad-&gt;Update() and<br>
&gt; pad-&gt;GetOutput()-&gt;GetCellData()-&gt;SetScalars(image-&gt;GetPointData()-&gt;GetScalars())<br>
&gt; every time the image changes (full code below). This is a problem for<br>
&gt; my application where I&#39;ve been keeping the rendering pipeline separate<br>
&gt; from the image-updating code, and where the user can choose how the<br>
&gt; pipeline is set up.<br>
&gt;<br>
&gt; // Adapted from GenerateCubesFromLabels.cxx (can use the same CMakeLists.txt)<br>
&gt; #include &lt;vtkImageWrapPad.h&gt;<br>
&gt; #include &lt;vtkThreshold.h&gt;<br>
&gt; #include &lt;vtkTransformFilter.h&gt;<br>
&gt; #include &lt;vtkGeometryFilter.h&gt;<br>
&gt; #include &lt;vtkSmartPointer.h&gt;<br>
&gt; #include &lt;vtkTransform.h&gt;<br>
&gt; #include &lt;vtkImageData.h&gt;<br>
&gt; #include &lt;vtkPointData.h&gt;<br>
&gt; #include &lt;vtkCellData.h&gt;<br>
&gt; #include &lt;vtkRenderer.h&gt;<br>
&gt; #include &lt;vtkRenderWindow.h&gt;<br>
&gt; #include &lt;vtkRenderWindowInteractor.h&gt;<br>
&gt; #include &lt;vtkPolyDataMapper.h&gt;<br>
&gt;<br>
&gt; int* vtk_at(int* origin,int x,int y,int z,int X,int Y)<br>
&gt; {<br>
&gt;    // single-component vtkImageData scalars are stored as:<br>
&gt; int,int,... for consecutive x, then y, then z<br>
&gt;    return origin + x + X*(y + Y*z);<br>
&gt; }<br>
&gt;<br>
&gt; int main ()<br>
&gt; {<br>
&gt;    const int X=30,Y=25,Z=20;<br>
&gt;    vtkSmartPointer&lt;vtkImageData&gt; image = vtkSmartPointer&lt;vtkImageData&gt;::New();<br>
&gt;    image-&gt;SetExtent(0,X-1,0,Y-1,0,Z-1);<br>
&gt;    image-&gt;SetScalarTypeToInt();<br>
&gt;    image-&gt;SetNumberOfScalarComponents(1);<br>
&gt;    image-&gt;AllocateScalars();<br>
&gt;<br>
&gt;    int* image_data = static_cast&lt;int*&gt;(image-&gt;GetScalarPointer());<br>
&gt;<br>
&gt;    // add 4 cubes in a simple pattern<br>
&gt;    for(int i=0;i&lt;X*Y*Z;i++) image_data[i] = 0; // (clear the image)<br>
&gt;    *vtk_at(image_data,10,10,10,X,Y) = 1;<br>
&gt;    *vtk_at(image_data,15,10,10,X,Y) = 1;<br>
&gt;    *vtk_at(image_data,10,15,10,X,Y) = 1;<br>
&gt;    *vtk_at(image_data,10,10,15,X,Y) = 1;<br>
&gt;<br>
&gt;    // Pad the volume so that we can change the point data into cell data.<br>
&gt;    int *extent = image-&gt;GetExtent();<br>
&gt;    vtkSmartPointer&lt;vtkImageWrapPad&gt; pad =<br>
&gt; vtkSmartPointer&lt;vtkImageWrapPad&gt;::New();<br>
&gt;    pad-&gt;SetInput(image);<br>
&gt;    pad-&gt;SetOutputWholeExtent(extent[0], extent[1] + 1,<br>
&gt;        extent[2], extent[3] + 1,<br>
&gt;        extent[4], extent[5] + 1);<br>
&gt;    pad-&gt;Update();<br>
&gt;<br>
&gt;    // Copy the scalar point data of the volume into the scalar cell data<br>
&gt;    pad-&gt;GetOutput()-&gt;GetCellData()-&gt;SetScalars(image-&gt;GetPointData()-&gt;GetScalars());<br>
&gt;<br>
&gt;    vtkSmartPointer&lt;vtkThreshold&gt; selector =<br>
&gt; vtkSmartPointer&lt;vtkThreshold&gt;::New();<br>
&gt;    selector-&gt;SetInputArrayToProcess(0, 0, 0,<br>
&gt;        vtkDataObject::FIELD_ASSOCIATION_CELLS,<br>
&gt;        vtkDataSetAttributes::SCALARS);<br>
&gt;    selector-&gt;SetInputConnection(pad-&gt;GetOutputPort());<br>
&gt;    selector-&gt;ThresholdByUpper(0.5);<br>
&gt;    selector-&gt;Update();<br>
&gt;<br>
&gt;    // Shift the geometry by 1/2<br>
&gt;    vtkSmartPointer&lt;vtkTransform&gt; transform =<br>
&gt; vtkSmartPointer&lt;vtkTransform&gt;::New();<br>
&gt;    transform-&gt;Translate (-.5, -.5, -.5);<br>
&gt;<br>
&gt;    vtkSmartPointer&lt;vtkTransformFilter&gt; transformModel =<br>
&gt; vtkSmartPointer&lt;vtkTransformFilter&gt;::New();<br>
&gt;    transformModel-&gt;SetTransform(transform);<br>
&gt;    transformModel-&gt;SetInputConnection(selector-&gt;GetOutputPort());<br>
&gt;<br>
&gt;    vtkSmartPointer&lt;vtkGeometryFilter&gt; geometry =<br>
&gt; vtkSmartPointer&lt;vtkGeometryFilter&gt;::New();<br>
&gt;    geometry-&gt;SetInputConnection(transformModel-&gt;GetOutputPort());<br>
&gt;<br>
&gt;    vtkSmartPointer&lt;vtkPolyDataMapper&gt; mapper =<br>
&gt; vtkSmartPointer&lt;vtkPolyDataMapper&gt;::New();<br>
&gt;    mapper-&gt;SetInputConnection(geometry-&gt;GetOutputPort());<br>
&gt;    mapper-&gt;ScalarVisibilityOff();<br>
&gt;<br>
&gt;    vtkSmartPointer&lt;vtkActor&gt; actor = vtkSmartPointer&lt;vtkActor&gt;::New();<br>
&gt;    actor-&gt;SetMapper(mapper);<br>
&gt;<br>
&gt;    vtkSmartPointer&lt;vtkRenderer&gt; renderer = vtkSmartPointer&lt;vtkRenderer&gt;::New();<br>
&gt;    vtkSmartPointer&lt;vtkRenderWindow&gt; renderWindow =<br>
&gt; vtkSmartPointer&lt;vtkRenderWindow&gt;::New();<br>
&gt;    renderWindow-&gt;AddRenderer(renderer);<br>
&gt;    vtkSmartPointer&lt;vtkRenderWindowInteractor&gt; renderWindowInteractor<br>
&gt; = vtkSmartPointer&lt;vtkRenderWindowInteractor&gt;::New();<br>
&gt;    renderWindowInteractor-&gt;SetRenderWindow(renderWindow);<br>
&gt;<br>
&gt;    renderer-&gt;AddActor(actor);<br>
&gt;    renderer-&gt;SetBackground(.1, .2, .3);<br>
&gt;<br>
&gt;    renderWindow-&gt;Render();<br>
&gt;    renderWindowInteractor-&gt;Start(); // we&#39;ll start the animation<br>
&gt; after the user hits &#39;q&#39;<br>
&gt;<br>
&gt;    // test whether we can change the underlying image and just update<br>
&gt; the pipeline<br>
&gt;    for(int iFrame=0;iFrame&lt;X;iFrame++)<br>
&gt;    {<br>
&gt;        // add 4 cubes in a simple pattern that moves each frame<br>
&gt;        for(int i=0;i&lt;X*Y*Z;i++) image_data[i] = 0; // (clear the image)<br>
&gt;        *vtk_at(image_data,(10+iFrame)%X,10,10,X,Y) = 1;<br>
&gt;        *vtk_at(image_data,(15+iFrame)%X,10,10,X,Y) = 1;<br>
&gt;        *vtk_at(image_data,(10+iFrame)%X,15,10,X,Y) = 1;<br>
&gt;        *vtk_at(image_data,(10+iFrame)%X,10,15,X,Y) = 1;<br>
&gt;        image-&gt;Modified();<br>
&gt;<br>
&gt;        // PROBLEM: need these two lines else the pipeline doesn&#39;t work<br>
&gt;        pad-&gt;Update();<br>
&gt;        pad-&gt;GetOutput()-&gt;GetCellData()-&gt;SetScalars(image-&gt;GetPointData()-&gt;GetScalars());<br>
&gt;<br>
&gt;        renderer-&gt;ResetCameraClippingRange();<br>
&gt;        renderWindow-&gt;Render();<br>
&gt;    }<br>
&gt;<br>
&gt;    renderWindowInteractor-&gt;Start();<br>
&gt;    return EXIT_SUCCESS;<br>
&gt; }<br>
&gt;<br>
&gt; On 29 March 2012 18:03, Tim Hutton &lt;<a href="mailto:tim.hutton@gmail.com">tim.hutton@gmail.com</a>&gt; wrote:<br>
&gt;&gt; Thanks Bill,<br>
&gt;&gt;<br>
&gt;&gt; Yes, vtkImageData -&gt; vtkThreshold -&gt; vtkGeometryFilter was what I was<br>
&gt;&gt; looking for.<br>
&gt;&gt;<br>
&gt;&gt; On 29 March 2012 17:15, Bill Lorensen &lt;<a href="mailto:bill.lorensen@gmail.com">bill.lorensen@gmail.com</a>&gt; wrote:<br>
&gt;&gt;&gt; Tim,<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Take a look at this example:<br>
&gt;&gt;&gt; <a href="http://www.vtk.org/Wiki/VTK/Examples/Cxx/Medical/GenerateCubesFromLabels" target="_blank">http://www.vtk.org/Wiki/VTK/Examples/Cxx/Medical/GenerateCubesFromLabels</a><br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; The output of transformModel may be what you want.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Bill<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; On Thu, Mar 29, 2012 at 8:40 AM, Tim Hutton &lt;<a href="mailto:tim.hutton@gmail.com">tim.hutton@gmail.com</a>&gt; wrote:<br>
&gt;&gt;&gt;&gt; Hello,<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I&#39;ve got a 3d images (vtkImageData) containing values 0 and 1. I&#39;d<br>
&gt;&gt;&gt;&gt; like to render this as blocky voxels - rendered with cubes like in<br>
&gt;&gt;&gt;&gt; Minecraft.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I&#39;ve tried vtkContourFilter and vtkDiscreteMarchingCubes but these<br>
&gt;&gt;&gt;&gt; both show angled surfaces - e.g. an octahedron for an isolated voxel.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I tried vtkGeometryFilter but this just gives me the outer surface of<br>
&gt;&gt;&gt;&gt; the volume. And vtkImageThreshold just changes the pixel values.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I tried vtkImageDataGeometryFilter but this doesn&#39;t seem to support<br>
&gt;&gt;&gt;&gt; thresholding in 3D?<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Thanks for your help,<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Tim<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; --<br>
&gt;&gt;&gt;&gt; Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
&gt;&gt;&gt;&gt; _______________________________________________<br>
&gt;&gt;&gt;&gt; Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Visit other Kitware open-source projects at <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Please keep messages on-topic and check the VTK FAQ at: <a href="http://www.vtk.org/Wiki/VTK_FAQ" target="_blank">http://www.vtk.org/Wiki/VTK_FAQ</a><br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Follow this link to subscribe/unsubscribe:<br>
&gt;&gt;&gt;&gt; <a href="http://www.vtk.org/mailman/listinfo/vtkusers" target="_blank">http://www.vtk.org/mailman/listinfo/vtkusers</a><br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; --<br>
&gt;&gt;&gt; Unpaid intern in BillsBasement at noware dot com<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; --<br>
&gt;&gt; Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt; --<br>
&gt; Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
<br>
<br>
<br>
--<br>
Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
_______________________________________________<br>
Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
<br>
Visit other Kitware open-source projects at <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
<br>
Please keep messages on-topic and check the VTK FAQ at: <a href="http://www.vtk.org/Wiki/VTK_FAQ" target="_blank">http://www.vtk.org/Wiki/VTK_FAQ</a><br>
<br>
Follow this link to subscribe/unsubscribe:<br>
<a href="http://www.vtk.org/mailman/listinfo/vtkusers" target="_blank">http://www.vtk.org/mailman/listinfo/vtkusers</a><br>
</div></div></blockquote></div><br>