简体   繁体   中英

Independently color and rotate 3D VTK glyphs

I am trying to use the python wrapper for VTK to display several glyphs in a scene, each with their own color and rotation. Unfortunately, just the rotation (using vtkTensorGlyph ) is taken in consideration by vtk. Conversely, just color is taken in consideration when I use a vtkGlyph3D .

Here is a ready to use piece of code with a vtkTensorGlyph . Each cube should have a random color but instead, they all will be the same color. I read and read again the doc of VTK but I haven't found any solution.

#!/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()

I have finally managed to make something. If I well understood, glyphs need a surface and especially the normal on each point composing this surface. Each normal give the direction of each glyph. The example at Examples/VisualizationAlgorithms/Python/spikeF.py in vtk sources gives an illustration of what I mean. Here is an little example to color and rotate independently glyphs.

#!/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()

By the way, there is a simpler solution which consist to create one source, and any mapper and actor needed. Indeed, it is easy to give a color and a direction to each actor. The problem is that for a lot of actor (around 5000 on my machine) performances are really bad for interaction.

You can color the vtkTensorGlyphs differently the following way. I'll show you some snippets of my C++ Code using different colored tensor glyphs. I hope you can integrate something similar into your python code:

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();

Although it may have been the intention of the VTK developers to use RGB tuples for color definition, you only have to use the first parameter "r". Varying "r" within an interval of [0,1] will result in different colors.

Used VTK 6.1.0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM