The rendering performance of VTK is lower than that of QOpenGLWidget. How can I improve VTK's display performance?

The rendering performance of VTK is lower than that of QOpenGLWidget. How can I improve VTK’s display performance?

Background:
I am using Qt + VTK to display point cloud data, with the final deployment on Linux (but tested on Windows during development).

Testing shows that on both Linux and Windows,
when using the SimpleView example code (which utilizes vtkGenericOpenGLRenderWindow and QVTKRenderWidget), loading 10 million points results in lag during rotation.
In contrast, using QOpenGLWidget to load the same 10 million points achieves smooth rotation.

  • The data used is in OBJ format, but only contains vertices (no normals/colors).
  • The number of points is confirmed identical in both cases.

Questions:

  1. How can I make VTK rotate faster?
    *mapper->SetVBOShiftScaleMethod(vtkPolyDataMapper::DISABLE_SHIFT_SCALE);
    *actor->GetProperty()->SetLighting(false);
    I’ve tried both methods mentioned above, but they didn’t improve performance.

  2. Why is VTK significantly slower than native QOpenGLWidget?

If no solution exists, I may have to downsample the data, though I prefer to avoid downsampling.

Thank you for your help!

QOpenGLWidget

VTK

The main code related to QOpenGLWidget is as follows:

void GenericRender::initsize(QString filename)
{
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, R"(vsrc.vert)");
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, R"(fsrc.frag)");
    program_.link();

    ObjLoader objModelLoader;
    objModelLoader.load(filename,vertPoints_);
    QVector<float> points;
    points << vertPoints_ ;
    vbo_.create();
    vbo_.bind();
    vbo_.allocate(points.data(),points.count() * sizeof(float));
}
void GenericRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix, QVector3D &cameraLocation, QVector3D &lightCation)
{
    f->glEnable(GL_DEPTH_TEST);
    program_.bind();
    vbo_.bind();
    program_.setUniformValue("uPMatrix",pMatrix);
    program_.setUniformValue("uVMatrix",vMatrix);
    program_.setUniformValue("uMMatrix",mMatrix);
    program_.setUniformValue("uLightLocation",lightCation);
    program_.setUniformValue("uCamera",cameraLocation);
    program_.enableAttributeArray(0);
    program_.setAttributeBuffer(0,GL_FLOAT,0,3,3*sizeof(GLfloat));

    f->glDrawArrays(GL_POINTS,0,vertPoints_.count()/3);

    program_.disableAttributeArray(0);

    vbo_.release();
    program_.release();
    f->glDisable(GL_DEPTH_TEST);
}

vsrc.vert
windows: #version 330
linux: #version 320 es


#version 330
uniform mediump mat4 uPMatrix,uVMatrix,uMMatrix;
uniform mediump vec3 uLightLocation,uCamera;
layout (location = 0) in mediump vec3 aPosition;

void pointLight(in vec3 normal,inout vec4 ambient,inout vec4 diffuse,inout vec4 specular,in vec4 lightAmbient,in vec4 lightDiffuse,in vec4 lightSpecular,in float shininess){
    ambient = lightAmbient;

    vec3 normalTarget = aPosition + normal;
    vec3 newNormal = normalize((uMMatrix * vec4(normalTarget,1)).xyz - (uMMatrix * vec4(aPosition,1)).xyz);
    vec3 eye = normalize(uCamera - (uMMatrix * vec4(aPosition,1)).xyz);
    vec3 vp = normalize(uLightLocation - (uMMatrix * vec4(aPosition,1)).xyz);
    vec3 halfVector = normalize(eye + vp);

    float nDotViewPotision = max(0.0,dot(newNormal,vp));
    diffuse = lightDiffuse * nDotViewPotision;

    float nDotViewHalfVector = dot(newNormal,halfVector);
    float powerFactor = max(0.0,pow(nDotViewHalfVector,shininess));
    specular = lightSpecular * powerFactor;
}

void main(void)
{
    gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);

}

fsrc.frag
windows: #version 330
linux: #version 320 es

#version 330
out mediump vec4 fragColor;

void main(void)
{
    fragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

The main code related to VTK is as follows:

vtkSmartPointer<vtkOBJReader> reader = vtkSmartPointer<vtkOBJReader>::New();
reader->SetFileName(R"(data.obj)");
reader->Update();

// Mapper
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(reader->GetOutput());

// Actor in scene
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);

// VTK Renderer
vtkNew<vtkRenderer> ren;

// Add Actor to renderer
ren->AddActor(actor);

// VTK/Qt wedded
vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
this->ui->qvtkWidget->setRenderWindow(renderWindow);
this->ui->qvtkWidget->renderWindow()->AddRenderer(ren);	

@jaswantp May way take a look at it?

Can you confirm that VTK is built in Release mode? Debug builds are known to result in extremely slow rendering for large no. of points. The default is Debug, so please check your build.

Otherwise, here is what you can try:

  1. Set the Static flag on mapper. mapper->SetStatic(1)
  2. See if using vtkPointGaussianMapper instead helps performance.
  3. Check if there are any OpenGL errors. For release builds, configure VTK with VTK_REPORT_OPENGL_ERRORS_IN_RELEASE_BUILDS=ON
1 Like
  1. It is under Release build.

  2. mapper->SetStatic(1) has no effect.

  3. After using vtkPointGaussianMapper, 3d rotation is not work.

  4. With VTK_REPORT_OPENGL_ERRORS_IN_RELEASE_BUILDS=ON, no OpenGL errors were reported.

  5. QSurfaceFormat is consistent, yet VTK’s performance remains lower than QOpenGLWidget.

I tested the data with ParaView 5.13.1 on Windows, and there was no lag during rotation.

Additionally, my own program using VTK 7.1 also performs better than version 9.4.1.

So, is 9.4.1 less performant?

But I ultimately need to run it on ARM-based Linux, and only 9.4.1 can properly load OpenGL ES.

I tested the data with ParaView 5.13.1 on Windows, and there was no lag during rotation.

What about ParaView nightly? Go to https://www.paraview.org/download/ and select nightly in the version drop down menu.

ParaView nightly 5.13.20250422 is slower than 5.13.1

The effect of ParaView nightly is almost the same as when I use 9.4.1.

ParaView 5.13.1 is slightly slower than when I use QOpenGLWidget directly.

5.13.1

ParaView nightly 5.13.20250422

data

My computer configuration
i7-8550U
16G
GTX 1050 with Max-Q Design

Okay. Thanks for sharing data, we can look into it.

Fyi, @cory.quammen this seems to affect ParaView as well.

Is there any way to improve the efficiency of version 9.4.1?

apologies i have not yet looked into this. will try to investigate this week.

you can get faster support through https://www.kitware.com/contact/

If I’m understanding your OpenGL code correctly, you’ve effectively disabled lighting in your rendering pipeline. The pointLight function in your vertex shader is defined but never called, so no lighting calculations are performed. Instead, your fragment shader simply sets every fragment to a constant orange color. For a fair comparison with VTK, you would need to similarly disable lighting calculations in VTK.

Additionally, your OpenGL code renders the data as points (GL_POINTS), which is computationally inexpensive and very fast. In contrast, the VTK code processes and renders the data as vtkPolyData, which involves additional steps like triangulation and potentially more complex rendering. To make the comparison more equivalent, I might recommend setting the actor’s representation to points.

1 Like