Inheriting from vtkActor for custom OpenGL rendering

Hello. I created a CustomActor class which inherits from vtkOpenGLActor and overrides the common rendering methods. The idea is to use OpenGL calls directly within these methods to render with custom shaders.

I managed to get the code below compiling and running. The issue is: GLEW fails to initialize and throws an error from vtkOpenGLRenderWindow::OpenGLInit(). Trying to call any OpenGL functions result in a segmentation fault because of that.

ERR| vtkXOpenGLRenderWindow (0x5623a0c95ee0): GLEW could not be initialized: Missing GL version

Despite the error, the program runs flawlessly and renders the transparent objects (with the logs from the overridden methods), but I’m unable to write OpenGL code for rendering. Any advice on this?

I’m on VTK 9.0.3, built from source on Ubuntu 20.04 LTS.

Result is correct:

hpp file:

#include <vtkOpenGLActor.h>
#include <vtkObjectFactory.h>

#include <iostream>

class CustomActor : public vtkOpenGLActor
{
public:
  static CustomActor *New();
  vtkTypeMacro(CustomActor, vtkOpenGLActor);
  virtual void PrintSelf(ostream& os, vtkIndent indent);

  // Override standard render methods.
  int RenderOverlay(vtkViewport *viewport);
  int RenderOpaqueGeometry(vtkViewport *viewport);
  int HasTranslucentPolygonalGeometry();
  int RenderTranslucentPolygonalGeometry(vtkViewport* viewport);

protected:
  CustomActor();
  ~CustomActor();

private:
  // Not implemented.
  CustomActor(const CustomActor&);  
  void operator=(const CustomActor&);

};

cpp file:

#include "custom_actor.hpp"

#include <vtk_glew.h>

#include <vtkConeSource.h>
#include <vtkCubeSource.h>
#include <vtkInteractorObserver.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkOpenGLRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkPolyDataMapper.h>


/* --- CustomActor implementation --- */

vtkStandardNewMacro(CustomActor);

CustomActor::CustomActor() {}

CustomActor::~CustomActor() {}

void CustomActor::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
};

int CustomActor::RenderOverlay(vtkViewport *viewport)
{
  std::cout << "CustomActor::RenderOverlay" << std::endl;
  return this->Superclass::RenderOverlay(viewport);
}

int CustomActor::RenderOpaqueGeometry(vtkViewport *viewport)
{
  std::cout << "CustomActor::RenderOpaqueGeometry" << std::endl;
  return this->Superclass::RenderOpaqueGeometry(viewport);
}

int CustomActor::HasTranslucentPolygonalGeometry()
{
  std::cout << "CustomActor::HasTranslucentPolygonalGeometry" << std::endl;
  return this->Superclass::HasTranslucentPolygonalGeometry();
}

int CustomActor::RenderTranslucentPolygonalGeometry(vtkViewport* viewport)
{
  std::cout << "CustomActor::RenderTranslucentPolygonalGeometry" << std::endl;
  return this->Superclass::RenderTranslucentPolygonalGeometry(viewport);
}


// Setup custom actors.
void _setupCubeActor(CustomActor* cube_actor);
void _setupConeActor(CustomActor* cone_actor);

// Main
int main(int argc, char* argv[])
{
  vtkNew<CustomActor> cubeActor;
  _setupCubeActor(cubeActor);
  vtkNew<CustomActor> coneActor;
  _setupConeActor(coneActor);

  // Create renderer, render window and an OpenGL context.
  vtkNew<vtkRenderer> renderer;
  vtkNew<vtkRenderWindow> renWin;
  vtkOpenGLRenderWindow* context = vtkOpenGLRenderWindow::SafeDownCast(renWin);
  // vtkOpenGLRenderWindow::OpenGLInit() calls glewInit(), which fails:
  // ERROR: vtkOpenGLRenderWindow.c:569    ERR| vtkXOpenGLRenderWindow (0x5623a0c95ee0): GLEW could not be initialized: Missing GL version
  context->OpenGLInit();
  context->MakeCurrent();
  context->AddRenderer(renderer);
  context->SetSize(800, 800);

  unsigned int vao;
  //glGenVertexArrays(1, &vao); // -> Segmantation fault!

  vtkNew<vtkNamedColors> colors;
  renderer->SetBackground(colors->GetColor3d("MidnightBlue").GetData());
  renderer->AddActor(cubeActor);
  renderer->AddActor(coneActor);

  // Setup interactor.
  vtkNew<vtkRenderWindowInteractor> iren;
  iren->SetRenderWindow(context);

  context->Render();
  context->SetWindowName("Transparent Objects");

  // Interact with the data
  iren->Start();

  return EXIT_SUCCESS;
}


