一:主要的知识点
1、说明
本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程------逐行解析官网所有Python示例-CSDN博客
2、知识点纪要
本段代码主要涉及的有①vtkElevationFilter的标量分配方法,②vtkDeformPointSet的网格变形方法简介
二:代码及注释
python
import vtkmodules.vtkInteractionStyle
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonCore import vtkPoints
from vtkmodules.vtkCommonDataModel import vtkPolyData, vtkCellArray
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkRenderingCore import vtkActor, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, \
vtkPolyDataMapper
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersCore import vtkElevationFilter
from vtkmodules.vtkFiltersGeneral import vtkDeformPointSet
def main():
colors = vtkNamedColors()
# 创建一个球形去变形
sphere = vtkSphereSource()
sphere.SetThetaResolution(51)
sphere.SetPhiResolution(17)
sphere.Update()
bounds = sphere.GetOutput().GetBounds()
"""
vtkElevationFilter 为 3D 几何体中的顶点分配标量值(Scalar Values)
这些标量值通常用于表示高程(Elevation)或沿着某一方向的渐变
简而言之,它根据每个点在 3D 空间中沿着一条指定直线的投影位置,来计算一个数值,并将这个数值作为该点的属性数据
用户通过 SetLowPoint(x_L, y_L, z_L) 和 SetHighPoint(x_H, y_H, z_H) 定义了一条直线
对于输入几何体上的每一个顶点 P,过滤器计算 P 沿着这条直线方向的投影距离
位于 LowPoint 处的投影值被映射为最低的标量值(默认 0)
位于 HighPoint 处的投影值被映射为最高的标量值(默认 1)
位于两者之间的点,其标量值通过线性插值得到
"""
ele = vtkElevationFilter()
ele.SetInputConnection(sphere.GetOutputPort())
ele.SetLowPoint((bounds[1] + bounds[0]) / 2.0,
(bounds[3] + bounds[2]) / 2.0,
-bounds[5])
ele.SetHighPoint((bounds[1] + bounds[0]) / 2.0,
(bounds[3] + bounds[2]) / 2.0,
bounds[5])
ele.Update()
pts = vtkPoints()
pts.SetNumberOfPoints(6)
pts.SetPoint(0,
bounds[0] - 0.1 * (bounds[1] - bounds[0]),
(bounds[3] + bounds[2]) / 2.0,
(bounds[5] + bounds[4]) / 2.0)
pts.SetPoint(1,
bounds[1] + 0.1 * (bounds[1] - bounds[0]),
(bounds[3] + bounds[2]) / 2.0,
(bounds[5] + bounds[4]) / 2.0)
pts.SetPoint(2,
(bounds[1] + bounds[0]) / 2.0,
bounds[2] - 0.1 * (bounds[3] - bounds[2]),
(bounds[5] + bounds[4]) / 2.0)
pts.SetPoint(3,
(bounds[1] + bounds[0]) / 2.0,
bounds[3] + 0.1 * (bounds[3] - bounds[2]),
(bounds[5] + bounds[4]) / 2.0)
pts.SetPoint(4,
(bounds[1] + bounds[0]) / 2.0,
(bounds[3] + bounds[2]) / 2.0,
bounds[4] - 0.1 * (bounds[5] - bounds[4]))
pts.SetPoint(5,
(bounds[1] + bounds[0]) / 2.0,
(bounds[3] + bounds[2]) / 2.0,
bounds[5] + 0.1 * (bounds[5] - bounds[4]))
tris = vtkCellArray()
cells = [[2, 0, 4], [1, 2, 4], [3, 1, 4], [0, 3, 4], [0, 2, 5], [2, 1, 5], [1, 3, 5], [3, 0, 5]]
for cell in cells:
tris.InsertNextCell(3)
for c in cell:
tris.InsertCellPoint(c)
pd = vtkPolyData()
pd.SetPoints(pts)
pd.SetPolys(tris)
meshMapper = vtkPolyDataMapper()
meshMapper.SetInputData(pd)
meshActor = vtkActor()
meshActor.SetMapper(meshMapper)
meshActor.GetProperty().SetRepresentationToWireframe() # 只展示结构
meshActor.GetProperty().SetColor(colors.GetColor3d('Black'))
"""
vtkDeformPointSet 基于控制网格的3D几何体形变的过滤器
允许用户通过操作一个简单的"笼子"或"控制网格"来平滑地、直观地改变复杂模型的形状,而无需直接修改模型本身的数千甚至数百万个顶点
基于控制网格的形变,需要输入对象,即要被形变的3D模型,控制对象,一个简单的,由用户定义的3D网格,必须包裹住输入对象
对于球体内部的任何一个点 P vtkDeformPointSet 算法需要回答一个问题:
"如果我移动笼子上的某个顶点 P control,球体上的 P sphere 应该移动多少?"
答案由插值权重 wi决定。对于球体上的一个点 Psphere,它与笼子上的所有顶点 P
control,i都有一个权重 wi关联,且所有权重之和 ∑w i 通常等于 1。
权重 w i的含义:w i越大,表示 P sphere 距离 P
control,i越近,或受其影响越大。w i越小(接近 0),表示影响越小。
计算这些权重的方法有很多种(如均值坐标法或径向基函数),但它们都依赖于笼子的拓扑结构来确定 P
sphere在笼子内部的相对位置
"""
deform = vtkDeformPointSet()
deform.SetInputData(ele.GetOutput())
deform.SetControlMeshData(pd)
deform.Update()
# 移动控制点,使其发生变形,如果没有下面的这几行代码,球体不会发生形变
controlPoint = pts.GetPoint(5)
pts.SetPoint(5, controlPoint[0],
controlPoint[1],
bounds[5] + .8 * (bounds[5] - bounds[4]))
pts.Modified()
polyMapper = vtkPolyDataMapper()
polyMapper.SetInputConnection(deform.GetOutputPort())
polyActor = vtkActor()
polyActor.SetMapper(polyMapper)
renderer = vtkRenderer()
renWin = vtkRenderWindow()
renWin.AddRenderer(renderer)
iren = vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
renderer.AddActor(polyActor)
renderer.AddActor(meshActor)
renderer.GetActiveCamera().SetPosition(1, 1, 1)
renderer.ResetCamera()
renderer.SetBackground(colors.GetColor3d('DarkSlateGray'))
renWin.SetSize(300, 300)
renWin.SetWindowName('DeformPointSet')
renWin.Render()
iren.Start()
if __name__ == '__main__':
main()