Рекурсивные обратные вызовы: первый обратный вызов отключает следующие обратные вызовы - PullRequest
0 голосов
/ 28 февраля 2019

Я запускаю приведение лучей в своем коде:

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 компонент ray-caster автоматически отключается, и больше нельзя выполнять тесты приведения лучей.Это потому, что для RunMode установлено значение SingleShot, как указано в документации .

Одним из решений является установка RunMode на Continuous, но это нежелательно, поскольку он делает наложение лучей непрерывно и излишне.Случайно, есть ли другое возможное решение, о котором я не знаю?

Ответы [ 2 ]

0 голосов
/ 03 марта 2019

@ UKMonkey предоставил ссылку на комментарий, который помог мне решить проблему таким образом, я все еще не уверен, является ли это лучшим способом ее решения:

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);
}
0 голосов
/ 28 февраля 2019

Возможно, это немного хакерский обходной путь, но вы можете настроить очередь лучей для проверки:

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));
}
...