Writing custom passes in vtk.js

Hello Everybody,
This is my first entry in this forum so please be nice :slight_smile:
We are using vtk.js to render volume data in the browser which works pretty good so far. The problem is that a new custom version of the tool needs a different appearance as well as a bit of post-processing. What we want to do is to basically use the vtkForwardPass as delegate for our custom pass where we then can set any 2D kernel that we like to do for instance edge-enhancement on the finished rendering. From a WebGL point of view this should not be a problem and we also already managed to compile the source with our own pass by using the source code and npm. The problem is we cannot get the framebuffer to work with the code that we wrote.

In the test page:
…
const forwardPass = vtk.Rendering.OpenGL.vtkForwardPass.newInstance();
const customPass = vtk.Rendering.OpenGL.vtkCustomPostProcessingPass.newInstance();
customPass.setDelegates([forwardPass]);
openglRenderWindowLeft.setRenderPasses([customPass]);
…

our custom pass:
…
function vtkCustomPostProcessingPass(publicAPI, model) {
// Set our className
model.classHierarchy.push(‘vtkCustomPostProcessingPass’);

// handles radial distortion and call delegate
publicAPI.traverse = (viewNode, parent = null) => {
if (model.deleted) {
return;
}

// allocate framebuffer if needed and bind it
if (model.framebuffer === null) {
  model.framebuffer = vtkOpenGLFramebuffer.newInstance();
}

// prepare framebuffer
const size = viewNode.getSize();
console.log(size);
const openGLRenderWindow = viewNode;
const ctx = openGLRenderWindow.getContext();
model.framebuffer.setOpenGLRenderWindow(viewNode);

console.log(ctx);	// remains null even though getContext() does not return null in the framebuffer

if (ctx === null) {
  // nothing to do -> no render context
  return;
}

// model.framebuffer.saveCurrentBindingsAndBuffers();
const fbSize = model.framebuffer.getSize();
console.log(fbSize);
if (fbSize === null || fbSize[0] !== size[0] || fbSize[1] !== size[1]) {
  model.framebuffer.create(size[0], size[1]);
  // model.framebuffer.populateFramebuffer();
}
// model.framebuffer.bind();

// traverse delegate passes
model.delegates.forEach((val) => {
  val.traverse(viewNode, publicAPI);
});

// insert processing here

};
}
…

We are grateful for any hints that point us in the right direction.

Cheers Dominik