我想渲染固定数量的具有固定位置的球体,并随时间修改颜色。
我创建一个具有相应位置的vtkPolyData
对象,然后创建一个vtkGlyph3D
,其中vtkPolyData
对象作为输入,vtkSphereSource
对象作为源。
颜色存储在vtkPolyData
对象的Scalars数组中。
目前我正在使用RepeatingTimer,我在vtkGlyph3D
方法中反复设置execute
对象的输入和来源。这似乎是一种非常低效的方法。有没有办法只更新vtkPolyData
对象的Scalars数组中的颜色值?
显然只是更改数组值并调用Update
对象的vtkGlyph3D
方法不起作用。
import numpy as np
import vtk
class vtkTimerCallback():
def __init__(self, tspan, radius, mapper, actor, glyph, polyData):
self._tspan = tspan
self._radius = radius
self._mapper = mapper
self._actor = actor
self._glyph = glyph
self._polyData = polyData
self._timeIndex = 0
def execute(self, obj, event):
array = self._polyData.GetPointData().GetScalars()
for i in xrange(coords.shape[0]):
v = int(float(i) / coords.shape[0] * 255)
if self._timeIndex % 2 == 0:
red = 0
green = 255 - v
blue = v
else:
red = v
green = 0
blue = 255 - v
array.InsertTuple3(i, red, green, blue)
self._polyData.Update()
sphereSource = vtk.vtkSphereSource()
sphereSource.SetRadius(self._radius)
self._glyph.SetColorModeToColorByScalar()
self._glyph.SetSource(sphereSource.GetOutput())
self._glyph.SetInput(self._polyData)
self._glyph.Update()
self._mapper.SetInput(self._glyph.GetOutput())
self._mapper.Update()
self._timeIndex += 1
if self._timeIndex >= self._tspan.shape[0]:
self._timeIndex = 0
iren = obj
iren.GetRenderWindow().Render()
def viewData(coords, tspan, radius=0.1, interval=50):
points = vtk.vtkPoints()
points.SetNumberOfPoints(coords.shape[0])
for i in xrange(coords.shape[0]):
coord = coords[i, :]
points.InsertPoint(i, coord[0], coord[1], coord[2])
polyData = vtk.vtkPolyData()
polyData.SetPoints(points)
array = vtk.vtkUnsignedCharArray()
array.SetName('colors')
array.SetNumberOfComponents(3)
array.SetNumberOfTuples(coords.shape[0])
polyData.GetPointData().SetScalars(array)
sphereSource = vtk.vtkSphereSource()
sphereSource.SetRadius(radius)
glyph = vtk.vtkGlyph3D()
glyph.SetColorModeToColorByScalar()
if vtk.VTK_MAJOR_VERSION <= 5:
glyph.SetSource(sphereSource.GetOutput())
glyph.SetInput(polyData)
else:
glyph.SetSourceConnection(sphereSource.GetOutputPort())
glyph.SetInputData(polyData)
glyph.ScalingOff()
glyph.Update()
#glyph.FillCellDataOn()
# Create a mapper and actor
mapper = vtk.vtkPolyDataMapper()
if vtk.VTK_MAJOR_VERSION <= 5:
mapper.SetInput(glyph.GetOutput())
else:
mapper.SetInputConnection(glyph.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Create a renderer, render window, and interactor
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.Initialize()
# Register callback for animation
cb = vtkTimerCallback(tspan, radius, mapper, actor, glyph, polyData)
renderWindowInteractor.AddObserver('TimerEvent', cb.execute)
timeId = renderWindowInteractor.CreateRepeatingTimer(interval)
cb.execute(renderWindowInteractor, None)
renderWindow.Render()
# Render and interact
renderWindowInteractor.Start()
if __name__ == '__main__':
# Create a 3D-grid of 11x11x11 points
r = np.linspace(-10.0, 10.0, 15)
X, Y, Z = np.meshgrid(r, r, r)
X, Y, Z = X.flatten(), Y.flatten(), Z.flatten()
coords = np.array([(X[i], Y[i], Z[i]) for i in xrange(X.shape[0])], dtype=np.double)
tspan = np.arange(100, dtype=np.double)
viewData(coords, tspan, radius=0.5, interval=1)