问题
Setting up ray-caster
I add QRayCaster to my root entity and connect its signal to a slot:
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);
// ...
}
I log ray-caster hits by the slot:
void MySceneClass::handleRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{
qDebug() << "Ray casting resulted in hits";
}
Triggering ray-caster
I trigger ray-caster iteratively inside a loop:
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)
);
}
}
Problem
The problem is, on all the tests, only the last iteration of the trigger-loop inside triggerRayCaster()
is captured and logged by the slot inside handleRayCasterHits()
.
I don't get why. Am I missing something?
回答1:
To understand why this happens you need to understand how Qt3D works:
Qt3D executes everything in threads. Rendering, logic and everything else has its own thread and is executed in parallel (unless you tell it not to do so).
Qt3D has a frontend (what you use in your code) and a backend. Frontend nodes get translated into backend nodes. Have a look at the backend nodes of the renderer, for example. The render thread collects all render backend nodes and executes them during the render phase. All other threads do the same with their backend nodes (logic, input, etc). Whenever the frontend nodes change they notify the backend nodes so they can modify their content accordingly or get deleted or created.
This means, what you do in your example code is that you quickly (because for loops are executed within microseconds) set the direction of the ray you want to cast on the ray caster but this doesn't cast the ray yet. The actual ray casting happens when the backend thread handling the backend node corresponding to your frontend ray caster node performs the ray casting. This can never happen within the few microseconds your for loop needs for executing. This is the reason why you need a callback function to obtain the hits and cannot simply cast a ray and obtain the results in the next line of code.
Solution: What you have to do is to either cast the next ray from within your callback function and store and index somewhere which tells you when to stop casting new rays or you use a timer with an interval of lets say 100ms (which should be enough for all threads of Qt3D to be executed at least once, since it probably runs at 30fps) which triggers the ray casting.
来源:https://stackoverflow.com/questions/54900335/signal-to-slot-connection-triggering-signal-iteratively-inside-a-loop