一:主要的知识点
1、说明
本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程——逐行解析官网所有Python示例-CSDN博客
2、知识点纪要
本段代码主要涉及的有①vtkCollisionDetectionFilter检测三维物体是否碰撞,②三种碰撞模式的不同
二:代码及注释
import vtkmodules.vtkRenderingOpenGL2 import vtkmodules.vtkInteractionStyle from vtkmodules.vtkCommonColor import vtkNamedColors from vtkmodules.vtkFiltersSources import vtkSphereSource from vtkmodules.vtkCommonMath import vtkMatrix4x4 from vtkmodules.vtkCommonTransforms import vtkTransform from vtkmodules.vtkFiltersModeling import vtkCollisionDetectionFilter from vtkmodules.vtkRenderingCore import ( vtkActor, vtkPolyDataMapper, vtkRenderWindow, vtkRenderWindowInteractor, vtkRenderer, vtkTextActor ) import time def main(): contactMode = 0 colors = vtkNamedColors() sphere0 = vtkSphereSource() sphere0.SetRadius(0.29) sphere0.SetPhiResolution(31) sphere0.SetThetaResolution(31) sphere0.SetCenter(0.0, 0, 0) sphere1 = vtkSphereSource() sphere1.SetPhiResolution(30) sphere1.SetThetaResolution(30) sphere1.SetRadius(0.3) matrix1 = vtkMatrix4x4() transform0 = vtkTransform() """ vtkCollisionDetectionFilter 检测两个三维物体(多边形模型)之间是否发生碰撞(接触或交叉) 输出结果: 类型 说明 vtkPolyData 物体A vtkPolyData 物体B vtkPolyData 碰撞点(接触点云) """ collide = vtkCollisionDetectionFilter() collide.SetInputConnection(0, sphere0.GetOutputPort()) collide.SetInputConnection(1, sphere1.GetOutputPort()) collide.SetTransform(0, transform0) # 设置输入0的变换 collide.SetMatrix(1, matrix1) # 设置输入1的变换 collide.SetBoxTolerance(0.0) # 设置包围盒容差,设置为0.0表示严格检查,要求包围盒必须接触或重叠,非0允许在几何体实际接触之前就报告“接近” collide.SetCellTolerance(0.0) # 设置单元容差,0.0意味着只有实际接触或重叠才被视为碰撞 collide.SetNumberOfCellsPerNode(2) # 设置叶子节点的最大单元数, #设置为2是一个非常小的值,这意味着:树结构会更深、更精细。构造时间可能会增加。但最终的碰撞测试可能会更快且更精确,因为它能更快地排除不相关的几何体 if contactMode == 0: """ 报告所有发现的接触点。 过滤器会彻底检查两个对象的所有几何体(单元)之间的关系。 它会继续运行,直到检查完所有潜在的碰撞对,并在碰撞数据集中返回所有接触的单元。 效率最低,结果最完整 """ collide.SetCollisionModeToAllContacts() elif contactMode == 1: """ 效率优先。 过滤器一旦发现第一次几何单元接触,就会立即停止执行。 它只报告这个首次发现的接触,并认为“碰撞已经发生”,然后退出。 效率最高,结果完整性最低 """ collide.SetCollisionModeToFirstContact() else: """ 报告单向接触。 这是一个更复杂的模式,通常用于优化。它只会报告模型 A 穿透模型 B 的接触点,而忽略模型 B 穿透模型 A 的接触点(如果它们是分开处理的话)。 这对于某些对称或定向的碰撞场景非常有用,可以减少一半的计算量 """ collide.SetCollisionModeToHalfContacts() collide.GenerateScalarsOn() # 指示碰撞检测过滤器在其输出数据中生成并包含表示“接触状态”的标量数据 mapper1 = vtkPolyDataMapper() mapper1.SetInputConnection(collide.GetOutputPort(0)) mapper1.ScalarVisibilityOff() actor1 = vtkActor() actor1.SetMapper(mapper1) actor1.GetProperty().BackfaceCullingOn() #启用背面剔除,指示渲染器不要绘制几何体上背向相机的三角形或多边形 actor1.SetUserTransform(transform0) actor1.GetProperty().SetDiffuseColor(colors.GetColor3d("Tomato")) actor1.GetProperty().SetRepresentationToWireframe() mapper2 = vtkPolyDataMapper() mapper2.SetInputConnection(collide.GetOutputPort(1)) actor2 = vtkActor() actor2.SetMapper(mapper2) actor2.GetProperty().BackfaceCullingOn() actor2.SetUserMatrix(matrix1) mapper3 = vtkPolyDataMapper() mapper3.SetInputConnection(collide.GetContactsOutputPort()) """ SetResolveCoincidentTopologyToPolygonOffset 用来解决3D渲染时的共面拓扑冲突问题,也称为Z-Fighting 当两个或多个几何体(或同一个几何体的不同部分)在3D空间中精确地位于同一个平面上时,就会发生 Z-Fighting 由于计算机的浮点精度限制,深度缓冲区(Z-Buffer)无法确定哪个多边形在前面,哪个在后面。这导致的结果是: 闪烁 (Flickering):渲染器在渲染这两个共面多边形时不断切换它们的先后顺序。 条纹或斑点 (Stippling):在同一个表面上随机出现交替的颜色或纹理 SetResolveCoincidentTopologyToPolygonOffset 启用多边形偏移来解决问题。 多边形偏移原理 偏移正面: 当需要同时渲染两个共面几何体(例如,一个实体表面和一个在其上的线框)时,您可以选择让其中一个几何体(比如线框)在渲染时沿着其法线方向稍微向相机移动(偏移)。 打破共面: 即使两个几何体的数学位置是精确共面的,由于渲染时的轻微偏移,它们的深度值在 Z-Buffer 中不再相同。 消除冲突: 这样,深度缓冲区就能明确判断哪个多边形在前,哪个在后,从而消除闪烁和条纹。 """ mapper3.SetResolveCoincidentTopologyToPolygonOffset() actor3 = vtkActor() actor3.SetMapper(mapper3) actor3.GetProperty().SetColor(colors.GetColor3d("Black")) actor3.GetProperty().SetLineWidth(3.0) txt = vtkTextActor() txt.GetTextProperty().SetFontSize(18) renderer = vtkRenderer() renderer.UseHiddenLineRemovalOn() renderer.AddActor(actor1) renderer.AddActor(actor2) renderer.AddActor(actor3) renderer.AddActor(txt) renderer.SetBackground(colors.GetColor3d("Gray")) renderer.UseHiddenLineRemovalOn() renderWindow = vtkRenderWindow() renderWindow.SetSize(640, 480) renderWindow.AddRenderer(renderer) interactor = vtkRenderWindowInteractor() interactor.SetRenderWindow(renderWindow) numSteps = 100 dx = 1.0 / float(numSteps) * 2.0 transform0.Translate(-numSteps * dx - .3, 0.0, 0.0) renderWindow.Render() renderer.GetActiveCamera().Azimuth(-60) renderer.GetActiveCamera().Elevation(45) renderer.GetActiveCamera().Dolly(1.2) renderWindow.SetWindowName('CollisionDetection') renderWindow.Render() for i in range(0, numSteps): transform0.Translate(dx, 0.0, 0.0) renderer.ResetCameraClippingRange() s = '{:s}: Number of contact cells is {:d}'.format(collide.GetCollisionModeAsString(), collide.GetNumberOfContacts()) txt.SetInput(s) renderWindow.Render() if collide.GetNumberOfContacts() > 0: break # The total animation time is 3 seconds time.sleep(3.0 / numSteps) renderer.ResetCamera() renderWindow.Render() renderWindow.Render() interactor.Start() if __name__ == '__main__': main()