Skip to content

MultipleLayersAndWindows

Repository source: MultipleLayersAndWindows


Description

Demonstrates the use of four renderers in two layers. The left renderers camera is independent of the right renderers camera.

There are four objects in two windows and two layers.

Layers Left Right
0 cube cone
1 sphere cylinder

When the program first runs, the top-most layer will be the active layer, (layer 1 in this case). Objects in layer 0 will be almost transparent.

  • Pressing 0 on the keyboard will let you manipulate the objects in layer 0. Objects in layer 1 will be almost transparent.
  • Pressing 1 on the keyboard will let you manipulate the objects in layer 1. Objects in layer 0 will be almost transparent.

Note:

  • The layer 0 background is the only visible background; backgrounds in layer 1 and subsequent layers are transparent.
  • It is easy to access the renderers and actors from the interactor by iterating through the renderer and actor collections.
  • In renderer collections and actor collections it is important to remember that the references are stored in last in - first out order.

Info

Also see the LayeredActors and TransparentBackground examples.

Other languages

See (PythonicAPI)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

MultipleLayersAndWindows.cxx

#include <vtkActor.h>
#include <vtkCallbackCommand.h>
#include <vtkConeSource.h>
#include <vtkCubeSource.h>
#include <vtkCylinderSource.h>
#include <vtkInteractorObserver.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>

#include <array>
#include <iostream>
#include <vector>

namespace {
/**
 * Select the layer to manipulate.
 */
void SelectLayer(vtkObject* caller, long unsigned int eventId, void* clientData,
                 void* callData);

} // namespace

int main(int, char*[])
{
  vtkNew<vtkNamedColors> colors;

  // Set the background color.
  std::array<unsigned char, 4> cubeColor{{250, 128, 114, 255}};
  colors->SetColor("CubeColor", cubeColor.data());
  std::array<unsigned char, 4> bkg{{230, 230, 230, 255}};
  colors->SetColor("BkgColor", bkg.data());

  // Create the rendering windows and renderers.
  std::array<vtkSmartPointer<vtkRenderer>, 2> leftRends;
  std::array<vtkSmartPointer<vtkRenderer>, 2> rightRends;
  vtkNew<vtkRenderWindow> renWin;
  renWin->SetSize(1200, 600);
  renWin->SetPosition(0, 50);
  renWin->SetWindowName("MultipleLayersAndWindows");
  renWin->SetNumberOfLayers(2);

  // Define the renderers setting viewport, layer and color.
  for (int i = 0; i < 2; ++i)
  {
    leftRends[i] = vtkSmartPointer<vtkRenderer>::New();
    leftRends[i]->SetViewport(0, 0, 0.5, 1);
    leftRends[i]->SetBackground(colors->GetColor3d("BkgColor").GetData());
    leftRends[i]->SetLayer(i);
    renWin->AddRenderer(leftRends[i]);
    rightRends[i] = vtkSmartPointer<vtkRenderer>::New();
    rightRends[i]->SetViewport(0.5, 0, 1, 1);
    rightRends[i]->SetBackground(colors->GetColor3d("Linen").GetData());
    rightRends[i]->SetLayer(i);
    renWin->AddRenderer(rightRends[i]);
  }

  vtkNew<vtkRenderWindowInteractor> iRen;
  iRen->SetRenderWindow(renWin);
  vtkNew<vtkInteractorStyleTrackballCamera> style;
  iRen->SetInteractorStyle(style);

  // Create an actor and give it conical geometry.
  vtkNew<vtkConeSource> cone;
  cone->SetResolution(8);
  vtkNew<vtkPolyDataMapper> coneMapper;
  coneMapper->SetInputConnection(cone->GetOutputPort());
  vtkNew<vtkActor> coneActor;
  coneActor->SetMapper(coneMapper);
  coneActor->GetProperty()->SetColor(colors->GetColor3d("CubeColor").GetData());

  // Create an actor and give it cylindrical geometry.
  vtkNew<vtkCylinderSource> cylinder;
  cylinder->SetResolution(8);
  cylinder->SetHeight(0.5);
  cylinder->SetRadius(0.25);
  vtkNew<vtkPolyDataMapper> cylinderMapper;
  cylinderMapper->SetInputConnection(cylinder->GetOutputPort());
  vtkNew<vtkActor> cylinderActor;
  cylinderActor->SetMapper(cylinderMapper);
  cylinderActor->GetProperty()->SetColor(
      colors->GetColor3d("Peacock").GetData());

  // Create an actor and give it cubic geometry.
  vtkNew<vtkCubeSource> cube;
  vtkNew<vtkPolyDataMapper> cubeMapper;
  cubeMapper->SetInputConnection(cube->GetOutputPort());
  vtkNew<vtkActor> cubeActor;
  cubeActor->SetMapper(cubeMapper);
  cubeActor->GetProperty()->SetColor(colors->GetColor3d("CubeColor").GetData());

  // Create an actor and give it spherical geometry.
  vtkNew<vtkSphereSource> sphere;
  sphere->SetRadius(0.25);
  vtkNew<vtkPolyDataMapper> sphereMapper;
  sphereMapper->SetInputConnection(sphere->GetOutputPort());
  vtkNew<vtkActor> sphereActor;
  sphereActor->SetMapper(sphereMapper);
  sphereActor->GetProperty()->SetColor(colors->GetColor3d("Peacock").GetData());

  // Assign our actors to the renderers.
  leftRends[0]->AddActor(cubeActor);      // Cube -> Left renderer, Layer 0
  leftRends[1]->AddActor(sphereActor);    // Sphere -> Left renderer, Layer 1
  rightRends[0]->AddActor(coneActor);     // Cone -> Right renderer, Layer 0
  rightRends[1]->AddActor(cylinderActor); // Cylinder -> Right renderer, Layer 1

  // Hide the layer 0 actors.
  cubeActor->GetProperty()->SetOpacity(0.1);
  coneActor->GetProperty()->SetOpacity(0.1);

  vtkNew<vtkCallbackCommand> keypressCallback;
  keypressCallback->SetCallback(SelectLayer);
  iRen->AddObserver(vtkCommand::KeyPressEvent, keypressCallback);

  // Draw the resulting scene.
  renWin->Render();

  // Set the active cameras.
  leftRends[1]->SetActiveCamera(leftRends[0]->GetActiveCamera());
  rightRends[1]->SetActiveCamera(rightRends[0]->GetActiveCamera());

  iRen->Start();

  return EXIT_SUCCESS;
}

