[vtkusers] vtkSmartVolumeMapper doesn't properly handle input changes

Marc Ruiz Altisent marc.ruiz+vtk at gmail.com
Wed May 23 13:29:06 EDT 2018


Hi everyone,

I have found an issue with vtkSmartVolumeMapper. If you create several
vtkImageData objects, set one of them as the input of the mapper and
render, then you won't be able to render one of the others at a later time:
if you set one of the others as input the mapper will keep rendering the
first one.

The issue is in the method vtkSmartVolumeMapper::ConnectMapperInput. It
doesn't pass the original input to its internal mapper, but a shallow copy
of it. The first time it will always perform the shallow copy, but
afterwards it will only do it if the new input has been modified after
creating the previous shallow copy, which is not always the case (e.g. if
you create all the data before the first render).

Possible workarounds are to call Modified() on the input data when setting
a new one or to create a new mapper each time.

Below is a sample program (adapted from a couple of examples) to proof the
issue. Pressing 1 or 2 alternates between 2 datasets but only the first one
is always rendered. Uncommenting the 2 Modified() calls makes it work as
expected.

#include <vtkSmartPointer.h>
#include <vtkSphere.h>
#include <vtkBox.h>
#include <vtkSampleFunction.h>
#include <vtkSmartVolumeMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkVolumeProperty.h>
#include <vtkCamera.h>
#include <vtkImageShiftScale.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkDataArray.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkObjectFactory.h>

// Define interaction style
class KeyPressInteractorStyle : public vtkInteractorStyleTrackballCamera
{
  public:
    static KeyPressInteractorStyle* New();
    vtkTypeMacro(KeyPressInteractorStyle,
vtkInteractorStyleTrackballCamera);

    virtual void OnKeyPress()
    {
      // Get the keypress
      vtkRenderWindowInteractor *rwi = this->Interactor;
      std::string key = rwi->GetKeySym();

      if(key == "1")
      {
        mapper->SetInputData(imageData1);
        //imageData1->Modified();
        rwi->Render();
      }
      else if(key == "2")
      {
        mapper->SetInputData(imageData2);
        //imageData2->Modified();
        rwi->Render();
      }

      // Forward events
      vtkInteractorStyleTrackballCamera::OnKeyPress();
    }
    vtkSmartPointer<vtkVolumeMapper> mapper;
    vtkSmartPointer<vtkImageData> imageData1, imageData2;
};
vtkStandardNewMacro(KeyPressInteractorStyle);

static void CreateImageData(vtkImageData* im, bool);

int main(int argc, char *argv[])
{
  vtkSmartPointer<vtkImageData> imageData =
    vtkSmartPointer<vtkImageData>::New();
  vtkSmartPointer<vtkImageData> imageData2 =
    vtkSmartPointer<vtkImageData>::New();

  CreateImageData(imageData, true);
  CreateImageData(imageData2, false);

  vtkSmartPointer<vtkRenderWindow> renWin =
    vtkSmartPointer<vtkRenderWindow>::New();
  vtkSmartPointer<vtkRenderer> ren1 =
    vtkSmartPointer<vtkRenderer>::New();
  ren1->SetBackground(0.1,0.4,0.2);

  renWin->AddRenderer(ren1);

  renWin->SetSize(301,300); // intentional odd and NPOT  width/height

  vtkSmartPointer<vtkRenderWindowInteractor> iren =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
  iren->SetRenderWindow(renWin);

  vtkSmartPointer<KeyPressInteractorStyle> style =
    vtkSmartPointer<KeyPressInteractorStyle>::New();
  iren->SetInteractorStyle(style);
  style->SetCurrentRenderer(ren1);

  renWin->Render(); // make sure we have an OpenGL context.

  vtkSmartPointer<vtkSmartVolumeMapper> volumeMapper =
    vtkSmartPointer<vtkSmartVolumeMapper>::New();
  volumeMapper->SetBlendModeToComposite(); // composite first
  volumeMapper->SetInputData(imageData);
  vtkSmartPointer<vtkVolumeProperty> volumeProperty =
    vtkSmartPointer<vtkVolumeProperty>::New();
  volumeProperty->ShadeOff();
  volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION);

  style->mapper = volumeMapper;
  style->imageData1 = imageData;
  style->imageData2 = imageData2;

  vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity =
    vtkSmartPointer<vtkPiecewiseFunction>::New();
  compositeOpacity->AddPoint(0.0,0.0);
  compositeOpacity->AddPoint(80.0,1.0);
  compositeOpacity->AddPoint(80.1,0.0);
  compositeOpacity->AddPoint(255.0,0.0);
  volumeProperty->SetScalarOpacity(compositeOpacity); // composite first.

  vtkSmartPointer<vtkColorTransferFunction> color =
    vtkSmartPointer<vtkColorTransferFunction>::New();
  color->AddRGBPoint(0.0  ,0.0,0.0,1.0);
  color->AddRGBPoint(40.0  ,1.0,0.0,0.0);
  color->AddRGBPoint(255.0,1.0,1.0,1.0);
  volumeProperty->SetColor(color);

  vtkSmartPointer<vtkVolume> volume =
    vtkSmartPointer<vtkVolume>::New();
  volume->SetMapper(volumeMapper);
  volume->SetProperty(volumeProperty);
  ren1->AddViewProp(volume);
  ren1->ResetCamera();

  // Render composite. In default mode. For coverage.
  renWin->Render();

  iren->Start();

  return EXIT_SUCCESS;
}

void CreateImageData(vtkImageData* imageData, bool spherical)
{
  vtkSmartPointer<vtkImplicitFunction> implicitFunction;

  if (spherical)
  {
    vtkSmartPointer<vtkSphere> sphere =
      vtkSmartPointer<vtkSphere>::New();
    sphere->SetRadius(0.1);
    sphere->SetCenter(0.0,0.0,0.0);
    implicitFunction = sphere;
  }
  else
  {
    vtkSmartPointer<vtkBox> box =
      vtkSmartPointer<vtkBox>::New();
    box->SetBounds(-0.1, 0.1, -0.1, 0.1, -0.1, 0.1);
    implicitFunction = box;
  }

  vtkSmartPointer<vtkSampleFunction> sampleFunction =
    vtkSmartPointer<vtkSampleFunction>::New();
  sampleFunction->SetImplicitFunction(implicitFunction);
  sampleFunction->SetOutputScalarTypeToDouble();
  sampleFunction->SetSampleDimensions(127,127,127); // intentional NPOT
dimensions.
  sampleFunction->SetModelBounds(-1.0,1.0,-1.0,1.0,-1.0,1.0);
  sampleFunction->SetCapping(false);
  sampleFunction->SetComputeNormals(false);
  sampleFunction->SetScalarArrayName("values");
  sampleFunction->Update();

  vtkDataArray* a =
sampleFunction->GetOutput()->GetPointData()->GetScalars("values");
  double range[2];
  a->GetRange(range);

  vtkSmartPointer<vtkImageShiftScale> t =
    vtkSmartPointer<vtkImageShiftScale>::New();
  t->SetInputConnection(sampleFunction->GetOutputPort());

  t->SetShift(-range[0]);
  double magnitude=range[1]-range[0];
  if(magnitude==0.0)
  {
    magnitude=1.0;
  }
  t->SetScale(255.0/magnitude);
  t->SetOutputScalarTypeToUnsignedChar();

  t->Update();

  imageData->ShallowCopy(t->GetOutput());
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://vtk.org/pipermail/vtkusers/attachments/20180523/d2f09ad0/attachment.html>


More information about the vtkusers mailing list