递归回调:第一个回调禁用以下回调

时间:2019-02-28 11:22:15

标签: c++ qt qt3d

我正在代码中触发射线投射:

m_rayCaster = new Qt3DRender::QRayCaster(m_rootEntity);
// Connect ray-caster signal to callback/slot
QObject::connect(m_rayCaster, &Qt3DRender::QRayCaster::hitsChanged, this, &MySceneClass::handleRayCasterHits);
// ...
// ...
m_rayCaster->trigger(origin, direction, length);

射线投射器的结果由回调/插槽处理,该操作再次递归进行射线投射:

void MySceneClass::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{
    // ...
    // Handle ray caster hits
    // ...

    // Condition to stop ray casting
    m_counter++;
    if ( m_counter >= m_size )  {
        return;
    }


    // Recursive ray casting: trigger ray casting again:
    m_rayCaster->trigger(origin, direction, length);
}

问题在于,当回调/插槽MySceneClass::handleRayCasterHits返回时,光线投射器组件将自动禁用自身,并且无法执行更多的光线投射测试。如documentation所述,这是因为RunMode设置为SingleShot

一种解决方案是将RunMode设置为Continuous,但这是不希望的,因为它会连续且不必要地进行射线投射。碰巧有其他我不知道的可能解决方案吗?

2 个答案:

答案 0 :(得分:0)

也许有些棘手的解决方法,但是您可以设置要测试的射线的队列

struct Ray {
    QVector3D origin;
    QVector3D direction;
    float length;
};

std::deque<Ray> m_raysEnqueued;

然后,您可以通过将新的光线推入队列来启动光线跟踪:

m_raysEnqueued.push_back({ origin, direction, length });

框架回调中,检查队列并处理光线,直到光线为空:

while (!m_raysEnqueued.empty()) {
    Ray r = m_raysEnqueued.pop_front();
    m_rayCaster->trigger(r.origin, r.direction, r.length);
}

...在raycaster的回调中,您只需排队更多的光线:

void MySceneClass::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{
    // ...
    // Handle ray caster hits
    // ...

    // Recursive ray casting: trigger ray casting again:
    m_raysEnqueued.push_back(Ray(origin, direction, length));
}

答案 1 :(得分:0)

@UKMonkey在评论中提供了link,可以帮助我以这种方式解决问题,但我仍然不确定这是否是解决问题的最佳方式:

void MySceneClass::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{
    // ...
    // Handle ray caster hits
    // ...

    // // Wait 1 milli-second, then suggest doing next possible ray casting
    // // We wait for QRayCaster to be disabled, before doing the next ray casting
    QTimer::singleShot(1, this, &MySceneClass::handleRayCasterFinish);
}

这个新的插槽实际上触发了下一个可能的射线投射:

void MySceneClass::handleRayCasterFinish()
{

    while ( m_rayCaster->isEnabled() ) {
        qDebug() << __func__ << "Wait for ray caster to be disabled by the previous ray casting ... enabled: " << m_rayCaster->isEnabled();
        // Above debug message never gets logged, so I guess waiting for 1 milli-second is already enough
    }

    // Condition to stop ray casting
    m_counter++;
    if ( m_counter >= m_size ) return;

    // ...

    // Now we are sure that ray caster is disabled by previous ray casting test, therefore we can trigger the next ray casting test
    m_rayCaster->trigger(origin, direction, length);
}