forked from Rowland/EG
打包后场景聚焦功能,动画播放
This commit is contained in:
parent
79b2547446
commit
f4d21a62f9
@ -138,8 +138,8 @@ class MovementController(object):
|
||||
self.showbase.accept("j", self.print_position)
|
||||
|
||||
# mouse
|
||||
self.showbase.accept("mouse1", self.set_mouse_enabled, [True])
|
||||
self.showbase.accept("mouse1-up", self.set_mouse_enabled, [False])
|
||||
self.showbase.accept("mouse3", self.set_mouse_enabled, [True])
|
||||
self.showbase.accept("mouse3-up", self.set_mouse_enabled, [False])
|
||||
|
||||
# arrow mouse navigation
|
||||
self.showbase.accept("arrow_up", self.set_hpr_movement, [1, 1])
|
||||
|
||||
2
main.py
2
main.py
@ -1,6 +1,8 @@
|
||||
import warnings
|
||||
|
||||
from core.Command_System import CommandManager
|
||||
from core.InfoPanelManager import InfoPanelManager
|
||||
from core.patrol_system import PatrolSystem
|
||||
from demo.video_integration import VideoManager
|
||||
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
|
||||
@ -11,7 +11,9 @@ from __future__ import print_function
|
||||
import json
|
||||
|
||||
from direct.actor.Actor import Actor
|
||||
from panda3d.core import TextNode, CardMaker, TextureStage, NodePath, Texture, TransparencyAttrib, CollisionTraverser
|
||||
from direct.showbase.ShowBaseGlobal import globalClock
|
||||
from panda3d.core import TextNode, CardMaker, TextureStage, NodePath, Texture, TransparencyAttrib, CollisionTraverser, \
|
||||
Point3
|
||||
from core.InfoPanelManager import InfoPanelManager
|
||||
# 获取渲染管线路径
|
||||
# 在文件开头添加sys导入(如果还没有的话)
|
||||
@ -79,9 +81,6 @@ class MainApp(ShowBase):
|
||||
from rpcore import RenderPipeline
|
||||
self.render_pipeline = RenderPipeline()
|
||||
self.render_pipeline.create(self)
|
||||
#self.render_pipeline.pre_show_base_init()
|
||||
#ShowBase.__init__(self)
|
||||
|
||||
|
||||
except ImportError as e:
|
||||
|
||||
@ -103,6 +102,9 @@ class MainApp(ShowBase):
|
||||
try:
|
||||
# 再导入controller模块
|
||||
from rpcore.util.movement_controller import MovementController
|
||||
|
||||
self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam
|
||||
|
||||
self.controller = MovementController(self)
|
||||
self.controller.set_initial_position(
|
||||
Vec3(0, -50, 20), Vec3(0, 0, 0))
|
||||
@ -115,6 +117,12 @@ class MainApp(ShowBase):
|
||||
self._last_clicked_node = None
|
||||
self._double_click_threshold = 0.3
|
||||
|
||||
self.cameraSpeed = 20.0
|
||||
self.cameraRotateSpeed=10.0
|
||||
|
||||
self.lastMouseX=0
|
||||
self.lastMouseY=0
|
||||
self.mouseRightPressed=False
|
||||
|
||||
self._loadFont()
|
||||
self.loadFullScene()
|
||||
@ -122,6 +130,9 @@ class MainApp(ShowBase):
|
||||
self.setupMouseClickHandler()
|
||||
self.cTrav = CollisionTraverser()
|
||||
|
||||
self.women_actor = None
|
||||
self.current_actor = None
|
||||
|
||||
if hasattr(self, 'accept'):
|
||||
base.accept("l", self.tour)
|
||||
|
||||
@ -182,6 +193,38 @@ class MainApp(ShowBase):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def checkAnimationStatus(self):
|
||||
"""检查场景中所有Actor的动画状态"""
|
||||
try:
|
||||
all_actors = self.render.findAllMatches("**/+ActorNode")
|
||||
print(f"=== 动画状态检查 ===")
|
||||
print(f"场景中总共有 {len(all_actors)} 个Actor")
|
||||
|
||||
for i, actor_np in enumerate(all_actors):
|
||||
actor_node = actor_np.node()
|
||||
if isinstance(actor_node, Actor):
|
||||
# 确保Actor可见
|
||||
actor_np.show()
|
||||
|
||||
current_anim = actor_node.getCurrentAnim()
|
||||
anim_names = actor_node.getAnimNames()
|
||||
print(f"Actor {i + 1} ({actor_np.getName()}):")
|
||||
print(f" 位置: {actor_np.getPos()}")
|
||||
print(f" 可见性: {actor_np.isHidden()}")
|
||||
print(f" 可用动画: {anim_names}")
|
||||
print(f" 当前播放: {current_anim}")
|
||||
if current_anim:
|
||||
frame = actor_node.getCurrentFrame(current_anim)
|
||||
num_frames = actor_node.getNumFrames(current_anim)
|
||||
play_rate = actor_node.getPlayRate(current_anim)
|
||||
print(f" 播放进度: {frame}/{num_frames} 帧")
|
||||
print(f" 播放速度: {play_rate}")
|
||||
else:
|
||||
print(f"节点 {actor_np.getName()} 不是Actor类型")
|
||||
print("==================")
|
||||
except Exception as e:
|
||||
print(f"检查动画状态时出错: {str(e)}")
|
||||
|
||||
def _processModelAnimations(self, node_path):
|
||||
"""处理节点中的动画模型"""
|
||||
try:
|
||||
@ -234,19 +277,38 @@ class MainApp(ShowBase):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# 在 processSceneElements 方法中修改碰撞体创建部分
|
||||
# 修复 processSceneElements 方法中的碰撞体创建
|
||||
def processSceneElements(self, scene):
|
||||
"""处理场景中的各种元素"""
|
||||
try:
|
||||
processed_lights = []
|
||||
loaded_nodes = {}
|
||||
def processNode(nodePath,depth=0):
|
||||
|
||||
def processNode(nodePath, depth=0):
|
||||
loaded_nodes[nodePath.getName()] = nodePath
|
||||
|
||||
# 为模型添加碰撞体 - 修复版本
|
||||
if nodePath.hasTag("is_scene_element") and not nodePath.hasTag("is_gizmo"):
|
||||
# 使用更精确的包围盒
|
||||
from panda3d.core import CollisionNode, CollisionBox
|
||||
bounds = nodePath.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
min_point = bounds.getMin()
|
||||
max_point = bounds.getMax()
|
||||
|
||||
# 创建碰撞节点
|
||||
collision_node = CollisionNode(f'collision_{nodePath.getName()}')
|
||||
collision_node.addSolid(CollisionBox(min_point, max_point))
|
||||
collision_np = nodePath.attachNewNode(collision_node)
|
||||
# 隐藏碰撞体
|
||||
collision_np.hide()
|
||||
|
||||
if nodePath.hasTag("scripts_info"):
|
||||
try:
|
||||
import json
|
||||
scripts_info = json.loads(nodePath.getTag("scripts_info"))
|
||||
self.processScripts(nodePath,scripts_info)
|
||||
self.processScripts(nodePath, scripts_info)
|
||||
except Exception as e:
|
||||
print(f"处理节点 {nodePath.getName()} 的脚本时出错: {str(e)}")
|
||||
|
||||
@ -261,13 +323,10 @@ class MainApp(ShowBase):
|
||||
processed_lights.append(nodePath)
|
||||
|
||||
for child in nodePath.getChildren():
|
||||
processNode(child,depth+1)
|
||||
processNode(child, depth + 1)
|
||||
|
||||
processNode(scene)
|
||||
|
||||
# 处理GUI元素
|
||||
#self.processGUIElements(scene)
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理场景元素时出错: {str(e)}")
|
||||
|
||||
@ -432,7 +491,7 @@ class MainApp(ShowBase):
|
||||
pos=tuple(absolute_position),
|
||||
text=text,
|
||||
size=absolute_scale[0] if absolute_scale and len(absolute_scale) > 0 else 1.0,
|
||||
#command=self.resetWomenModel
|
||||
command=self.playModelAnimation
|
||||
)
|
||||
elif gui_type == "label":
|
||||
new_element = self.createGUILabel(
|
||||
@ -721,45 +780,131 @@ class MainApp(ShowBase):
|
||||
texture.set_loop(True)
|
||||
texture.set_play_rate(1.0)
|
||||
|
||||
def resetWomenModel(self):
|
||||
"""调整 Women_1.glb 模型大小,实现从小到大再到小的完整循环效果"""
|
||||
def playModelAnimation(self):
|
||||
"""播放场景中所有 .glb 模型的动画(仅转换有动画的模型为 Actor)"""
|
||||
try:
|
||||
# 查找 Women_1.glb 模型
|
||||
women_models = self.render.findAllMatches("**/Women_1.glb*")
|
||||
glb_models = self.render.findAllMatches("**/*.glb*")
|
||||
|
||||
if women_models:
|
||||
for model in women_models:
|
||||
# 定义完整的缩放级别序列(从0.5到3.0再回到0.5)
|
||||
scale_levels = [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 2.5, 2.0, 1.5, 1.0, 0.5]
|
||||
# 修复过滤逻辑,确保正确排除碰撞体节点
|
||||
filtered_models = []
|
||||
for model in glb_models:
|
||||
model_name = model.getName().lower()
|
||||
# 排除碰撞体节点
|
||||
if ("collision_" not in model_name and
|
||||
"modelcollision_" not in model_name and
|
||||
not model_name.endswith("_bounds")):
|
||||
filtered_models.append(model)
|
||||
|
||||
# 获取当前缩放值
|
||||
current_scale = model.getScale()
|
||||
if not filtered_models:
|
||||
print("⚠️ 场景中没有找到 .glb 模型")
|
||||
return
|
||||
|
||||
# 查找当前最接近的缩放级别索引
|
||||
current_index = 0
|
||||
min_diff = float('inf')
|
||||
for i, scale in enumerate(scale_levels):
|
||||
diff = abs(current_scale.x - scale)
|
||||
if diff < min_diff:
|
||||
min_diff = diff
|
||||
current_index = i
|
||||
print(f"找到 {len(filtered_models)} 个 glb 模型")
|
||||
|
||||
# 计算下一个缩放级别(循环)
|
||||
next_index = (current_index + 1) % len(scale_levels)
|
||||
next_scale = scale_levels[next_index]
|
||||
self.actors = [] # 存储所有 Actor,避免被垃圾回收
|
||||
|
||||
# 应用新的缩放
|
||||
model.setScale(next_scale)
|
||||
print(f"✓ 调整模型 {model.getName()} 大小: {current_scale.x:.1f} -> {next_scale:.1f}")
|
||||
print(f" 当前索引: {current_index}, 下一个索引: {next_index}")
|
||||
else:
|
||||
print("⚠️ 未找到 Women_1.glb 模型")
|
||||
for model in filtered_models:
|
||||
print(f"正在处理模型: {model.getName()}")
|
||||
|
||||
actor = None
|
||||
|
||||
# 尝试把模型当作Actor加载,判断是否有动画
|
||||
try:
|
||||
# 在创建Actor之前先检查节点是否可能包含动画
|
||||
if not self._isValidAnimationNode(model):
|
||||
print(f"⚠️ {model.getName()} 不是有效的动画节点,跳过")
|
||||
continue
|
||||
|
||||
test_actor = Actor(model)
|
||||
anim_names = test_actor.getAnimNames()
|
||||
except Exception as e:
|
||||
print(f"⚠️ {model.getName()} 无法作为Actor加载: {str(e)}")
|
||||
anim_names = []
|
||||
|
||||
if anim_names: # ✅ 只有有动画才转为Actor
|
||||
if not isinstance(model, Actor):
|
||||
model_parent = model.getParent()
|
||||
model_pos = model.getPos()
|
||||
model_hpr = model.getHpr()
|
||||
model_scale = model.getScale()
|
||||
|
||||
actor = Actor(model)
|
||||
actor.reparentTo(model_parent)
|
||||
actor.setPos(model_pos)
|
||||
actor.setHpr(model_hpr)
|
||||
actor.setScale(model_scale)
|
||||
|
||||
model.detachNode()
|
||||
else:
|
||||
actor = model
|
||||
|
||||
# 播放动画
|
||||
actor.show()
|
||||
self.actors.append(actor)
|
||||
|
||||
print(f"✓ {actor.getName()} 可用动画: {anim_names}")
|
||||
first_anim = anim_names[0]
|
||||
|
||||
actor.stop()
|
||||
actor.setPlayRate(1.0, first_anim)
|
||||
actor.loop(first_anim)
|
||||
print(f"✓ {actor.getName()} 正在播放动画: {first_anim}")
|
||||
|
||||
actor.update()
|
||||
|
||||
else: # 没有动画
|
||||
print(f"⚠️ {model.getName()} 没有动画,不转为Actor")
|
||||
|
||||
except Exception as e:
|
||||
print(f"调整模型大小时出错: {str(e)}")
|
||||
print(f"播放模型动画时出错: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _isValidAnimationNode(self, nodePath):
|
||||
"""检查节点是否可能是有效的动画节点"""
|
||||
# 排除明显不是动画节点的节点
|
||||
name = nodePath.getName().lower()
|
||||
if ("collision_" in name or
|
||||
"modelcollision_" in name or
|
||||
"bound" in name or
|
||||
name.endswith("_bounds")):
|
||||
return False
|
||||
|
||||
# 检查节点是否有网格数据(简单判断)
|
||||
from panda3d.core import GeomNode
|
||||
geom_nodes = nodePath.findAllMatches("**/+GeomNode")
|
||||
if not geom_nodes:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def focusOnWomenModel(self):
|
||||
"""定位并聚焦到Women模型"""
|
||||
try:
|
||||
women_models = self.render.findAllMatches("**/Women_1.glb*")
|
||||
if women_models:
|
||||
model = women_models[0]
|
||||
# 确保模型可见
|
||||
model.show()
|
||||
|
||||
# 将模型放置在原点附近
|
||||
model.setPos(0, 0, 0)
|
||||
model.setScale(1.0)
|
||||
|
||||
# 确保是Actor的话设置动画
|
||||
if isinstance(model, Actor):
|
||||
anim_names = model.getAnimNames()
|
||||
if anim_names:
|
||||
model.loop(anim_names[0])
|
||||
model.setPlayRate(1.0, anim_names[0])
|
||||
print(f"为模型设置动画: {anim_names[0]}")
|
||||
|
||||
print(f"已定位模型: {model.getName()}")
|
||||
else:
|
||||
print("未找到Women模型")
|
||||
except Exception as e:
|
||||
print(f"定位模型时出错: {str(e)}")
|
||||
|
||||
def processScripts(self, element, script_info_list):
|
||||
"""处理元素上挂载的脚本 - 使用新的脚本系统"""
|
||||
try:
|
||||
@ -812,51 +957,92 @@ class MainApp(ShowBase):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def checkDoubleClick(self,nodePath):
|
||||
def checkDoubleClick(self, nodePath):
|
||||
"""检查是否为双击,返回布尔值 - 改进版本"""
|
||||
try:
|
||||
import time
|
||||
current_time = time.time()
|
||||
|
||||
is_double_click = (self._last_clicked_node == nodePath and
|
||||
# 必须是同一节点且在时间阈值内
|
||||
is_double_click = (self._last_clicked_node is not None and
|
||||
self._last_clicked_node == nodePath and
|
||||
nodePath is not None and
|
||||
current_time - self._last_click_time<self._double_click_threshold)
|
||||
current_time - self._last_click_time < self._double_click_threshold)
|
||||
|
||||
if is_double_click:
|
||||
# 双击成功,重置状态
|
||||
self._last_click_time = 0
|
||||
self._last_clicked_node = None
|
||||
print(f"✓ 检测到双击: {nodePath.getName()}")
|
||||
return True
|
||||
else:
|
||||
# 单击,更新状态
|
||||
self._last_click_time = current_time
|
||||
self._last_clicked_node = nodePath
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"双击检测失败:{e}")
|
||||
print(f"双击检测失败: {e}")
|
||||
return False
|
||||
|
||||
def focusCameraOnNode(self,nodePath):
|
||||
def focusCameraOnNode(self, nodePath):
|
||||
"""带动画效果的聚焦到节点方法"""
|
||||
try:
|
||||
if not nodePath or nodePath.isEmpty():
|
||||
print("无效的节点")
|
||||
return
|
||||
bounds = nodePath.getBounds()
|
||||
|
||||
if bounds.isEmpty():
|
||||
center = nodePath.getPos()
|
||||
minPoint = Point3()
|
||||
maxPoint = Point3()
|
||||
|
||||
if not nodePath.calcTightBounds(minPoint, maxPoint,self.render):
|
||||
print("无法计算选中节点的边界框,使用节点为位置作为替代方案")
|
||||
node_pos = nodePath.getPos(self.render)
|
||||
optimal_distance = 10.0
|
||||
current_cam_pos = self.cam.getPos()
|
||||
view_direction = node_pos - current_cam_pos
|
||||
if view_direction.length()<0.001:
|
||||
view_direction = Vec3(5,-5,2)
|
||||
view_direction.normalize()
|
||||
target_cam_pos = node_pos-(view_direction * optimal_distance)
|
||||
|
||||
temp_node = self.render.attachNewNode("temp_lookat_target")
|
||||
temp_node.setPos(node_pos)
|
||||
dummy_cam = self.render.attachNewNode("dummy_camera")
|
||||
dummy_cam.setPos(target_cam_pos)
|
||||
dummy_cam.lookAt(temp_node)
|
||||
target_cam_hpr = Vec3(dummy_cam.getHpr())
|
||||
|
||||
temp_node.removeNode()
|
||||
dummy_cam.removeNode()
|
||||
|
||||
current_cam_pos = Point3(self.cam.getPos())
|
||||
current_cam_hpr = Vec3(self.cam.getHpr())
|
||||
self._startCameraFocusAnimation(current_cam_pos,target_cam_pos,current_cam_hpr,target_cam_hpr)
|
||||
print(f"开始聚焦到节点(使用位置): {nodePath.getName()}")
|
||||
|
||||
return
|
||||
|
||||
center = Point3(
|
||||
(minPoint.x + maxPoint.x)*0.5,
|
||||
(minPoint.y+maxPoint.y)*0.5,
|
||||
(minPoint.z+maxPoint.z)*0.5
|
||||
)
|
||||
|
||||
size = (maxPoint - minPoint).length()
|
||||
if size < 0.01:
|
||||
size = 1.0
|
||||
else:
|
||||
center = bounds.getCenter()
|
||||
size = bounds.getRadius()
|
||||
|
||||
current_cam_pos = self.cam.getPos()
|
||||
current_cam_hpr = self.cam.getHpr()
|
||||
current_cam_pos = Point3(self.cam.getPos())
|
||||
current_cam_hpr = Vec3(self.cam.getHpr())
|
||||
|
||||
view_direction = current_cam_pos - center
|
||||
if view_direction.length()<0.001:
|
||||
if view_direction.length() < 0.001:
|
||||
view_direction = Vec3(5,-5,2)
|
||||
|
||||
view_direction.normalize()
|
||||
|
||||
optimal_distance = max(size*2,3.0)
|
||||
optimal_distance = max(size * 2.5,1.0)
|
||||
|
||||
target_cam_pos = center + (view_direction * optimal_distance)
|
||||
|
||||
@ -871,118 +1057,118 @@ class MainApp(ShowBase):
|
||||
temp_node.removeNode()
|
||||
dummy_cam.removeNode()
|
||||
|
||||
self._startCameraFocusAnimation(current_cam_pos,target_cam_pos,current_cam_hpr,target_cam_hpr)
|
||||
self._startCameraFocusAnimation(current_cam_pos,target_cam_pos,
|
||||
current_cam_hpr,target_cam_hpr)
|
||||
|
||||
print(f"开始聚焦到节点: {nodePath.getName()}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"聚焦到节点失败{e}")
|
||||
print(f"聚焦相机失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _startCameraFocusAnimation(self,start_pos,end_pos,start_hpr,end_hpr):
|
||||
def _startCameraFocusAnimation(self, start_pos, end_pos, start_hpr, end_hpr):
|
||||
"""启动相机聚焦动画 - 改进版本"""
|
||||
try:
|
||||
class CameraFocusData:
|
||||
def __init__(self,start_pos,end_pos,start_hpr,end_hpr):
|
||||
self.start_pos = start_pos
|
||||
self.end_pos = end_pos
|
||||
self.start_hpr = start_hpr
|
||||
self.end_hpr = end_hpr
|
||||
self.elapsed_time = 0
|
||||
self.duration = 0.5
|
||||
def __init__(self, start_pos, end_pos, start_hpr, end_hpr):
|
||||
self.start_pos = Point3(start_pos)
|
||||
self.end_pos = Point3(end_pos)
|
||||
self.start_hpr = Vec3(start_hpr)
|
||||
self.end_hpr = Vec3(end_hpr)
|
||||
self.elapsed_time = 0.0
|
||||
self.duration = 0.5 # 增加动画时间使移动更平滑
|
||||
|
||||
self._camera_focus_data = CameraFocusData(start_pos,end_pos,start_hpr,end_hpr)
|
||||
self._camera_focus_data = CameraFocusData(start_pos, end_pos, start_hpr, end_hpr)
|
||||
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
taskMgr.remove("cameraFocusTask")
|
||||
|
||||
taskMgr.add(self._cameraFocusTask, "cameraFocusTask")
|
||||
except Exception as e:
|
||||
print(f"启动摄像机聚焦动画失败{e}")
|
||||
print(f"开始相机聚焦动画: {start_pos} -> {end_pos}")
|
||||
|
||||
def _normalizeAngle(self,angle):
|
||||
while angle >180:
|
||||
except Exception as e:
|
||||
print(f"相机聚焦动画启动失败: {str(e)}")
|
||||
|
||||
def _normalizeAngle(self, angle):
|
||||
"""规范化角度到-180到180度之间"""
|
||||
while angle > 180:
|
||||
angle -= 360
|
||||
while angle < -180:
|
||||
angle += 360
|
||||
return angle
|
||||
|
||||
def _cameraFocusTask(self,task):
|
||||
def _cameraFocusTask(self, task):
|
||||
"""摄像机聚焦动画任务"""
|
||||
try:
|
||||
if not hasattr(self,'_camera_focus_data'):
|
||||
if not hasattr(self, '_camera_focus_data'):
|
||||
return task.done
|
||||
|
||||
data = self._camera_focus_data
|
||||
from direct.showbase.ShowBaseGlobal import globalClock
|
||||
data.elapsed_time += globalClock.getDt()
|
||||
dt = globalClock.getDt()
|
||||
|
||||
t = min(1.0,data.elapsed_time/data.duration)
|
||||
if dt <= 0:
|
||||
dt = 0.016
|
||||
|
||||
smooth_t = t*t*(3-2*t)
|
||||
data.elapsed_time += dt
|
||||
t = min(1.0, data.elapsed_time / data.duration)
|
||||
|
||||
# 使用平滑插值
|
||||
smooth_t = t * t * (3 - 2 * t)
|
||||
|
||||
# 插值位置和朝向
|
||||
current_pos = data.start_pos + (data.end_pos - data.start_pos) * smooth_t
|
||||
current_hpr = data.start_hpr + (data.end_hpr - data.start_hpr) * smooth_t
|
||||
|
||||
self.cam.setPos(current_pos)
|
||||
|
||||
start_h = self._normalizeAngle(data.start_hpr.x)
|
||||
end_h = self._normalizeAngle(data.end_hpr.x)
|
||||
start_p = self._normalizeAngle(data.start_hpr.y)
|
||||
end_p = self._normalizeAngle(data.end_hpr.y)
|
||||
start_r = self._normalizeAngle(data.start_hpr.z)
|
||||
end_r = self._normalizeAngle(data.end_hpr.z)
|
||||
|
||||
if abs(end_h - start_h)>180:
|
||||
if end_h > start_h:
|
||||
start_h += 360
|
||||
else:
|
||||
end_h += 360
|
||||
|
||||
if abs(end_p - start_p) > 180:
|
||||
if end_p > start_p:
|
||||
start_p += 360
|
||||
else:
|
||||
end_p += 360
|
||||
|
||||
if abs(end_r - start_r)>180:
|
||||
if end_r > start_r:
|
||||
start_r += 360
|
||||
else:
|
||||
end_r += 360
|
||||
|
||||
current_hpr = Vec3(
|
||||
start_h + (end_h - start_h)*smooth_t,
|
||||
start_p + (end_p - start_p)*smooth_t,
|
||||
start_r + (end_r - start_r)*smooth_t
|
||||
)
|
||||
|
||||
current_hpr.x = self._normalizeAngle(current_hpr.x)
|
||||
current_hpr.y = self._normalizeAngle(current_hpr.y)
|
||||
current_hpr.z = self._normalizeAngle(current_hpr.z)
|
||||
|
||||
self.cam.setHpr(current_hpr)
|
||||
|
||||
if t>=1.0:
|
||||
if t >= 1.0:
|
||||
self.cam.setPos(data.end_pos)
|
||||
self.cam.setHpr(data.end_hpr)
|
||||
|
||||
print(f"聚焦完成: 位置 {data.end_pos}, 朝向 {data.end_hpr}")
|
||||
|
||||
if hasattr(self, '_camera_focus_data'):
|
||||
delattr(self, '_camera_focus_data')
|
||||
|
||||
return task.done
|
||||
|
||||
return task.cont
|
||||
|
||||
except Exception as e:
|
||||
print(f"摄像机聚焦动画失败{e}")
|
||||
print(f"摄像机聚焦动画任务失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return task.done
|
||||
|
||||
def setupMouseClickHandler(self):
|
||||
"""设置鼠标点击处理器"""
|
||||
try:
|
||||
# 设置鼠标监听
|
||||
self.accept("mouse1", self.onMouseClick)
|
||||
|
||||
if not hasattr(self,'mouseWatcherNode'):
|
||||
# 启用鼠标观察器
|
||||
if not hasattr(self, 'mouseWatcherNode'):
|
||||
from panda3d.core import MouseWatcher
|
||||
self.mouseWatcherNode = MouseWatcher()
|
||||
|
||||
except Exception as e:
|
||||
print(f"设置鼠标点击处理器失败: {e}")
|
||||
|
||||
def onMouseClick(self):
|
||||
"""处理鼠标左键点击"""
|
||||
try:
|
||||
if not hasattr(self, 'mouseWatcherNode') or not self.mouseWatcherNode.hasMouse():
|
||||
return
|
||||
|
||||
# 获取鼠标位置
|
||||
mouse_pos = self.mouseWatcherNode.getMouse()
|
||||
|
||||
# 创建射线进行点击检测
|
||||
from panda3d.core import CollisionRay, CollisionNode, CollisionHandlerQueue, BitMask32
|
||||
from panda3d.core import GeomNode
|
||||
|
||||
# 创建射线
|
||||
ray = CollisionRay()
|
||||
@ -991,7 +1177,7 @@ class MainApp(ShowBase):
|
||||
# 创建碰撞节点
|
||||
ray_node = CollisionNode('mouseRay')
|
||||
ray_node.addSolid(ray)
|
||||
ray_node.setFromCollideMask(BitMask32.bit(0))
|
||||
ray_node.setFromCollideMask(BitMask32.allOn())
|
||||
|
||||
# 附加到相机
|
||||
ray_np = self.camera.attachNewNode(ray_node)
|
||||
@ -999,43 +1185,73 @@ class MainApp(ShowBase):
|
||||
# 创建碰撞队列
|
||||
handler = CollisionHandlerQueue()
|
||||
|
||||
# 修复语法错误:正确初始化碰撞遍历器
|
||||
if not hasattr(self, 'cTrav') or self.cTrav is None:
|
||||
# 确保碰撞遍历器存在
|
||||
if not hasattr(self, 'cTrav'):
|
||||
self.cTrav = CollisionTraverser()
|
||||
|
||||
self.cTrav.addCollider(ray_np, handler)
|
||||
self.cTrav.traverse(self.render)
|
||||
|
||||
# 检查碰撞结果
|
||||
target_node = None
|
||||
if handler.getNumEntries() > 0:
|
||||
# 按距离排序
|
||||
handler.sortEntries()
|
||||
|
||||
# 获取最近的碰撞节点
|
||||
entry = handler.getEntry(0)
|
||||
clicked_node = entry.getIntoNodePath()
|
||||
# 遍历所有碰撞结果,找到最近的有效节点
|
||||
for i in range(handler.getNumEntries()):
|
||||
entry = handler.getEntry(i)
|
||||
clicked_node = entry.getIntoNodePath()
|
||||
|
||||
# 向上遍历找到可选择的父节点
|
||||
current_node = clicked_node
|
||||
while current_node and not current_node.isEmpty():
|
||||
# 检查节点是否应该被选择
|
||||
if (current_node.hasTag("is_scene_element") or
|
||||
current_node.hasTag("element_type") or
|
||||
current_node.getName() not in ["render", "camera", "ambient_light", "directional_light"]):
|
||||
# 向上遍历找到可选择的父节点
|
||||
current_node = clicked_node
|
||||
found_valid_node = False
|
||||
|
||||
# 检查是否为双击
|
||||
if self.checkDoubleClick(current_node):
|
||||
print(f"双击节点: {current_node.getName()}")
|
||||
self.focusCameraOnNode(current_node)
|
||||
while current_node and not current_node.isEmpty():
|
||||
# 检查节点是否应该被选择
|
||||
if (current_node.hasTag("is_scene_element") and
|
||||
not current_node.hasTag("is_gizmo") and
|
||||
current_node.getName() not in ["render", "camera", "ambient_light",
|
||||
"directional_light", "mouseRay"] and
|
||||
not current_node.getName().startswith("collision_") and
|
||||
"ground" not in current_node.getName().lower()):
|
||||
target_node = current_node
|
||||
found_valid_node = True
|
||||
break
|
||||
else:
|
||||
print(f"单击节点: {current_node.getName()}")
|
||||
|
||||
current_node = current_node.getParent()
|
||||
# 避免无限循环
|
||||
if current_node.getName() == "render":
|
||||
# 如果当前节点是碰撞体,获取其父节点作为目标
|
||||
if current_node.getName().startswith("collision_"):
|
||||
parent = current_node.getParent()
|
||||
if (parent.hasTag("is_scene_element") and
|
||||
not parent.hasTag("is_gizmo") and
|
||||
parent.getName() not in ["render", "camera", "ambient_light",
|
||||
"directional_light"] and
|
||||
"ground" not in parent.getName().lower()):
|
||||
target_node = parent
|
||||
found_valid_node = True
|
||||
break
|
||||
|
||||
current_node = current_node.getParent()
|
||||
if current_node.getName() == "render":
|
||||
break
|
||||
|
||||
if found_valid_node:
|
||||
break
|
||||
|
||||
# 如果找到了目标节点,则进行双击检测
|
||||
if target_node:
|
||||
print(f"找到可选择节点: {target_node.getName()}")
|
||||
print(f"节点位置: {target_node.getPos()}")
|
||||
print(f"节点边界: {target_node.getBounds()}")
|
||||
# 检查是否为双击
|
||||
if self.checkDoubleClick(target_node):
|
||||
print(f"双击节点: {target_node.getName()}")
|
||||
self.focusCameraOnNode(target_node)
|
||||
else:
|
||||
print(f"单击节点: {target_node.getName()}")
|
||||
else:
|
||||
print("未找到有效的目标节点")
|
||||
|
||||
# 清理碰撞器
|
||||
ray_np.removeNode()
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user