Faster Rendering of vtkpoly

Hey all,

i am visualizing sensordata (x,y,z,sensorvalue) with a python vtk app.
When Rendering more then 10 million “Points” it gets very laggy.
Also when zooming out this is getting worse.

Is there a way to improve the rendering/visualizing ?
Maybe something like rendering half of the data when zooming in and more when zooming out.
Some Options in the renderer or the renderwindow/interactor that can speed up the mouse interaction (ratation,mooving…)

As i am pretty working myself into vtk, there may be some simple options i just dont know yet.

Very Basic example of the code i am using right know (just the “important”):

lookUpTable_3d = vtk.vtkLookupTable()
vtkpoints_3d = vtk.vtkPoints()
vtkpoly = vtk.vtkPolyData()
vtkcells = vtk.vtkCellArray()

renderer = vtk.vtkRenderer()
renderWindowInteractor = vtk.RenderWindowInteractor()

mapper = vtk.vtkPolyDataMapper()

actor = vtk.vtkActor()



cells_array_init = np.arange(len(viewer3d_sensor_coordinates)).reshape(len(viewer3d_sensor_coordinates), 1)
cells_array_set = np.repeat(cells_array_init, repeats=3, axis=1)
cells_npy = np.column_stack([np.full(len(viewer3d_sensor_coordinates), 3, dtype=np.int64), cells_array_set.astype(np.int64)]).ravel()
vtkcells.SetCells(len(viewer3d_sensor_coordinates), numpy_to_vtkIdTypeArray(cells_npy))



setting up the lut … then:

viewer3d_color_2d = numpy_to_vtk(viewer3d_sensor_values)


Level-of-detail (LOD) actors can change the displayed details of your data dynamically to ensure that all interactions are fluid.

If you find that rendering is slow when you are not changing your data just moving the camera around then most likely your GPU is slow. If you use a discrete graphics card then rendering of polygons should be very, very fast.

10 million points for models is large, but it is small for a volume. So you can also consider splatting the points into a volume and display that using volume rendering.

1 Like

Hello, Bastian,

I routinely display 10s of millions points without any noticeable performance penalty (on an NVidia Quadro P5200 or the like). As @lassoan said, you may be either changing the data or using a less-than-recommended graphics card or you are even using software emulation. Anyway, if suport of low-end systems is a design requirement, then you have to be smart: using levels-of-detail as suggested, using a data structure with faster rendering like suggested above, using decimation, etc.




Thank u both for your comments,

i am using a GeForce RTX 3090 in a 128GByte-Ram 16Core Processor System. So i am pretty sure the performance issues do not come from this :slight_smile:

So i will look into splatting the points into a volume. Any suggestions where to start ?


With a recent GPU like this polygon rendering should run at very high frame rate (if you just rotate the view and not make any changes in the data or rendering pipeline while interacting). Make sure to assign your application to run on this GPU.

1 Like

Hi, Bastian,

This is how I raster point sets with high level code. You can see this as a pseudocode to implement as direct VTK API. I only use VTK for rendering. If more than one point falls in the same cell, this code simply overwrites the previous value (you may want to average them, for example):

    //loop over the point set samples
    //to transfer values to the volume
    for( int iPoint = 0; iPoint < pointCount; ++iPoint ){

        //get location of sample
        double x, y, z;
            x = psOrig->getX( iPoint );
            y = psOrig->getY( iPoint );
            z = psOrig->getZ( iPoint );

        //get the run-length address of the volume cell that contains the point
        int volumeRunLengthIndex = -1;
            uint i, j, k;
            bool isInside = volDest->XYZtoIJK( x, y, z, i, j, k );
            if( ! isInside )
                continue; //abort current iteration if the point fell outside the grid
            volumeRunLengthIndex = volDest->IJKtoIndex( i, j, k );

        //get the point value
        double collocatedValue = psOrig->getValue( iPoint );

        //set the collocated value to the data array of the volume
        volDest->getDataArray()[ volumeRunLengthIndex ] = collocatedValue;

Here are the implementations of the functions XYZtoIJK() and IJKtoIndex() which are not so obvious:

//this assumes the volume is orthogonal to x,y,z axes.
bool CartesianVolume::XYZtoIJK(double x, double y, double z, 
                             uint  &i,  uint &j,  uint &k)
    //compute the indexes from the spatial location.
    double xWest = _xOrigin;
    double ySouth = _yOrigin;
    double zBottom = _zOrigin;
    i = (x - xWest) / _cellSizeX;
    j = (y - ySouth) / _cellSizeY;
    k = (z - zBottom) / _cellSizeZ;

    //check whether the location is outside the grid
	if( i >= _nColumns ||  j >= _nRows || k >= _nSlices ){
        return false;
	return true;

uint CartesianVolume::IJKtoIndex(uint i, uint j, uint k)
    return k * _nRows * _nColumns + j * _nColumns + i;

I hope this helps somehow.



1 Like