namespace {
void SelectLayer(vtkObject* caller, long unsigned int vtkNotUsed(eventId),
                 void* vtkNotUsed(clientData), void* vtkNotUsed(callData))
{
  vtkRenderWindowInteractor* iRen =
      static_cast<vtkRenderWindowInteractor*>(caller);
  vtkRendererCollection* renderers = iRen->GetRenderWindow()->GetRenderers();
  auto numberOfItems = renderers->GetNumberOfItems();
  if (numberOfItems < 4)
  {
    std::cerr << "We need at least four renderers, we have only "
              << renderers->GetNumberOfItems() << std::endl;
    return;
  }
  std::vector<vtkRenderer*> rens;
  renderers->InitTraversal();
  // Top item is rens[0] and the bottom item is rens[numberOfItems-1].
  for (auto i = 0; i < numberOfItems; ++i)
  {
    rens.push_back(renderers->GetNextItem());
  }
  // Reverse so that the bottom item is rens[0]
  //  and the top item is rens[numberOfItems-1].
  std::reverse(rens.begin(), rens.end());

  /**
   * Set the actor properties.
   *
   * Note: rens is the list of renderers defined in the caller.
   *
   * @param idx Index of the specified renderer.
   * @param opacity Opacity of the first actor in the specified renderer.
   *
   */
  auto SetActorProperties = [&](const int& idx, const double& opacity) {
    auto actor = rens[idx]->GetActors();
    actor->InitTraversal();
    actor->GetNextActor()->GetProperty()->SetOpacity(opacity);
  };

  std::string key = iRen->GetKeySym();

  if (key == "0" || key == "KP_0")
  {
    SetActorProperties(0, 0.1);
    SetActorProperties(1, 0.1);
    SetActorProperties(2, 1);
    SetActorProperties(3, 1);

    std::cout << "Selected layer 0." << std::endl;
    rens[0]->InteractiveOff(); // Cylinder -> Right renderer, Layer 1
    rens[1]->InteractiveOff(); // Sphere -> Left renderer, Layer 1
    rens[2]->InteractiveOn();  // Cone -> Right renderer, Layer 0
    rens[3]->InteractiveOn();  // Cube -> Left renderer, Layer 0
  }
  if (key == "1" || key == "KP_1")
  {
    SetActorProperties(0, 1);
    SetActorProperties(1, 1);
    SetActorProperties(2, 0.1);
    SetActorProperties(3, 0.1);

    std::cout << "Selected layer 1." << std::endl;
    rens[0]->InteractiveOn();  // Cylinder -> Right renderer, Layer 1
    rens[1]->InteractiveOn();  // Sphere -> Left renderer, Layer 1
    rens[2]->InteractiveOff(); // Cone -> Right renderer, Layer 0
    rens[3]->InteractiveOff(); // Cube -> Left renderer, Layer 0
  }
  iRen->Render();
}
} // namespace

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(MultipleLayersAndWindows)

find_package(VTK COMPONENTS 
  CommonColor
  CommonCore
  FiltersSources
  InteractionStyle
  RenderingContextOpenGL2
  RenderingCore
  RenderingFreeType
  RenderingGL2PSOpenGL2
  RenderingOpenGL2
)

if (NOT VTK_FOUND)
  message(FATAL_ERROR "MultipleLayersAndWindows: Unable to find the VTK build folder.")
endif()

# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(MultipleLayersAndWindows MACOSX_BUNDLE MultipleLayersAndWindows.cxx )
  target_link_libraries(MultipleLayersAndWindows PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS MultipleLayersAndWindows
  MODULES ${VTK_LIBRARIES}
)

Download and Build MultipleLayersAndWindows

Click here to download MultipleLayersAndWindows and its CMakeLists.txt file. Once the tarball MultipleLayersAndWindows.tar has been downloaded and extracted,

cd MultipleLayersAndWindows/build

If VTK is installed:

cmake ..

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:

cmake -DVTK_DIR:PATH=/home/me/vtk_build ..

Build the project:

make

and run it:

./MultipleLayersAndWindows

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.