Соединение сигнал-слот: итеративный запуск сигнала внутри цикла - PullRequest
0 голосов
/ 27 февраля 2019

Настройка ray-caster

Я добавляю QRayCaster к моей корневой сущности и подключаю его сигнал к слоту:

void MySceneClass::createRootEntity()
{
    // ...
    // Add ray caster to root entity
    m_rayCaster = new Qt3DRender::QRayCaster(m_rootEntity);
    m_rayCaster->setRunMode(Qt3DRender::QAbstractRayCaster::SingleShot);
    m_rootEntity->addComponent(m_rayCaster);

    // Set up signal to slot connection
    QObject::connect(m_rayCaster, &Qt3DRender::QRayCaster::hitsChanged,
                     this,        &MySceneClass::handleRayCasterHits);
    // ...
}

Я регистрирую попадания ray-casterпо слоту:

void MySceneClass::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{

    qDebug() << "Ray casting resulted in hits";

}

Включение заклинателя лучей

Я запускаю заклинатель лучей внутри цикла:

void MyOtherClass::triggerRayCaster()
{

    for (int i = 0; i < 100; ++i) {

        m_mySceneClass->castRay(QVector3D(i, i, 50.0f),       // origin
                                QVector3D(0.0f, 0.0f, -1.0f), // direction
                                -1                            // length (-1 means infinite)
                                );

    }

}

Проблема

Проблема заключается в том, что во всех тестах только последняя итерация цикла триггера внутри triggerRayCaster() захватывается и регистрируется слотом внутри handleRayCasterHits().

Не понимаю, почему.Я что-то упустил?

1 Ответ

0 голосов
/ 27 февраля 2019

Чтобы понять, почему это происходит, вам нужно понять, как работает Qt3D:

  1. Qt3D выполняет все в потоках .Рендеринг, логика и все остальное имеет свой собственный поток и выполняется параллельно (если вы не скажете, чтобы это не делалось).

  2. Qt3D имеет внешний интерфейс (то, что вы используете вваш код) и бэкэнд .Внешние узлы преобразуются в внутренние узлы.Взгляните, например, на внутренние узлы рендерера .Поток рендеринга собирает все узлы рендеринга и выполняет их на этапе рендеринга.Все остальные потоки делают то же самое со своими внутренними узлами (логика, ввод и т. Д.).Всякий раз, когда изменяются интерфейсные узлы, они уведомляют внутренние узлы, чтобы они могли соответствующим образом изменить свое содержимое или удалить или создать.

Это означает, что вы делаете в своем примере кода то, что вы быстро (поскольку циклы for выполняются в течение микросекунд) установите направление луча, который вы хотите наложить на заклинатель лучей, но это еще не приведёт луч .Фактическое приведение лучей происходит, когда внутренний поток, обрабатывающий внутренний узел, соответствующий вашему узлу кастера внешних лучей, выполняет приведение лучей.Это никогда не произойдет в течение нескольких микросекунд, необходимых для выполнения цикла for. Это причина, по которой вам нужна функция обратного вызова для получения попаданий, и вы не можете просто привести луч и получить результаты в следующей строке кода.

Решение: То, что вам нужно сделать, это либо привести следующий луч изнутри вашей функции обратного вызова и сохранить и проиндексировать где-нибудь, что скажет вам, когда прекратить излучать новые лучи, либо использовать таймер с интервалом, скажем, 100 мс (этого должно быть достаточно длявсе потоки Qt3D должны быть выполнены хотя бы один раз, поскольку он, вероятно, работает со скоростью 30 кадров в секунду), что вызывает приведение лучей.

...