#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
from direct.showbase.ShowBase import ShowBase
from panda3d.core import (
    Point3, Point2, Vec3, CollisionTraverser, CollisionHandlerQueue,
    CollisionNode, CollisionRay, CollisionSphere, BitMask32, CardMaker
)

class CenterRayTest(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        # 设置相机位置 - 和你的程序一样
        self.cam.setPos(-3.87655, -188.38084, 82.602684)
        self.cam.lookAt(0, 0, 0)
        
        print(f"相机位置: {self.cam.getPos()}")
        print(f"相机朝向: {self.cam.getHpr()}")
        
        # 创建测试立方体
        self.createTestCube()
        
        # 设置射线检测
        self.setupRayPicking()
        
        # 测试从屏幕中心射出的射线
        self.testCenterRay()
        
        # 测试朝向立方体的直接射线
        self.testDirectRay()
    
    def createTestCube(self):
        """创建测试立方体"""
        cm = CardMaker("TestCube")
        cm.setFrame(-1, 1, -1, 1)
        self.cube = self.render.attachNewNode(cm.generate())
        
        self.cube.setPos(0, 10, 3)
        self.cube.setScale(3, 3, 3)
        self.cube.setColor(1, 0, 0, 1)
        self.cube.setTwoSided(True)
        self.cube.setHpr(45, 15, 0)
        
        print(f"立方体世界位置: {self.cube.getPos(self.render)}")
        
        # 添加碰撞检测
        cNode = CollisionNode('TestCubeCollision')
        cSphere = CollisionSphere(Point3(0, 0, 0), 4.0)
        cNode.addSolid(cSphere)
        cNode.setIntoCollideMask(BitMask32.bit(0))
        cNode.setFromCollideMask(BitMask32.allOff())
        
        self.cNodePath = self.cube.attachNewNode(cNode)
        print(f"碰撞球体半径: 4.0, 实际半径: {4.0 * 3} = 12.0")
    
    def setupRayPicking(self):
        """设置射线检测"""
        self.picker = CollisionTraverser()
        self.pickerQueue = CollisionHandlerQueue()
        
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        
        mask = BitMask32.bit(0)
        self.pickerNode.setFromCollideMask(mask)
        self.pickerNode.setIntoCollideMask(BitMask32.allOff())
        
        self.pickerNP = self.cam.attachNewNode(self.pickerNode)
        self.picker.addCollider(self.pickerNP, self.pickerQueue)
    
    def testCenterRay(self):
        """测试从屏幕中心射出的射线"""
        print(f"\n=== 屏幕中心射线测试 ===")
        
        # 屏幕中心的归一化坐标应该是 (0, 0)
        normalized_x = 0.0
        normalized_y = 0.0
        
        print(f"屏幕中心归一化坐标: ({normalized_x}, {normalized_y})")
        
        camera_pos = self.cam.getPos(self.render)
        lens = self.cam.node().getLens()
        
        nearPoint = Point3()
        farPoint = Point3()
        
        if lens.extrude(Point2(normalized_x, normalized_y), nearPoint, farPoint):
            nearWorldPoint = self.cam.getRelativePoint(self.render, nearPoint)
            farWorldPoint = self.cam.getRelativePoint(self.render, farPoint)
            
            rayDirWorld = farWorldPoint - nearWorldPoint
            rayDirWorld.normalize()
            
            print(f"射线起点: {camera_pos}")
            print(f"射线方向: {rayDirWorld}")
            
            # 设置射线
            self.pickerRay.setOrigin(camera_pos)
            self.pickerRay.setDirection(rayDirWorld)
            
            # 执行碰撞检测
            self.pickerQueue.clearEntries()
            self.picker.traverse(self.render)
            
            numEntries = self.pickerQueue.getNumEntries()
            print(f"检测到 {numEntries} 个碰撞")
            
            if numEntries > 0:
                self.pickerQueue.sortEntries()
                for i in range(numEntries):
                    entry = self.pickerQueue.getEntry(i)
                    hitPos = entry.getSurfacePoint(self.render)
                    hitNode = entry.getIntoNodePath()
                    distance = (hitPos - camera_pos).length()
                    print(f"  碰撞 {i}: {hitNode.getName()}, 距离: {distance:.2f}, 位置: {hitPos}")
            else:
                # 分析射线到立方体的距离
                cube_world_pos = self.cube.getPos(self.render)
                to_cube = cube_world_pos - camera_pos
                cross_product = to_cube.cross(rayDirWorld)
                distance_to_ray = cross_product.length()
                
                print(f"  射线到立方体中心的距离: {distance_to_ray:.2f}")
                print(f"  需要小于: 12.0")
                print(f"  射线错过了立方体")
    
    def testDirectRay(self):
        """测试直接朝向立方体的射线"""
        print(f"\n=== 直接射线测试 ===")
        
        camera_pos = self.cam.getPos(self.render)
        cube_pos = self.cube.getPos(self.render)
        
        # 计算从相机直接指向立方体的射线
        direct_direction = cube_pos - camera_pos
        direct_direction.normalize()
        
        print(f"相机位置: {camera_pos}")
        print(f"立方体位置: {cube_pos}")
        print(f"直接方向: {direct_direction}")
        
        # 设置射线
        self.pickerRay.setOrigin(camera_pos)
        self.pickerRay.setDirection(direct_direction)
        
        # 执行碰撞检测
        self.pickerQueue.clearEntries()
        self.picker.traverse(self.render)
        
        numEntries = self.pickerQueue.getNumEntries()
        print(f"检测到 {numEntries} 个碰撞")
        
        if numEntries > 0:
            self.pickerQueue.sortEntries()
            for i in range(numEntries):
                entry = self.pickerQueue.getEntry(i)
                hitPos = entry.getSurfacePoint(self.render)
                hitNode = entry.getIntoNodePath()
                distance = (hitPos - camera_pos).length()
                print(f"  碰撞 {i}: {hitNode.getName()}, 距离: {distance:.2f}, 位置: {hitPos}")
        else:
            print("  直接射线也没击中！可能是碰撞设置问题。")

if __name__ == "__main__":
    app = CenterRayTest()
    print("\n测试完成！") 