EG/demo/basic_ray_test.py
2025-07-02 09:49:59 +08:00

175 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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基础测试完成!")