递归回调:第一个回调禁用后面的回调
Recursive callbacks: the first callback disables the following callbacks
我正在我的代码中触发光线投射:
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);
光线投射结果由 callback/slot 处理,它以递归方式再次进行光线投射:
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);
}
问题是当callback/slot MySceneClass::handleRayCasterHits
returns时,光线投射器组件将自动禁用,并且无法再执行光线投射测试。那是因为 RunMode
设置为 SingleShot
,如 documentation.
中所述
一种解决方案是将 RunMode
设置为 Continuous
,但这是不可取的,因为它会连续且不必要地进行光线投射。有没有其他我不知道的可能的解决方案?
可能有点老套的解决方法,但您可以设置一个 队列 待测试的光线:
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);
}
...在光线投射器的回调中,您只需将更多光线加入队列即可:
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));
}
@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);
}
我正在我的代码中触发光线投射:
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);
光线投射结果由 callback/slot 处理,它以递归方式再次进行光线投射:
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);
}
问题是当callback/slot MySceneClass::handleRayCasterHits
returns时,光线投射器组件将自动禁用,并且无法再执行光线投射测试。那是因为 RunMode
设置为 SingleShot
,如 documentation.
一种解决方案是将 RunMode
设置为 Continuous
,但这是不可取的,因为它会连续且不必要地进行光线投射。有没有其他我不知道的可能的解决方案?
可能有点老套的解决方法,但您可以设置一个 队列 待测试的光线:
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);
}
...在光线投射器的回调中,您只需将更多光线加入队列即可:
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));
}
@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);
}