You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt3D中实体重叠时如何获取所有被拾取的实体?

解决Qt3D多重叠实体拾取全结果问题

核心思路

别盯着单个QObjectPicker的clicked信号了——这个信号本来就只会触发当前Picker绑定实体的回调。要拿到所有重叠实体的命中结果,得改从全局拾取事件里直接捞所有PickResult集合。

具体实现步骤

1. 确认拾取配置生效

先把QPickingSettings的结果模式和拾取方法配置对,这是基础:

# 假设你有Qt3DWindow实例window
picking_settings = window.renderSettings().pickingSettings()
picking_settings.setPickResultMode(Qt3DRender.QPickingSettings.PickAllPicks)
picking_settings.setPickMethod(Qt3DRender.QPickingSettings.TrianglePicking)  # 按需调整,也可以用BoundingVolumePicking

2. 重写Qt3DWindow的鼠标点击事件

自定义一个窗口子类,通过重写mousePressEvent直接捕获全局拾取结果:

from PySide2.Qt3DExtras import Qt3DWindow
from PySide2.Qt3DRender import QPickEvent
from PySide2.QtWidgets import QInputDialog

class Custom3DWindow(Qt3DWindow):
    def mousePressEvent(self, event):
        # 获取当前鼠标位置的所有拾取结果
        pick_event = self.pick(event.x(), event.y())
        if pick_event and pick_event.hits():
            # 提取所有命中的实体
            hit_entities = [hit.entity() for hit in pick_event.hits() if hit.entity()]
            
            # 根据命中数量分支处理
            if len(hit_entities) == 1:
                hit_entities[0].setSelected(True)
            else:
                # 弹出选择框让用户选目标实体(这里用QInputDialog示例)
                entity_labels = [f"实体ID: {ent.id}" for ent in hit_entities]
                selected_label, ok = QInputDialog.getItem(self, "选择实体", "多个实体被命中,请选择:", entity_labels)
                if ok:
                    selected_idx = entity_labels.index(selected_label)
                    hit_entities[selected_idx].setSelected(True)
        
        # 别忘了调用父类方法,保证其他事件正常流转
        super().mousePressEvent(event)

3. 调整实体的QObjectPicker配置

不需要再给每个实体的QObjectPicker绑定clicked信号了——全局事件已经能拿到所有结果。如果需要保留Picker做hover之类的其他交互,可以留着但不用管clicked信号。

4. 关键细节

  • pick(x, y)方法返回的QPickEvent里,hits()就是所有命中的PickResult列表,前提是你已经开了PickAllPicks模式。
  • 从PickResult的entity()方法能直接拿到对应实体对象,你可以给自己的NodeEntity加id、名称之类的自定义属性,方便用户区分选择。

替代方案:手动发射射线

如果不想重写窗口事件,也可以用QRayCaster手动发射射线获取结果:

from PySide2.Qt3DRender import QRayCaster
from PySide2.QtCore import QPointF, QRectF

# 初始化时给根实体添加射线发射器
ray_caster = Qt3DRender.QRayCaster()
root_entity.addComponent(ray_caster)

# 绑定鼠标点击事件触发射线
def on_mouse_click(event):
    camera = window.camera()
    # 计算鼠标位置对应的射线起点和方向
    ray_origin = camera.unproject(QPointF(event.x(), event.y()), 
                                  QRectF(0, 0, window.width(), window.height()))
    ray_direction = camera.viewVector()
    
    # 设置射线参数并发射
    ray_caster.setOrigin(ray_origin)
    ray_caster.setDirection(ray_direction)
    ray_caster.setLength(1000.0)  # 按需调整射线长度
    ray_caster.trigger()

# 监听射线命中结果变化
def handle_hits(hits):
    if hits:
        hit_entities = [hit.entity() for hit in hits if hit.entity()]
        # 后续选择逻辑和前面一致
ray_caster.hitsChanged.connect(handle_hits)

这种方式更灵活,适合需要手动控制射线发射时机的场景。

内容的提问来源于stack exchange,提问作者PePer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 17:48:16