void _setupCubeActor(CustomActor* cube_actor)
{
  vtkNew<vtkNamedColors> colors;

  // Cube object.
  vtkNew<vtkCubeSource> cubeSource;
  cubeSource->SetXLength(4.0);
  cubeSource->SetYLength(9.0);
  cubeSource->SetZLength(1.0);
  cubeSource->SetCenter(0.0, 0.0, -6.0);

  vtkNew<vtkPolyDataMapper> cubeMapper;
  cubeMapper->SetInputConnection(cubeSource->GetOutputPort());

  cube_actor->GetProperty()->SetDiffuseColor(
      colors->GetColor3d("DarkGreen").GetData()
  );
  cube_actor->GetProperty()->SetOpacity(0.5);
  cube_actor->SetMapper(cubeMapper);
}

void _setupConeActor(CustomActor* cone_actor)
{
  vtkNew<vtkNamedColors> colors;

  // Cone object.
  vtkNew<vtkConeSource> coneSource;
  coneSource->SetCenter(0.0, 0.0, 0.0);
  coneSource->SetHeight(4.0);
  coneSource->SetRadius(2.0);
  coneSource->SetDirection(0.0, 1.0, 0.0);
  coneSource->SetResolution(60);
  coneSource->CappingOn();

  vtkNew<vtkPolyDataMapper> coneMapper;
  coneMapper->SetInputConnection(coneSource->GetOutputPort());

  cone_actor->GetProperty()->SetDiffuseColor(
      colors->GetColor3d("DarkTurquoise").GetData()
  );
  cone_actor->GetProperty()->SetOpacity(0.5);
  cone_actor->SetMapper(coneMapper);
}

All of the OpenGL shader logic is handled by mappers in VTK. For polydata, check the code for vtkOpenGLPolyDataMapper.

@sankhesh Thanks for the pointer. In my program, I would like to render only a specific type of actor with custom OpenGL calls, that’s why I implemented it as a subclass of vtkActor and reimplemented its render methods.
Would you say this is not advised? It did not seem risky to me, as it’s still drawing with OpenGL. I never used VTK’s way of injecting custom shaders, so I’m not sure how restrictive it can be.

Could you please elaborate on what you’re trying to do?

Depends on what you’re trying to do. The vtkOpenGLActor doesn’t do much except call Render on its mapper. So, if you’d really like to do custom OpenGL, mapper is where you’d do it.

Basically, I want to have a single vtkActor represent many copies of the same geometry and use it to render them. Let’s say a million cubes, for example.

The goal is to call OpenGL functions directly to draw them for maximum performance, avoiding possible overheads from VTK. This would be achieved by reimplementing RenderOpaqueGeometry and RenderTranslucentPolygonalGeometry in a new class, and using all OpenGL machinery needed within them, finishing with some glDraw___ call. These 2 render methods seemed enough for this goal, serving as direct entry points for OpenGL with no need to reference a vtkMapper as in vtkActor::Render. Honestly, being able to execute OpenGL with GLSL shaders that are agnostic to VTK would be awesome.

Unfortunately, I kind of got stuck on the GLEW issue, so don’t have a concrete result to show besides the CustomActor class skeleton. The main idea is simple though, just wanted to reach out for some advice (on the implementation and possibly on the weird GLEW error), as I figured someone must have tried this before.

What you are referring to is called instanced rendering. vtkGlyph3DMapper does exactly that.

You can override functions as much as you like, however, keep in mind that VTK considers actors as containers for prop transforms and properties. The task of transforming, scalar lookup, rasterization, and picking is left to the mapper. It might be a small detail when you are dealing with a single class but might cause issues when you have a complex application involving different views, many data types, etc.

About the GLEW issue, do you want VTK to create a native window or are you trying to render VTK inside an external OpenGL context?

1 Like

Thanks, I’ll have a closer look at vtkGlyph3DMapper.

The GLEW error arises from the main.cpp I wrote above. I’m simply creating a vtkOpenGLRenderWindow and trying to make it a valid OpenGL context with OpenGLInit() and MakeCurrent(), which causes GLEW to fail loading gl functions that I want to use.

The program still renders the scene as expected, though, which is odd unless VTK has another rendering backend other than OpenGL. Tried this in both CPU and GPU and got the same behavior.

Yes, and that is why I asked what is your intended windowing system. The vtkOpenGLRenderWindow cannot be used like that. If you would like for VTK to create a window, just instantiate a vtkRenderWindow and call Render on it. It will create a context and initialize it for VTK rendering. Once done, your custom classes would just need to include the vtk_glew.h header for access to the GL api. If you’d like to do VTK rendering in an OpenGL context created by a different application, you need to use vtkExternalOpenGLRenderWindow.

Thank you! Your inputs helped me solve the issue and better understand the VTK way of doing things.

if i want to render a vtkTextureObejct to th FrameBuffer, only the texture fullfill the frameBuffer.
which class should i inherit? still vtkActor? and which map should i inherit?
thanks!