我正在代码中触发射线投射:
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
返回时,光线投射器组件将自动禁用自身,并且无法执行更多的光线投射测试。如documentation所述,这是因为RunMode
设置为SingleShot
。
一种解决方案是将RunMode
设置为Continuous
,但这是不希望的,因为它会连续且不必要地进行射线投射。碰巧有其他我不知道的可能解决方案吗?
答案 0 :(得分:0)
也许有些棘手的解决方法,但是您可以设置要测试的射线的队列:
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));
}
答案 1 :(得分:0)
@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);
}