"""
VR可视化模块

提供VR手柄和交互元素的高级可视化功能：
- 手柄3D模型渲染
- 交互射线显示
- 按钮状态可视化
- 触摸板和扳机反馈
"""

from panda3d.core import (
    NodePath, GeomNode, LineSegs, CardMaker, Geom, GeomVertexData,
    GeomVertexFormat, GeomVertexWriter, GeomTriangles, GeomPoints,
    Vec3, Vec4, Mat4, TransparencyAttrib, RenderState, ColorAttrib,
    InternalName, loadPrcFileData
)
from panda3d.core import Texture, Material, TextureStage

# 启用Assimp支持OBJ文件加载
loadPrcFileData("", "load-file-type p3assimp")


class VRControllerVisualizer:
    """VR手柄可视化器"""

    def __init__(self, controller, render_node):
        """初始化手柄可视化器

        Args:
            controller: VRController实例
            render_node: 渲染节点
        """
        self.controller = controller
        self.render = render_node

        # 可视化节点
        self.visual_node = None
        self.model_node = None
        self.ray_node = None
        self.button_indicator_node = None

        # 射线参数
        self.ray_length = 10.0
        self.ray_color = Vec4(0.9, 0.9, 0.2, 0.8)
        self.ray_hit_color = Vec4(0.2, 0.9, 0.2, 0.8)

        # 按钮指示器参数
        self.button_colors = {
            'normal': Vec4(0.3, 0.3, 0.8, 1.0),
            'left': Vec4(0.2, 0.6, 0.9, 1.0),
            'right': Vec4(0.9, 0.3, 0.3, 1.0),
            'trigger': Vec4(0.9, 0.6, 0.2, 1.0),
            'grip': Vec4(0.6, 0.9, 0.3, 1.0),
            'menu': Vec4(0.9, 0.2, 0.9, 1.0),
            'trackpad': Vec4(0.2, 0.9, 0.9, 1.0)
        }

        self._create_visual_components()

    def _create_visual_components(self):
        """创建可视化组件"""
        if not self.controller.anchor_node:
            return

        # 创建主可视化节点
        self.visual_node = self.controller.anchor_node.attachNewNode(f'{self.controller.name}_visual')

        # 创建手柄模型
        self._create_controller_model()

        # 创建交互射线
        self._create_interaction_ray()

        # 暂时注释按钮指示器功能，避免额外几何体造成悬空零件
        # self._create_button_indicators()

    def _create_controller_model(self):
        """创建手柄3D模型"""
        if not self.visual_node:
            return

        # 创建模型节点
        self.model_node = self.visual_node.attachNewNode(f'{self.controller.name}_model')

        # 尝试加载SteamVR官方模型
        steamvr_model = self._load_steamvr_model()

        if steamvr_model:
            # 使用SteamVR官方模型
            steamvr_model.reparentTo(self.model_node)

            # 应用SteamVR配置中的正确旋转值，绕Y轴（俯仰轴）旋转90度
            # body组件的rotate_xyz: [5.037,0.0,0.0]，再加上绕Y轴旋转90度
            # 右手正确，左手需要反向
            if self.controller.name == 'left':
                # 左手控制器：绕Y轴俯仰+90度（修正反向）
                steamvr_model.setHpr(0, 5.037 + 90, 0)
            else:
                # 右手控制器：绕Y轴俯仰+90度（保持不变）
                steamvr_model.setHpr(0, 5.037 + 90, 0)

            # 设置合适的缩放值
            steamvr_model.setScale(1.0)

            # 打印实际应用的旋转值
            if self.controller.name == 'left':
                print(f"🔧 {self.controller.name}手柄：缩放: 1.0，旋转: (0, {5.037 + 90}, 0) [Y轴俯仰+90度]")
            else:
                print(f"🔧 {self.controller.name}手柄：缩放: 1.0，旋转: (0, {5.037 + 90}, 0) [Y轴俯仰+90度]")

            # 修复纯黑色问题：重新设置材质属性
            self._fix_model_material(steamvr_model)

            # 暂时注释身份标记功能，避免额外几何体造成悬空零件
            # self._apply_controller_identity_marker(steamvr_model)

            # 根据渲染模式设置渲染属性
            self._apply_render_mode_settings(steamvr_model)

            print(f"✅ {self.controller.name}手柄已加载SteamVR官方模型（缩放: 1.0，实体渲染模式）")
        else:
            # 降级到改进的程序化模型
            self._create_fallback_model()
            print(f"⚠️ {self.controller.name}手柄使用程序化模型（未找到SteamVR模型）")

    def _load_steamvr_model(self):
        """加载SteamVR官方手柄模型"""
        import os
        from panda3d.core import Filename, Texture, TextureStage

        # SteamVR模型基础路径
        steamvr_base_paths = [
            "/home/hello/.local/share/Steam/steamapps/common/SteamVR/resources/rendermodels/vr_controller_vive_1_5",
            "/home/hello/.steam/steam/steamapps/common/SteamVR/resources/rendermodels/vr_controller_vive_1_5",
            "~/.local/share/Steam/steamapps/common/SteamVR/resources/rendermodels/vr_controller_vive_1_5"
        ]

        for base_path in steamvr_base_paths:
            expanded_base_path = os.path.expanduser(base_path)
            if os.path.exists(expanded_base_path):
                print(f"🔍 找到SteamVR模型目录: {expanded_base_path}")

                # 不再添加目录到搜索路径，避免自动加载多余组件
                # from panda3d.core import getModelPath
                # getModelPath().appendDirectory(expanded_base_path)

                # 尝试加载不同的模型文件，按优先级排序
                model_files = [
                    ("body.obj", "手柄主体"),          # 最重要的部分
                    ("vr_controller_vive_1_5.obj", "完整手柄模型"),  # 组合模型
                ]

                for model_file, description in model_files:
                    model_path = os.path.join(expanded_base_path, model_file)
                    if os.path.exists(model_path):
                        try:
                            print(f"🎮 尝试加载{description}: {model_file}")

                            # 加载主模型
                            model = loader.loadModel(Filename.fromOsSpecific(model_path))
                            if model:
                                # 先应用纹理，再修复材质（保持纹理效果）
                                self._apply_steamvr_textures(model, expanded_base_path)
                                print(f"✅ 成功加载{description}")
                                return model
                            else:
                                print(f"⚠️ 模型文件存在但加载失败: {model_file}")

                        except Exception as e:
                            print(f"❌ 加载{description}失败: {e}")
                            continue

                # 不再尝试组合加载多个部件，避免悬空零件问题
                print("⚠️ 单个模型文件加载失败，跳过组合加载以避免悬空零件")
                break

        print("❌ 未找到任何SteamVR模型目录")
        return None

    def _fix_model_material(self, model):
        """修复模型材质，使用RenderPipeline兼容的新Material API"""
        from panda3d.core import Material, Vec4

        # 检查模型是否有纹理
        has_texture = model.hasTexture()

        # 创建新的材质，使用RenderPipeline兼容的API
        material = Material()

        if has_texture:
            # 有纹理时，设置白色基础颜色让纹理完全显示
            material.setBaseColor(Vec4(1.0, 1.0, 1.0, 1.0))  # 白色让纹理完全显示
            material.setRoughness(0.4)        # 中等粗糙度
            material.setMetallic(0.3)         # 轻度金属感
            material.setRefractiveIndex(1.5)  # 标准折射率
            print(f"🎨 {self.controller.name}手柄：已设置材质（纹理+PBR）")
        else:
            # 无纹理时，设置手柄颜色
            material.setBaseColor(Vec4(0.7, 0.7, 0.8, 1.0))  # 略偏蓝的灰色
            material.setRoughness(0.5)        # 中等粗糙度
            material.setMetallic(0.2)         # 轻度金属感
            material.setRefractiveIndex(1.5)  # 标准折射率
            print(f"🎨 {self.controller.name}手柄：已设置材质（颜色+PBR）")

        # 应用材质到模型，使用优先级1确保覆盖默认材质
        model.setMaterial(material, 1)

        # 确保模型能正确渲染（双面渲染是NodePath的方法）
        model.setTwoSided(False)

        print(f"🔧 {self.controller.name}手柄：已使用RenderPipeline兼容的Material API")

    def _apply_controller_identity_marker(self, model):
        """为控制器添加身份标记，区分左右手"""
        from panda3d.core import RenderModeAttrib

        # 创建一个小的标识几何体
        marker_geom = self._create_box_geometry(0.005, 0.005, 0.02)
        marker_node = model.attachNewNode(marker_geom)

        # 根据左右手设置不同位置和颜色（现在都是Y轴+90度俯仰）
        if self.controller.name == 'left':
            # 左手控制器：左侧标记
            marker_node.setPos(-0.03, 0.05, 0.02)
            marker_node.setColor(0.2, 0.4, 1.0, 1.0)  # 蓝色
            print(f"🔵 {self.controller.name}手柄已添加蓝色身份标记")
        else:
            # 右手控制器：右侧标记
            marker_node.setPos(0.03, 0.05, 0.02)
            marker_node.setColor(1.0, 0.2, 0.2, 1.0)  # 红色
            print(f"🔴 {self.controller.name}手柄已添加红色身份标记")

        # 让标记发光以便更容易看到
        marker_node.setLightOff()  # 不受光照影响，保持明亮

        # 添加轻微的色彩调整（非常微弱，不影响主要纹理）
        if self.controller.name == 'left':
            model.setColorScale(0.98, 0.98, 1.02, 1.0)  # 极轻微的蓝色调
        else:
            model.setColorScale(1.02, 0.98, 0.98, 1.0)  # 极轻微的红色调


    def _apply_steamvr_textures(self, model, base_path):
        """为SteamVR模型应用纹理"""
        import os
        from panda3d.core import Texture, TextureStage

        # SteamVR纹理文件
        texture_files = {
            'diffuse': 'onepointfive_texture.png',
            'specular': 'onepointfive_spec.png'
        }

        textures_applied = 0

        for texture_type, texture_file in texture_files.items():
            texture_path = os.path.join(base_path, texture_file)
            if os.path.exists(texture_path):
                try:
                    texture = loader.loadTexture(texture_path)
                    if texture:
                        # 确保纹理能正确加载
                        texture.setWrapU(Texture.WMClamp)
                        texture.setWrapV(Texture.WMClamp)
                        texture.setMinfilter(Texture.FTLinearMipmapLinear)
                        texture.setMagfilter(Texture.FTLinear)

                        if texture_type == 'diffuse':
                            # 应用主要漫反射纹理
                            model.setTexture(texture)
                            print(f"✅ 应用了主纹理: {texture_file}")
                            textures_applied += 1
                        elif texture_type == 'specular':
                            # 应用高光纹理
                            ts = TextureStage('specular')
                            ts.setMode(TextureStage.MModulate)
                            model.setTexture(ts, texture)
                            print(f"✅ 应用了高光纹理: {texture_file}")
                            textures_applied += 1
                except Exception as e:
                    print(f"⚠️ 应用纹理失败 {texture_file}: {e}")

        if textures_applied == 0:
            print(f"⚠️ {self.controller.name}手柄未能加载任何纹理，将使用材质颜色")
        else:
            print(f"🎨 {self.controller.name}手柄成功应用了 {textures_applied} 个纹理")

    def _load_combined_steamvr_model(self, base_path):
        """尝试组合加载多个SteamVR模型部件"""
        import os
        from panda3d.core import NodePath

        # 重要的模型部件
        important_components = [
            "body.obj",
            "trigger.obj",
            "trackpad.obj",
            "l_grip.obj" if self.controller.name == 'left' else "r_grip.obj"
        ]

        combined_model = NodePath("combined_controller")
        has_components = False

        for component in important_components:
            component_path = os.path.join(base_path, component)
            if os.path.exists(component_path):
                try:
                    part = loader.loadModel(component_path)
                    if part:
                        part.reparentTo(combined_model)
                        has_components = True
                        print(f"✅ 加载了部件: {component}")
                except Exception as e:
                    print(f"⚠️ 加载部件失败 {component}: {e}")

        if has_components:
            self._apply_steamvr_textures(combined_model, base_path)
            return combined_model

        return None

    def _create_fallback_model(self):
        """创建改进的程序化手柄模型作为后备方案"""
        # 主体（长条形状）
        main_body = self._create_box_geometry(0.025, 0.15, 0.04)
        main_node = self.model_node.attachNewNode(main_body)

        # 根据左右手设置不同颜色
        if self.controller.name == 'left':
            color = self.button_colors['left']
        else:
            color = self.button_colors['right']

        main_node.setColor(color)

        # 启用光照响应
        from panda3d.core import RenderState, MaterialAttrib, Material
        material = Material()
        material.setShininess(32)
        material.setAmbient((0.2, 0.2, 0.2, 1))
        material.setDiffuse(color)
        material.setSpecular((0.5, 0.5, 0.5, 1))
        main_node.setMaterial(material)

        # 扳机区域（小突起）
        trigger = self._create_box_geometry(0.015, 0.03, 0.02)
        trigger_node = self.model_node.attachNewNode(trigger)
        trigger_node.setPos(0, -0.08, 0.03)
        trigger_node.setColor(self.button_colors['trigger'])
        trigger_node.setMaterial(material)

        # 握把区域
        grip = self._create_box_geometry(0.02, 0.06, 0.03)
        grip_node = self.model_node.attachNewNode(grip)
        grip_node.setPos(0, 0.05, -0.03)
        grip_node.setColor(self.button_colors['grip'])
        grip_node.setMaterial(material)

        # 触摸板区域（圆盘）
        trackpad = self._create_disc_geometry(0.015, 0.005)
        trackpad_node = self.model_node.attachNewNode(trackpad)
        trackpad_node.setPos(0, -0.02, 0.04)
        trackpad_node.setColor(self.button_colors['trackpad'])
        trackpad_node.setMaterial(material)

        # 应用渲染模式设置
        self._apply_render_mode_settings(self.model_node)

    def _create_box_geometry(self, width, length, height):
        """创建立方体几何体"""
        # 创建顶点格式
        format = GeomVertexFormat.getV3n3()
        vdata = GeomVertexData('box', format, Geom.UHStatic)

        vertex = GeomVertexWriter(vdata, 'vertex')
        normal = GeomVertexWriter(vdata, 'normal')

        # 定义立方体的8个顶点
        vertices = [
            Vec3(-width/2, -length/2, -height/2),
            Vec3( width/2, -length/2, -height/2),
            Vec3( width/2,  length/2, -height/2),
            Vec3(-width/2,  length/2, -height/2),
            Vec3(-width/2, -length/2,  height/2),
            Vec3( width/2, -length/2,  height/2),
            Vec3( width/2,  length/2,  height/2),
            Vec3(-width/2,  length/2,  height/2)
        ]

        # 立方体的6个面，每个面4个顶点
        faces = [
            # 底面 (z = -height/2)
            [0, 1, 2, 3, Vec3(0, 0, -1)],
            # 顶面 (z = height/2)
            [7, 6, 5, 4, Vec3(0, 0, 1)],
            # 前面 (y = -length/2)
            [4, 5, 1, 0, Vec3(0, -1, 0)],
            # 后面 (y = length/2)
            [3, 2, 6, 7, Vec3(0, 1, 0)],
            # 左面 (x = -width/2)
            [0, 3, 7, 4, Vec3(-1, 0, 0)],
            # 右面 (x = width/2)
            [5, 6, 2, 1, Vec3(1, 0, 0)]
        ]

        # 添加顶点和法线
        for face in faces:
            for i in range(4):
                vertex.addData3(vertices[face[i]])
                normal.addData3(face[4])  # 法线向量

        # 创建几何体
        geom = Geom(vdata)

        # 为每个面创建三角形
        for face_idx in range(6):
            base_idx = face_idx * 4
            prim = GeomTriangles(Geom.UHStatic)
            # 第一个三角形
            prim.addVertices(base_idx, base_idx + 1, base_idx + 2)
            # 第二个三角形
            prim.addVertices(base_idx, base_idx + 2, base_idx + 3)
            geom.addPrimitive(prim)

        # 创建几何体节点
        geom_node = GeomNode('box')
        geom_node.addGeom(geom)

        return geom_node

    def _create_disc_geometry(self, radius, thickness):
        """创建圆盘几何体（用于触摸板）"""
        format = GeomVertexFormat.getV3n3()
        vdata = GeomVertexData('disc', format, Geom.UHStatic)

        vertex = GeomVertexWriter(vdata, 'vertex')
        normal = GeomVertexWriter(vdata, 'normal')

        # 创建圆盘顶点
        segments = 16
        import math

        # 中心点
        vertex.addData3(0, 0, thickness/2)
        normal.addData3(0, 0, 1)

        # 圆周点
        for i in range(segments):
            angle = 2 * math.pi * i / segments
            x = radius * math.cos(angle)
            y = radius * math.sin(angle)

            vertex.addData3(x, y, thickness/2)
            normal.addData3(0, 0, 1)

        # 创建几何体
        geom = Geom(vdata)
        prim = GeomTriangles(Geom.UHStatic)

        # 创建扇形三角形
        for i in range(segments):
            next_i = (i + 1) % segments
            prim.addVertices(0, i + 1, next_i + 1)

        geom.addPrimitive(prim)

        # 创建几何体节点
        geom_node = GeomNode('disc')
        geom_node.addGeom(geom)

        return geom_node

    def _create_interaction_ray(self):
        """创建交互射线"""
        if not self.visual_node:
            return

        # 创建射线几何
        line_segs = LineSegs()
        line_segs.setThickness(3)
        line_segs.setColor(self.ray_color)

        # 射线主体
        line_segs.moveTo(0, 0, 0)
        line_segs.drawTo(0, self.ray_length, 0)

        # 射线端点（小球）
        end_point = self._create_sphere_geometry(0.02)

        # 创建射线节点
        geom_node = line_segs.create()
        self.ray_node = self.visual_node.attachNewNode(geom_node)

        # 添加端点球
        end_node = self.ray_node.attachNewNode(end_point)
        end_node.setPos(0, self.ray_length, 0)
        end_node.setColor(self.ray_color)

        # 设置透明度
        self.ray_node.setTransparency(TransparencyAttrib.MAlpha)

        # 使用RenderPipeline兼容的Material API设置射线材质
        from panda3d.core import Material, Vec4
        ray_material = Material()
        ray_material.setBaseColor(Vec4(self.ray_color.x, self.ray_color.y, self.ray_color.z, self.ray_color.w))
        ray_material.setRoughness(0.1)        # 光滑射线
        ray_material.setMetallic(0.0)         # 非金属
        ray_material.setRefractiveIndex(1.5)  # 标准折射率

        # 为射线应用材质
        self.ray_node.setMaterial(ray_material, 1)
        self.ray_node.setTwoSided(False)

        # 为端点球设置相同的材质
        end_material = Material()
        end_material.setBaseColor(Vec4(self.ray_color.x, self.ray_color.y, self.ray_color.z, self.ray_color.w))
        end_material.setRoughness(0.2)        # 略粗糙
        end_material.setMetallic(0.0)         # 非金属
        end_material.setRefractiveIndex(1.5)  # 标准折射率

        # 为端点球应用材质
        end_node.setMaterial(end_material, 1)
        end_node.setTwoSided(False)

        # 默认隐藏射线
        self.ray_node.hide()

        print(f"✓ {self.controller.name}手柄交互射线已创建（含PBR支持）")

    def _create_sphere_geometry(self, radius):
        """创建球体几何体"""
        # 简单的立方体作为球体替代
        return self._create_box_geometry(radius, radius, radius)

    def _create_button_indicators(self):
        """创建按钮状态指示器"""
        if not self.visual_node:
            return

        # 创建按钮指示器容器
        self.button_indicator_node = self.visual_node.attachNewNode(f'{self.controller.name}_indicators')

        # 扳机指示器
        trigger_indicator = self._create_box_geometry(0.005, 0.01, 0.005)
        self.trigger_indicator = self.button_indicator_node.attachNewNode(trigger_indicator)
        self.trigger_indicator.setPos(0.02, -0.08, 0.03)
        self.trigger_indicator.setColor(0.2, 0.2, 0.2, 1.0)

        # 握把指示器
        grip_indicator = self._create_box_geometry(0.005, 0.02, 0.005)
        self.grip_indicator = self.button_indicator_node.attachNewNode(grip_indicator)
        self.grip_indicator.setPos(-0.02, 0.05, -0.03)
        self.grip_indicator.setColor(0.2, 0.2, 0.2, 1.0)

        # 触摸板指示器
        trackpad_indicator = self._create_disc_geometry(0.003, 0.002)
        self.trackpad_indicator = self.button_indicator_node.attachNewNode(trackpad_indicator)
        self.trackpad_indicator.setPos(0, -0.02, 0.045)
        self.trackpad_indicator.setColor(0.2, 0.2, 0.2, 1.0)

        # 为所有按钮指示器设置RenderPipeline兼容的材质
        from panda3d.core import Material, Vec4
        indicator_material = Material()
        indicator_material.setBaseColor(Vec4(0.2, 0.2, 0.2, 1.0))  # 深灰色
        indicator_material.setRoughness(0.8)          # 比较粗糙的表面
        indicator_material.setMetallic(0.1)           # 轻微金属感
        indicator_material.setRefractiveIndex(1.5)    # 标准折射率

        # 为所有指示器应用材质
        for indicator in [self.trigger_indicator, self.grip_indicator, self.trackpad_indicator]:
            indicator.setMaterial(indicator_material, 1)
            indicator.setTwoSided(False)

        print(f"✓ {self.controller.name}手柄按钮指示器已创建")

    def update(self):
        """更新可视化状态"""
        if not self.controller.is_connected:
            self.hide()
            return

        self.show()

        # 更新按钮指示器状态
        self._update_button_indicators()

        # 更新射线显示状态
        self._update_ray_display()

    def _update_button_indicators(self):
        """更新按钮指示器状态"""
        if not hasattr(self, 'trigger_indicator'):
            return

        # 扳机指示器
        if self.controller.is_trigger_pressed():
            self.trigger_indicator.setColor(self.button_colors['trigger'])
            # 根据扳机值调整位置
            trigger_offset = self.controller.trigger_value * 0.01
            self.trigger_indicator.setPos(0.02, -0.08 + trigger_offset, 0.03)
        else:
            self.trigger_indicator.setColor(0.2, 0.2, 0.2, 1.0)
            self.trigger_indicator.setPos(0.02, -0.08, 0.03)

        # 握把指示器
        if self.controller.is_grip_pressed():
            self.grip_indicator.setColor(self.button_colors['grip'])
        else:
            self.grip_indicator.setColor(0.2, 0.2, 0.2, 1.0)

        # 触摸板指示器
        if self.controller.touchpad_touched:
            self.trackpad_indicator.setColor(self.button_colors['trackpad'])
            # 根据触摸位置调整指示器位置
            if hasattr(self.controller, 'touchpad_pos'):
                offset_x = self.controller.touchpad_pos.x * 0.01
                offset_y = self.controller.touchpad_pos.y * 0.01
                self.trackpad_indicator.setPos(offset_x, -0.02 + offset_y, 0.045)
        else:
            self.trackpad_indicator.setColor(0.2, 0.2, 0.2, 1.0)
            self.trackpad_indicator.setPos(0, -0.02, 0.045)

    def _update_ray_display(self):
        """更新射线显示"""
        if not self.ray_node:
            return

        # 根据交互状态显示/隐藏射线
        # 这里可以添加更复杂的逻辑，比如只在指向对象时显示
        show_ray = (self.controller.is_trigger_pressed(threshold=0.1) or
                   self.controller.touchpad_touched)

        if show_ray:
            self.show_ray()
        else:
            self.hide_ray()

    def show(self):
        """显示手柄可视化"""
        if self.visual_node:
            self.visual_node.show()

    def hide(self):
        """隐藏手柄可视化"""
        if self.visual_node:
            self.visual_node.hide()

    def show_ray(self):
        """显示交互射线"""
        if self.ray_node:
            self.ray_node.show()

    def hide_ray(self):
        """隐藏交互射线"""
        if self.ray_node:
            self.ray_node.hide()

    def set_ray_color(self, color):
        """设置射线颜色"""
        if self.ray_node:
            self.ray_node.setColor(color)

            # 更新射线材质的baseColor
            from panda3d.core import Material, Vec4
            if isinstance(color, (list, tuple)) and len(color) >= 3:
                alpha = color[3] if len(color) > 3 else 0.8
                ray_color = Vec4(color[0], color[1], color[2], alpha)
            elif isinstance(color, Vec4):
                ray_color = color
            else:
                ray_color = Vec4(0.9, 0.9, 0.2, 0.8)  # 默认黄色

            # 更新射线材质
            ray_material = Material()
            ray_material.setBaseColor(ray_color)
            ray_material.setRoughness(0.1)
            ray_material.setMetallic(0.0)
            ray_material.setRefractiveIndex(1.5)
            self.ray_node.setMaterial(ray_material, 1)

    def set_ray_length(self, length):
        """设置射线长度"""
        self.ray_length = length
        # 重新创建射线（简单的实现）
        if self.ray_node:
            self.ray_node.removeNode()
            self._create_interaction_ray()

    def _apply_render_mode_settings(self, model_node):
        """根据当前渲染模式应用渲染设置

        Args:
            model_node: 手柄模型节点
        """
        if not model_node:
            return

        # 检测是否启用RenderPipeline模式
        is_render_pipeline = False
        try:
            # 通过VR管理器获取渲染模式
            vr_manager = self.controller.vr_manager
            if hasattr(vr_manager, 'vr_render_mode'):
                from core.vr import VRRenderMode
                is_render_pipeline = (vr_manager.vr_render_mode == VRRenderMode.RENDER_PIPELINE and
                                     vr_manager.render_pipeline_enabled)
        except Exception as e:
            print(f"⚠️ 检测渲染模式失败: {e}")

        if is_render_pipeline:
            # RenderPipeline模式：使用正常深度测试,添加着色器标签
            print(f"🎨 {self.controller.name}手柄：应用RenderPipeline渲染模式")

            # 设置着色器标签,使模型通过RenderPipeline的GBuffer渲染
            model_node.setTag("RenderPipeline", "1")

            # 使用正常的深度测试和深度写入
            model_node.setDepthTest(True)
            model_node.setDepthWrite(True)

            # 设置合适的渲染bin(transparent bin用于透明度支持)
            # 使用默认的opaque bin确保正常渲染
            model_node.clearBin()

            # 递归设置所有子节点
            for child in model_node.findAllMatches("**"):
                child.setTag("RenderPipeline", "1")
                child.setDepthTest(True)
                child.setDepthWrite(True)
                child.clearBin()

            print(f"✅ {self.controller.name}手柄已配置RenderPipeline渲染")
        else:
            # 普通模式：使用always-on-top设置
            print(f"🎨 {self.controller.name}手柄：应用普通渲染模式(always-on-top)")
            self._set_always_on_top(model_node)

    def _set_always_on_top(self, model_node):
        """设置手柄模型始终显示在上层，不被其他物体遮挡（仅普通渲染模式）"""
        if not model_node:
            return

        from panda3d.core import RenderState

        # 设置为固定渲染bin，优先级设为较高值（1000）
        # fixed bin中的对象按sort值从小到大渲染，越大越后渲染（越在上层）
        model_node.setBin("fixed", 1000)

        # 禁用深度测试和深度写入，确保始终可见
        model_node.setDepthTest(False)
        model_node.setDepthWrite(False)

        # 递归设置所有子节点的渲染属性
        for child in model_node.findAllMatches("**"):
            child.setBin("fixed", 1000)
            child.setDepthTest(False)
            child.setDepthWrite(False)

        print(f"🔝 {self.controller.name}手柄已设置为始终显示在上层")

    def cleanup(self):
        """清理资源"""
        # 清理射线节点
        if hasattr(self, 'ray_node') and self.ray_node:
            self.ray_node.removeNode()
            self.ray_node = None
            print(f"🧹 {self.controller.name}手柄射线已清理")

        # 清理模型节点
        if hasattr(self, 'model_node') and self.model_node:
            self.model_node.removeNode()
            self.model_node = None
            print(f"🧹 {self.controller.name}手柄模型已清理")

        # 清理主可视化节点
        if self.visual_node:
            self.visual_node.removeNode()
            self.visual_node = None
            print(f"🧹 {self.controller.name}手柄主节点已清理")

        print(f"✅ {self.controller.name}手柄可视化已彻底清理")