独立颜色和旋转 3D VTK 象形图

3 投票
2 回答
3109 浏览
提问于 2025-04-18 07:50

我正在尝试使用VTK的Python接口在场景中显示几个图形,每个图形都有自己的颜色和旋转。不过,奇怪的是,只有旋转(使用vtkTensorGlyph)被VTK考虑了。而当我使用vtkGlyph3D时,只有颜色被考虑。

这里有一段可以直接使用的代码,使用了vtkTensorGlyph。每个立方体应该有随机的颜色,但实际上它们都会是同一种颜色。我反复查看了VTK的文档,但还是没有找到解决办法。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import vtk
import scipy.linalg as sc
import random as ra
import numpy as np
import itertools

points = vtk.vtk.vtkPoints()  # where to locate each glyph in the scene
tensors = vtk.vtkDoubleArray() # rotation for each glyph
tensors.SetNumberOfComponents(9)
colors = vtk.vtkUnsignedCharArray() # should be the color for each glyph
colors.SetNumberOfComponents(3)

# let's make 10 cubes in the scene
for i in range(0, 50, 5): 
    points.InsertNextPoint(i, i, i) # position of a glyph
    colors.InsertNextTuple3(ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255) ) # pick random color
    rot = list(itertools.chain(*np.reshape(sc.orth(np.random.rand(3, 3)).transpose(), (1, 9)).tolist())) # random rotation matrix (row major)
    tensors.InsertNextTuple9(*rot)

polydata = vtk.vtkPolyData() # create the polydatas
polydata.SetPoints(points) 
polydata.GetPointData().SetTensors(tensors)
polydata.GetPointData().SetScalars(colors)

cubeSource = vtk.vtkCubeSource()
cubeSource.Update()

glyphTensor = vtk.vtkTensorGlyph()
glyphTensor.SetColorModeToScalars() # is it really work ?

try:
    glyphTensor.SetInput(polydata)
except AttributeError:
    glyphTensor.SetInputData(polydata)

glyphTensor.SetSourceConnection(cubeSource.GetOutputPort())
glyphTensor.ColorGlyphsOn() # should not color all cubes independently ?
glyphTensor.ThreeGlyphsOff()
glyphTensor.ExtractEigenvaluesOff()
glyphTensor.Update()

# next is usual vtk code
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(glyphTensor.GetOutputPort())

actor = vtk.vtkActor()
actor.SetMapper(mapper)

ren = vtk.vtkRenderer()
ren.SetBackground(0.2, 0.5, 0.3)
ren.AddActor(actor)

renwin = vtk.vtkRenderWindow()
renwin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
iren.SetRenderWindow(renwin)

renwin.Render()
iren.Initialize()
renwin.Render()
iren.Start()

2 个回答

1

你可以通过以下方式给vtkTensorGlyphs上不同的颜色。我会给你展示一些我用C++写的代码片段,这些代码使用了不同颜色的张量图标。希望你能把类似的东西整合到你的Python代码里:

vtkSmartPointer<vtkFloatArray> colors = vtkSmartPointer<vtkFloatArray>::New();
vtkSmartPointer<vtkPolyData> data = vtkSmartPointer<vtkPolyData>::New();

//Add for each single object the following data to colors: 
float color[3] = {r, g, b};
colors->InsertNextTupleValue(color);

//Then proceed here after adding all colors
colors->SetName("colors");
colors->SetNumberOfComponents(3);

//Add all necessary information to the vtkPolyData element, including the color information
data->GetPointData()->SetScalars(colors);

...

tensorGlyph->SetInputData(data);
tensorGlyph->ColorGlyphsOn();
tensorGlyph->SetColorModeToScalars();

虽然VTK的开发者可能是想让我们用RGB元组来定义颜色,但其实你只需要使用第一个参数“r”。在[0,1]这个范围内改变“r”的值,就能得到不同的颜色。

使用的是VTK 6.1.0版本

1

我终于做成了一些东西。 如果我理解得没错,glyphs(图形符号)需要一个表面,特别是这个表面上每个点的法线。每个法线指明了每个glyph的方向。 在vtk源代码中的Examples/VisualizationAlgorithms/Python/spikeF.py示例中,有一个我想表达的概念的例子。 这里有一个小例子,展示了如何独立地给glyph上色和旋转。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from vtk import *

# Let's create a surface with 3 points unconnected.
points = vtkPoints()
points.InsertNextPoint(1, 0, 0)
points.InsertNextPoint(0, 0, 0)
points.InsertNextPoint(0, 1, 0)

polydata = vtkPolyData()
polydata.SetPoints(points)

colors = vtkUnsignedCharArray()
colors.SetNumberOfComponents(3)
colors.SetNumberOfTuples(polydata.GetNumberOfPoints())

colors.InsertTuple3(0, 147, 25, 98)
colors.InsertTuple3(1, 32, 84, 247)
colors.InsertTuple3(2, 198, 214, 36)

polydata.GetPointData().SetScalars(colors)

# Now, let's control normal on each point composing or 'fake' surface
# We should say, let's give a direction to each point, a normal in strange for a point.
pointNormalsArray = vtkDoubleArray()
pointNormalsArray.SetNumberOfComponents(3)
pointNormalsArray.SetNumberOfTuples(polydata.GetNumberOfPoints())

pN1 = [1.0, 0.0, 0.0]
pN2 = [0.0, 1.0, 0.0]
pN3 = [0.0, 0.0, 1.0]

pointNormalsArray.SetTuple(0, pN1)
pointNormalsArray.SetTuple(1, pN2)
pointNormalsArray.SetTuple(2, pN3)

polydata.GetPointData().SetNormals(pointNormalsArray)

sources = vtkConeSource()
sources.SetResolution(6)
sources.Update()

glyph = vtkGlyph3D()
try:
    glyph.SetInput(polydata)
except AttributeError:
    glyph.SetInputData(polydata)

glyph.SetSourceConnection(sources.GetOutputPort())
glyph.SetColorModeToColorByScalar()
glyph.SetVectorModeToUseNormal()
glyph.ScalingOff()
glyph.Update()

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(glyph.GetOutputPort())

actor = vtkActor()
actor.SetMapper(mapper)

ren = vtkRenderer()
ren.SetBackground(0.2, 0.5, 0.3)
ren.AddActor(actor)

renwin = vtk.vtkRenderWindow()
renwin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
iren.SetRenderWindow(renwin)

renwin.Render()
iren.Initialize()
renwin.Render()
iren.Start()

顺便说一下,还有一个更简单的解决方案,就是创建一个源,然后使用任何需要的映射器和演员。实际上,给每个演员设置颜色和方向是很简单的。问题是,当演员数量很多(我这台机器上大约有5000个)时,交互性能会变得很差。

撰写回答