消隐与Z-Buffer
使用缓冲器记录物体表面在屏幕上投影所覆盖范围内的全部像素的深度值,依次访问屏幕范围内物体表面所覆盖的每一像素,用深度小(深度用z值表示,z值小表示离视点近)的像素点颜色替代深度大的像素点颜色可以实现消隐,称为深度缓冲器算法。深度缓冲器算法也称为Z-Buffer算法,在物体空间内不对物体表面的可见性进行检测,在图像空间中根据每个像素的深度值确定最终绘制到屏幕的物体表面上各个像素的颜色。
下面的例子中从读入一个简单的8个顶点的立方体STL模型,用vtkSelectVisiblePoints类过滤可见点,并输出相关信息。
VTK: vtkSelectVisiblePoints Class Reference: extract points that are visible (based on z-buffer calculation). vtkSelectVisiblePoints is a filter that selects points based on whether they are visible or not. Visibility is determined by accessing the z-buffer of a rendering window. (The position of each input point is converted into display coordinates, and then the z-value at that point is obtained. If within the user-specified tolerance, the point is considered visible.) Points that are visible are passed to the output. Associated data attributes are passed to the output as well.
鼠标左键旋转到不同视角,点击右键观察输出的信息:
#!usrbinenv python import vtk def loadSTL(filenameSTL): readerSTL = vtk.vtkSTLReader() readerSTL.SetFileName(filenameSTL) # 'update' the reader i.e. read the .stl file readerSTL.Update() polydata = readerSTL.GetOutput() # If there are no points in 'vtkPolyData' something went wrong if polydata.GetNumberOfPoints() == 0: raise ValueError("No point data could be loaded from '" + filenameSTL) return None return polydata # Customize vtkInteractorStyleTrackballCamera class MyInteractor(vtk.vtkInteractorStyleTrackballCamera): def __init__(self, parent=None): self.AddObserver("RightButtonPressEvent", self.RightButtonPressEvent) def SetVisibleFilter(self, vis): self.VisibleFilter = vis def RightButtonPressEvent(self,obj,event): self.VisibleFilter.Update() print "number of visible points: ", self.VisibleFilter.GetOutput().GetNumberOfPoints() mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(self.VisibleFilter.GetOutput()) actor =vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetPointSize(15) self.GetDefaultRenderer().AddActor(actor) # Forward events self.OnRightButtonDown() return def CreateScene(): # Create a rendering window and renderer renWin = vtk.vtkRenderWindow() ren = vtk.vtkRenderer() # Set background color ren.GradientBackgroundOn() ren.SetBackground(.1, .1, .1) ren.SetBackground2(0.8,0.8,0.8) # Set window size renWin.SetSize(600, 600) renWin.AddRenderer(ren) # Create a renderwindowinteractor iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) style = MyInteractor() style.SetDefaultRenderer(ren) iren.SetInteractorStyle(style) # load STL file mesh = loadSTL("cube.stl") mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(mesh) # maps polygonal data to graphics primitives actor = vtk.vtkLODActor() actor.SetMapper(mapper) ren.AddActor(actor) visPts = vtk.vtkSelectVisiblePoints() visPts.SetInputData(mesh) visPts.SetRenderer(ren) style.SetVisibleFilter(visPts) # Enable user interface interactor iren.Initialize() iren.Start() if __name__ == "__main__": CreateScene()
使用vtkCellPicker可以拾取模型上可见的面和点的信息(vtkCellPicker will shoot a ray into a 3D scene and return information about the first object that the ray hit),而用vtkPointPicker拾取点时会选择离射线距离最近的点,因此所选的点可能位于不可见的表面上。
#!usrbinenv python import vtk def loadSTL(filenameSTL): readerSTL = vtk.vtkSTLReader() readerSTL.SetFileName(filenameSTL) # 'update' the reader i.e. read the .stl file readerSTL.Update() polydata = readerSTL.GetOutput() print "Number of Cells:", polydata.GetNumberOfCells() print "Number of Points:", polydata.GetNumberOfPoints() # If there are no points in 'vtkPolyData' something went wrong if polydata.GetNumberOfPoints() == 0: raise ValueError("No point data could be loaded from " + filenameSTL) return None return polydata # Customize vtkInteractorStyleTrackballCamera class MyInteractor(vtk.vtkInteractorStyleTrackballCamera): def __init__(self,parent=None): self.AddObserver("RightButtonPressEvent", self.RightButtonPressEvent) def RightButtonPressEvent(self,obj,event): clickPos = self.GetInteractor().GetEventPosition() print "Picking pixel: " , clickPos # Pick from this location picker = self.GetInteractor().GetPicker() picker.Pick(clickPos[0], clickPos[1], 0, self.GetDefaultRenderer()) # If CellId = -1, nothing was picked if(picker.GetCellId() != -1): print "Pick position is: " , picker.GetPickPosition() print "Cell id is:", picker.GetCellId() print "Point id is:", picker.GetPointId() point_position = mesh.GetPoint(picker.GetPointId()) # Create a sphere sphereSource = vtk.vtkSphereSource() sphereSource.SetCenter(point_position) #sphereSource.SetRadius(0.2) sphereSource.SetRadius(0.02) # Create a mapper and actor mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(sphereSource.GetOutputPort()) actor = vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetColor(1.0, 0.0, 0.0) self.GetDefaultRenderer().AddActor(actor) # Forward events self.OnRightButtonDown() return def CreateScene(): # Create a rendering window and renderer renWin = vtk.vtkRenderWindow() # Set window size renWin.SetSize(600, 600) ren = vtk.vtkRenderer() # Set background color ren.GradientBackgroundOn() ren.SetBackground(.1, .1, .1) ren.SetBackground2(0.8,0.8,0.8) renWin.AddRenderer(ren) # Create a renderwindowinteractor iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) style = MyInteractor() style.SetDefaultRenderer(ren) iren.SetInteractorStyle(style) # vtkCellPicker will shoot a ray into a 3D scene and return information about # the first object that the ray hits. cellPicker = vtk.vtkCellPicker() iren.SetPicker(cellPicker) # load STL file global mesh mesh = loadSTL("Suzanne.stl") mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(mesh) # maps polygonal data to graphics primitives actor = vtk.vtkLODActor() actor.SetMapper(mapper) actor.GetProperty().EdgeVisibilityOn() actor.GetProperty().SetLineWidth(0.3) ren.AddActor(actor) # Enable user interface interactor iren.Initialize() iren.Start() if __name__ == "__main__": CreateScene()
参考:
VTK - Users - point picking problem
VTK: vtkCellPicker Class Reference
VTK: vtkPointPicker Class Reference
VTK/Examples/Cxx/PolyData/SelectVisiblePoints
Ray Casting with Python and VTK: Intersecting lines/rays with surface meshes