I’m trying to display a lot of actors in VTK but the rendering is very slow.
I’m wondering if I used VTK correctly to display that much actors.
In the code I have a mouse interactor which change the color of the selected actor. I would like to keep this faculty.
In the below example, I have one mapper per actor but it might not be the correct way to do it.
Any suggestion to speed up the rendering?
Here is a minimal example :
import vtk
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
import sys
import numpy as np
NUMBER_OF_OBJECTS = 10000
class Tetrahedre(vtk.vtkUnstructuredGrid):
def __init__(self, d=None, pos = None, scale = [1,1,1]):
vtk.vtkUnstructuredGrid.__init__(self, )
# Make a tetrahedron.
points = vtk.vtkPoints()
points.InsertNextPoint(pos[0]*scale[0]+0 ,pos[1]*scale[1]+0 ,pos[2]*scale[2]+2*d/3)
points.InsertNextPoint(pos[0]*scale[0]-d/2 ,pos[1]*scale[1]-d/3 ,pos[2]*scale[2]-d/3)
points.InsertNextPoint(pos[0]*scale[0]+d/2 ,pos[1]*scale[1]-d/3 ,pos[2]*scale[2]-d/3)
points.InsertNextPoint(pos[0]*scale[0]+0 ,pos[1]*scale[1]+2*d/3 ,pos[2]*scale[2]-d/3)
points.InsertNextPoint(pos[0]*scale[0]+0 ,pos[1]*scale[1]+0 ,pos[2]*scale[2]+2*d/3)
self.SetPoints(points)
ids = vtk.vtkIdList()
ids.SetNumberOfIds(5)
for i in range(5) :
ids.SetId(i, i)
cellArray =vtk.vtkCellArray()
cellArray.InsertNextCell(ids)
self.SetCells(vtk.VTK_TETRA, cellArray)
class MouseInteractorHighLightActor(vtk.vtkInteractorStyleTrackballCamera):
def __init__(self, parent=None):
self.AddObserver("LeftButtonPressEvent", self.leftButtonPressEvent)
self.LastPickedActor = None
self.LastPickedProperty = vtk.vtkProperty()
def leftButtonPressEvent(self, obj, event):
clickPos = self.GetInteractor().GetEventPosition()
print(clickPos)
picker = vtk.vtkPropPicker()
picker.Pick(clickPos[0], clickPos[1], 0, self.GetDefaultRenderer())
# get the new
self.NewPickedActor = picker.GetActor()
# If something was selected
if self.NewPickedActor:
# If we picked something before, reset its property
if self.LastPickedActor:
self.LastPickedActor.GetProperty().DeepCopy(self.LastPickedProperty)
# Save the property of the picked actor so that we can
# restore it next time
self.LastPickedProperty.DeepCopy(self.NewPickedActor.GetProperty())
# Highlight the picked actor by changing its properties
self.NewPickedActor.GetProperty().SetColor(1.0, 0.0, 0.0)
# save the last picked actor
self.LastPickedActor = self.NewPickedActor
self.OnLeftButtonDown()
return
class Graph_viewer3D_VTK(QMainWindow):
def __init__(self, parent=None):
super(Graph_viewer3D_VTK, self).__init__(parent)
import platform
if platform.system() == 'Darwin':
self.facteurzoom = 1.05
else:
self.facteurzoom = 1.25
self.parent=parent
# self.scene = QGraphicsScene(self)
# self.setScene(self.scene)
self.frame = QFrame()
self.vl = QVBoxLayout()
self.vtkWidget = QVTKRenderWindowInteractor(self.frame)
self.vl.addWidget(self.vtkWidget)
self.ren = vtk.vtkRenderer()
self.ren.SetBackground(.1, .1, .1)
self.vtkWidget.GetRenderWindow().AddRenderer(self.ren)
self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()
style = MouseInteractorHighLightActor(self)
style.SetDefaultRenderer(self.ren)
self.iren.SetInteractorStyle(style)
self.ren.ResetCamera()
self.frame.setLayout(self.vl)
self.setCentralWidget(self.frame)
self.show()
self.iren.Initialize()
self.iren.Start()
self.selected_cells = []
#
def set_center(self):
self.ren.ResetCamera()
def draw_Graph(self,):
self.ren.RemoveAllViewProps()
# Add spheres to play with
for i in range(NUMBER_OF_OBJECTS):
# random position and radius
x = vtk.vtkMath.Random(-500, 500)
y = vtk.vtkMath.Random(-500, 500)
z = vtk.vtkMath.Random(-500, 500)
radius = vtk.vtkMath.Random(.5, 20.0)
if np.random.randint(0,2):
source = vtk.vtkSphereSource()
source.SetRadius(radius)
source.SetCenter(x, y, z)
source.SetPhiResolution(11)
source.SetThetaResolution(21)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(source.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
else:
source = Tetrahedre(d=vtk.vtkMath.Random(.5, 20.0)*2, pos=[x,y,z])
mapper = vtk.vtkDataSetMapper()
mapper.SetInputData(source)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
r = vtk.vtkMath.Random(.4, 1.0)
g = vtk.vtkMath.Random(.4, 1.0)
b = vtk.vtkMath.Random(.4, 1.0)
actor.GetProperty().SetDiffuseColor(r, g, b)
actor.GetProperty().SetDiffuse(.8)
actor.GetProperty().SetSpecular(.5)
actor.GetProperty().SetSpecularColor(1.0, 1.0, 1.0)
actor.GetProperty().SetSpecularPower(30.0)
self.ren.AddActor(actor)
self.iren.GetRenderWindow().Render()
self.set_center()
class Window(QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__()
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.Graph_viewer = Graph_viewer3D_VTK(self)
self.Graph_viewer.draw_Graph()
layout = QVBoxLayout()
layout.addWidget(self.Graph_viewer)
self.centralWidget.setLayout(layout)
def main():
app = QApplication(sys.argv)
app.setStyle('Windows')
ex = Window(app)
ex.setWindowTitle('Model micro GUI')
# ex.showMaximized()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()