vtkPNGWriter offscreen rendering issue
I'm currently using VTK 8.2. When I render translucent objects to an image using vtkPNGWriter and offscreen rendering turned on, the renderer only succeeds the first time it's rendered to an image. The second time, the background goes blank with OpenGL errors. Also, the scene disappears when WindowToImageFilterUpdate is called.
Platform: Windows
I was able to reproduce the problem with the Screenshot VTK sample. Here's the code:
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkWindowToImageFilter.h>
#include <vtkPNGWriter.h>
#include <vtkAxesActor.h>
#include <vtkProperty.h>
#include <vtkTransform.h>
int main(int, char *[])
{
const double ONE_THIRD= 1.0/3;
const double TWO_THIRDS= 2.0/3;
const double ORIGIN_LENGTH= 40;
const double X_AXIS_SHAFT_COLOR[3]= { 199.0/255, 25.0/255, 25.0/255 };
const double Y_AXIS_SHAFT_COLOR[3]= { 25.0/255, 115.0/255, 25.0/255 };
const double Z_AXIS_SHAFT_COLOR[3]= { 25.0/255, 25.0/255, 161.0/255 };
vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetCenter(0.0, 0.0, 0.0);
sphereSource->SetRadius(5.0);
sphereSource->Update();
// Visualize
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(sphereSource->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetOpacity(0.5);
vtkSmartPointer<vtkAxesActor> origin_axes= vtkSmartPointer<vtkAxesActor>::New();
origin_axes->SetShaftTypeToCylinder();
origin_axes->SetXAxisLabelText("");
origin_axes->SetYAxisLabelText("");
origin_axes->SetZAxisLabelText("");
origin_axes->SetTotalLength(1, 1, 1); // This length doesn't matter because it will get recalculated later before each
render.
origin_axes->SetNormalizedShaftLength(TWO_THIRDS, TWO_THIRDS, TWO_THIRDS);
origin_axes->SetNormalizedTipLength(ONE_THIRD, ONE_THIRD, ONE_THIRD);
origin_axes->SetCylinderRadius(2*origin_axes->GetCylinderRadius());
origin_axes->SetConeRadius(1.0*origin_axes->GetConeRadius());
origin_axes->SetVisibility(false);
origin_axes->GetXAxisShaftProperty()->SetColor(const_cast<double *>(X_AXIS_SHAFT_COLOR));
origin_axes->GetYAxisShaftProperty()->SetColor(const_cast<double *>(Y_AXIS_SHAFT_COLOR));
origin_axes->GetZAxisShaftProperty()->SetColor(const_cast<double *>(Z_AXIS_SHAFT_COLOR));
origin_axes->SetVisibility(true);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->SetLayer(0);
vtkSmartPointer<vtkRenderer> origin_axes_renderer = vtkSmartPointer<vtkRenderer>::New();
origin_axes_renderer->SetLayer(1);
origin_axes_renderer->InteractiveOff();
vtkTransform *user_transform= vtkTransform::New();
//user_transform->Scale(0.1, 0.1, 0.1);
user_transform->Translate(-2, -2, 0);
origin_axes->SetUserTransform(user_transform);
user_transform->Delete();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->AddRenderer(origin_axes_renderer);
renderWindow->SetAlphaBitPlanes(1); //enable usage of alpha channel
renderWindow->SetNumberOfLayers(2);
renderWindow->SetMultiSamples(0);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->SetBackground(1,1,1); // Background color white
renderer->SetUseDepthPeeling(true);
// Set depth peeling parameters
// - Set the maximum number of rendering passes (initial value is 4):
renderer->SetMaximumNumberOfPeels(100);
// - Set the occlusion ratio (initial value is 0.0, exact image):
renderer->SetOcclusionRatio(0.1);
origin_axes_renderer->SetActiveCamera(renderer->GetActiveCamera());
origin_axes_renderer->AddActor(origin_axes);
renderer->ResetCamera();
renderWindow->Render();
// Screenshots
for (int i= 1; i <= 2; ++i)
{
vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
std::string filepath;
bool use_depth_peeling= renderer->GetUseDepthPeeling() != 0;
filepath= "C:\\Users\\amamidi\\Documents\\Tests\\Screenshot-OffscreenRenderingBug-8.2\\screenshot-";
filepath+= std::to_string(i);
filepath+= ".png";
renderer->SetGradientBackground(true);
renderer->SetBackground(1.0, 0.0, 0.0);
renderer->SetBackground2(1.0, 1.0, 1.0);
//renderer->SetUseDepthPeeling(false); // Doesn't work in offscreen rendering. Actually, only works the first time in VTK 8.1.1.
renderWindow->OffScreenRenderingOn(); // To avoid flashing.
renderWindow->Render();
windowToImageFilter->SetInput(renderWindow);
//#if VTK_MAJOR_VERSION > 8 || VTK_MAJOR_VERSION == 8 && VTK_MINOR_VERSION >= 1
// windowToImageFilter->SetScale(2); //image quality
//#else
// windowToImageFilter->SetMagnification(2); //image quality
//#endif
windowToImageFilter->SetInputBufferTypeToRGBA(); //also record the alpha (transparency) channel
windowToImageFilter->ReadFrontBufferOff(); // read from the back buffer
windowToImageFilter->Update();
vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
writer->SetInputConnection(windowToImageFilter->GetOutputPort());
writer->SetFileName(filepath.c_str());
writer->Write();
//renderer->SetUseDepthPeeling(use_depth_peeling);
renderer->SetBackground(1.0, 1.0, 1.0);
renderer->SetBackground2(1.0, 1.0, 1.0);
renderer->SetGradientBackground(false);
renderWindow->OffScreenRenderingOff();
renderWindow->Render();
}
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
Sample output:
Edited by Aravind M