VTK 碰撞检测 模型相交检测 几种实现方式

VTK 碰撞检测 功能实现有几种方式:

1, 求物体的包围盒,然后检测包围盒与线、面、或者另一个包围盒是否相交。包围盒主要包括球体、轴对齐包围盒(AABB)、有向包围盒(OBB)和凸包(Convex Hull),

2,VTK自带了一个vtkCollisionDetectionFilter过滤器,来计算碰撞检测,此过滤器利用的就是OBB包围盒,使用简单,只需提供两个物体的数据集和矩阵即可。

3.判断polydta1中的点是否在polydata2曲面的内部,如果在内部即发生碰撞,如果所有点都不在内部即两个polydata没有发生碰撞。原理类似于点是否在面内的判断方法,以点得到一条线段,判断其与面的交点,依据该点两侧交点个数的奇偶性判断,如果两侧交点均为偶数则在面外,如果为奇数则在面内 ;

1. 直接使用包围盒

好处: 简单快速,可能精度不高

import vtk

import vtk

def do_bounding_boxes_intersect(bounds1, bounds2):
    # 检查每个轴是否分离
    for i in range(3):
        if bounds1[2 * i] > bounds2[2 * i + 1] or bounds1[2 * i + 1] < bounds2[2 * i]:
            return False
    return True

# 创建两个示例的 vtkPolyData 对象
sphere1 = vtk.vtkSphereSource()
sphere1.SetCenter(0, 0, 0)
sphere1.SetRadius(5)
sphere1.Update()
polydata1 = sphere1.GetOutput()

sphere2 = vtk.vtkSphereSource()
sphere2.SetCenter(8, 0, 0)
sphere2.SetRadius(5)
sphere2.Update()
polydata2 = sphere2.GetOutput()

# 获取包围盒
bounds1 = [0] * 6
bounds2 = [0] * 6
polydata1.GetBounds(bounds1)
polydata2.GetBounds(bounds2)

# 打印包围盒范围
print(f"Bounds 1: {bounds1}")
print(f"Bounds 2: {bounds2}")

# 检查包围盒是否相交
if do_bounding_boxes_intersect(bounds1, bounds2):
    print("The bounding boxes intersect.")
else:
    print("The bounding boxes do not intersect.")

# 创建一个mapper和actor来显示包围盒
bbox_mapper = vtk.vtkPolyDataMapper()
bbox_mapper.SetInputData(polydata1)

bbox_actor = vtk.vtkActor()
bbox_actor.SetMapper(bbox_mapper)
bbox_actor.GetProperty().SetColor(1, 0, 0)  # 设置颜色为红色

# 创建一个mapper和actor来显示包围盒
bbox_mapper2 = vtk.vtkPolyDataMapper()
bbox_mapper2.SetInputData(polydata2)

bbox_actor2 = vtk.vtkActor()
bbox_actor2.SetMapper(bbox_mapper2)
bbox_actor2.GetProperty().SetColor(0, 1, 0)  # 设置颜色为红色


# 创建一个renderer和renderWindow来显示结果
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)

renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)

renderer.AddActor(bbox_actor)
renderer.AddActor(bbox_actor2)
  
renderWindow.Render()
renderWindowInteractor.Start()

输出:

The bounding boxes intersect.


 

2. vtkCollisionDetectionFilter

好处: 计算较多,有耗时长

#!/usr/bin/env python

import time

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingFreeType
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonMath import vtkMatrix4x4
from vtkmodules.vtkCommonTransforms import vtkTransform
from vtkmodules.vtkFiltersModeling import vtkCollisionDetectionFilter
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer,
    vtkTextActor
)


def get_program_parameters():
    import argparse
    description = 'Collision detection.'
    epilogue = '''
This examples uses vtkCollisionDetectionFilter to find the intersection between a
 fixed (solid white) and moving (red wireframe) sphere.
The animation places the moving sphere some distance from the fixed sphere and
 moves the moving sphere until it contacts the fixed sphere.

Three collision modes are available and can be set as the first argument on the command line.

1. All contacts (0) finds all the contacting cell pairs with two points per collision.
2. First contact (1) quickly find the first contact point.
3. Half contacts (2) finds all the contacting cell pairs with one points per collision.

    '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('contactMode', nargs='?', default=0, type=int, help='Contact mode 0 (default), 1, or 2.')
    args = parser.parse_args()
    return args.contactMode


def main():
    contactMode = get_program_parameters()

    # Define colors
    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()

    collide = vtkCollisionDetectionFilter()
    collide.SetInputConnection(0, sphere0.GetOutputPort())
    collide.SetTransform(0, transform0)
    collide.SetInputConnection(1, sphere1.GetOutputPort())
    collide.SetMatrix(1, matrix1)
    collide.SetBoxTolerance(0.0)
    collide.SetCellTolerance(0.0)
    collide.SetNumberOfCellsPerNode(2)
    if contactMode == 0:
        collide.SetCollisionModeToAllContacts()
    elif contactMode == 1:
        collide.SetCollisionModeToFirstContact()
    else:
        collide.SetCollisionModeToHalfContacts()
    collide.GenerateScalarsOn()

    # Visualize
    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())
    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)

    # Move the first object
    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()

3. 基于vtkSelectEnclosedPoints

vtkSelectEnclosedPoints 可以用来检查一个点集是否被另一个 vtkPolyData 完全包围。虽然它不是专门为碰撞检测设计的,但可以在某些情况下使用它来检查两个对象之间的包围关系。以下是一个示例,展示如何使用 vtkSelectEnclosedPoints 来检测两个 vtkPolyData 对象是否相交(假设一个对象包围另一个对象的某些点)

import vtk

# 创建两个示例的 vtkPolyData 对象
sphere1 = vtk.vtkSphereSource()
sphere1.SetCenter(0, 0, 0)
sphere1.SetRadius(5)
sphere1.Update()
polydata1 = sphere1.GetOutput()

sphere2 = vtk.vtkSphereSource()
sphere2.SetCenter(8, 0, 0)
sphere2.SetRadius(5)
sphere2.Update()
polydata2 = sphere2.GetOutput()

# 获取 polydata2 的点集
points = polydata2.GetPoints()

# 创建 vtkSelectEnclosedPoints 对象
enclosedPoints = vtk.vtkSelectEnclosedPoints()
enclosedPoints.SetInputData(polydata2)
enclosedPoints.SetSurfaceData(polydata1)
enclosedPoints.Update()

# 检查是否有点被包围
numEnclosedPoints = 0
for i in range(points.GetNumberOfPoints()):
    if enclosedPoints.IsInside(i):
        numEnclosedPoints += 1

if numEnclosedPoints > 0:
    print("The objects intersect.")
    print(f"Number of enclosed points: {numEnclosedPoints}")
else:
    print("The objects do not intersect.")

输出:

The objects intersect.
Number of enclosed points: 2

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恋恋西风

up up up

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值