#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys from direct.showbase.ShowBase import ShowBase from panda3d.core import ( Point3, Vec3, CollisionTraverser, CollisionHandlerQueue, CollisionNode, CollisionRay, CollisionSphere, BitMask32 ) class BasicRayTest(ShowBase): def __init__(self): ShowBase.__init__(self) print("=== 基础射线测试 ===") # 简单的相机设置 self.cam.setPos(0, -20, 5) self.cam.lookAt(0, 0, 0) print(f"相机位置: {self.cam.getPos()}") # 创建简单的碰撞球体在原点 self.createSimpleSphere() # 创建简单的射线检测 self.createSimpleRay() # 测试简单的射线 self.testSimpleRay() def createSimpleSphere(self): """在原点创建简单的碰撞球体""" print(f"\n创建测试球体...") # 创建碰撞节点 collisionNode = CollisionNode('testSphere') # 创建球体,中心在原点,半径5 sphere = CollisionSphere(Point3(0, 0, 0), 5.0) collisionNode.addSolid(sphere) # 设置掩码 collisionNode.setIntoCollideMask(BitMask32.bit(0)) collisionNode.setFromCollideMask(BitMask32.allOff()) # 附加到render self.sphereNP = self.render.attachNewNode(collisionNode) # 显示碰撞体 self.sphereNP.show() print(f"球体创建在原点: (0, 0, 0)") print(f"球体半径: 5.0") print(f"球体 IntoMask: {collisionNode.getIntoCollideMask()}") def createSimpleRay(self): """创建简单的射线检测""" print(f"\n创建射线检测...") # 创建遍历器和队列 self.traverser = CollisionTraverser() self.queue = CollisionHandlerQueue() # 创建射线节点 rayNode = CollisionNode('testRay') self.ray = CollisionRay() rayNode.addSolid(self.ray) # 设置射线掩码 rayNode.setFromCollideMask(BitMask32.bit(0)) rayNode.setIntoCollideMask(BitMask32.allOff()) # 创建射线节点路径 self.rayNP = self.render.attachNewNode(rayNode) # 注册到遍历器 self.traverser.addCollider(self.rayNP, self.queue) print(f"射线 FromMask: {rayNode.getFromCollideMask()}") print(f"遍历器中的碰撞器数量: {self.traverser.getNumColliders()}") def testSimpleRay(self): """测试简单的射线""" print(f"\n=== 射线测试 ===") # 测试1: 从相机直接射向原点 camera_pos = self.cam.getPos() target_pos = Point3(0, 0, 0) direction = target_pos - camera_pos direction.normalize() print(f"测试1: 从相机射向原点") print(f" 起点: {camera_pos}") print(f" 方向: {direction}") # 设置射线 self.ray.setOrigin(camera_pos) self.ray.setDirection(direction) # 执行检测 self.queue.clearEntries() self.traverser.traverse(self.render) entries = self.queue.getNumEntries() print(f" 检测到 {entries} 个碰撞") if entries > 0: self.queue.sortEntries() for i in range(entries): entry = self.queue.getEntry(i) hitPos = entry.getSurfacePoint(self.render) hitNode = entry.getIntoNodePath() distance = (hitPos - camera_pos).length() print(f" 碰撞 {i}: {hitNode.getName()}, 距离: {distance:.2f}") # 测试2: 从固定位置射向球体 print(f"\n测试2: 从固定位置射向球体") fixed_origin = Point3(-10, 0, 0) fixed_direction = Vec3(1, 0, 0) # 直接向右 print(f" 起点: {fixed_origin}") print(f" 方向: {fixed_direction}") self.ray.setOrigin(fixed_origin) self.ray.setDirection(fixed_direction) self.queue.clearEntries() self.traverser.traverse(self.render) entries = self.queue.getNumEntries() print(f" 检测到 {entries} 个碰撞") if entries > 0: self.queue.sortEntries() for i in range(entries): entry = self.queue.getEntry(i) hitPos = entry.getSurfacePoint(self.render) hitNode = entry.getIntoNodePath() distance = (hitPos - fixed_origin).length() print(f" 碰撞 {i}: {hitNode.getName()}, 距离: {distance:.2f}") # 测试3: 检查射线是否正确设置 print(f"\n测试3: 检查射线设置") print(f" 射线起点: {self.ray.getOrigin()}") print(f" 射线方向: {self.ray.getDirection()}") # 手动计算射线是否应该击中球体 origin = self.ray.getOrigin() direction = self.ray.getDirection() sphere_center = Point3(0, 0, 0) sphere_radius = 5.0 # 计算从射线起点到球心的向量 to_sphere = sphere_center - origin # 计算射线上最接近球心的点 t = to_sphere.dot(direction) closest_point = origin + direction * t # 计算最近距离 distance_to_center = (closest_point - sphere_center).length() print(f" 到球心的最近距离: {distance_to_center:.2f}") print(f" 球体半径: {sphere_radius:.2f}") if distance_to_center <= sphere_radius: print(f" 射线应该击中球体!") else: print(f" 射线会错过球体") if __name__ == "__main__": app = BasicRayTest() print("\n基础测试完成!")