3

Following this answer, I'm doing consecutive ray casts:

m_rayCaster = new Qt3DRender::QRayCaster(m_scene->rootEntity());
m_rayCaster->setRunMode(Qt3DRender::QAbstractRayCaster::SingleShot);
m_scene->rootEntity()->addComponent(m_rayCaster);

I have these slots to handle whether and when next consecutive ray cast test should be done:

QObject::connect(m_rayCaster, &Qt3DRender::QRayCaster::hitsChanged, this, &RayCastHandler::handleRayCasterHits);
QObject::connect(m_rayCaster, &Qt3DCore::QNode::enabledChanged, this, &RayCastHandler::handleRayCasterEnabledChange);
QObject::connect(this, &RayCastHandler::isPreviousTestDoneChanged, this, &RayCastHandler::handleIsPreviousTestDoneChange);
QObject::connect(this, &RayCastHandler::isNextTestRequiredChanged, this, &RayCastHandler::handleIsNextTestRequiredChange);

The slots set the conditions and check them:

void RayCastHandler::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{
    analyzeHits(hits);
    bool required = isNextTestRequired(/* according to m_testCounter, m_testsTotal, ... */);
    emit isNextTestRequiredChanged(required);
    emit isPreviousTestDoneChanged(true);
    return;
}

void RayCastHandler::handleRayCasterEnabledChange(const bool enabled)
{
    m_isRayCasterEnabled = enabled;
    triggerNextTestIfAllConditionsAreTrue();
    return;
}

void RayCastHandler::handleIsPreviousTestDoneChange(const bool done)
{
    m_isPreviousTestDone = done;
    triggerNextTestIfAllConditionsAreTrue();
    return;
}

void RayCastHandler::handleIsNextTestRequiredChange(const bool required)
{
    m_isNextTestRequired = required;
    if (!m_isNextTestRequired)
        emit rayCastResultsChanged(m_collisions);
    triggerNextTestIfAllConditionsAreTrue();
    return;
}

The code which checks if next ray cast test is required:

bool RayCastHandler::isNextTestRequired(int &testCounter, const int &testsTotal)
{
    testCounter++;
    if (testCounter >= testsTotal) {
        return false;
    }
    return true;
}

And finally, the function which checks all the conditions to trigger next ray cast test is:

bool RayCastHandler::triggerNextTestIfAllConditionsAreTrue()
{
    if (m_isPreviousTestDone && m_isNextTestRequired && m_isRayCasterEnabled) {
        triggerTest(/* Will trigger next ray cast test */);
        m_isPreviousTestDone = false;
        m_isNextTestRequired = false;
        m_isRayCasterEnabled = false;
    }
}

The code works fine, but after casting a few consecutive rays, it stops.

By logging to console, I observe that the m_rayCaster looks to be enabled/disabled randomly. I mean sometimes after finishing a ray cast test, it disables itself, and sometimes it enables itself! I wonder if anybody can introduce a reference on Qt3DRender::QRayCaster enabling/disabling logic. I looked at its source code a bit, I wonder which section of source code might help me to figure out.

Megidd
  • 7,089
  • 6
  • 65
  • 142

1 Answers1

1

Just wanted to share my observations:

I simplified the code by keeping only two signal-slot connections:

QObject::connect(m_rayCaster, &Qt3DRender::QRayCaster::hitsChanged, this, &RayCastHandler::handleRayCasterHits);
QObject::connect(m_rayCaster, &Qt3DCore::QNode::enabledChanged, this, &RayCastHandler::handleRayCasterEnabledChange);

One slot analyzes the hits of ray-caster:

void RayCastHandler::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{
    analyzeHits( ... , hits);
    return;
}

The other slot runs the next consecutive ray-cast test, if ray-caster has disabled itself:

void RayCastHandler::handleRayCasterEnabledChange(const bool enabled)
{
    // When the component disables itself, it is ready for the next ray-cast test
    if (!enabled) {
        bool required = isNextTestRequired( ... );
        if (required)
            triggerTest( ... );
        else
            // Send final ray-cast results by a signal, if next test is NOT needed
            emit rayCastResultsChanged( ... );
    }
    return;
}

The above code works as long as I trigger ray-cast tests with a time-delay. Sometimes I have to increase the above delay time to make it work. But at least it works. Although it is painful since it is NOT reliable:

void RayCastHandler::triggerTest( ... )
{
    ...
    // 1 millisecond delay time
    QTimer::singleShot(1, [rayCaster, origin, direction, length](){rayCaster->trigger(origin, direction, length);});

    ...
}

However, if I use no delay time, at some point, the ray caster stops unexpectedly, without sending any signal containing hit results, and ray caster stays enabled forever. Looks like ray-caster gets stuck:

void RayCastHandler::triggerTest( ... )
{
    ...
    // No delay
    rayCaster->trigger(origin, direction, length);

    ...
}
Megidd
  • 7,089
  • 6
  • 65
  • 142