信号到插槽的连接:在循环内迭代触发信号 [英] Signal to slot connection: triggering signal iteratively inside a loop

查看:166
本文介绍了信号到插槽的连接:在循环内迭代触发信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 QRayCaster 添加到我的根实体并连接其信号到插槽:

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)
                                );

    }

}


问题

问题在于,在所有测试中,只有triggerRayCaster()内部的触发器循环的最后一次迭代被捕获,并由handleRayCasterHits()内部的插槽记录.


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?

推荐答案

要了解为什么会发生这种情况,您需要了解Qt3D的工作原理:

To understand why this happens you need to understand how Qt3D works:

  1. Qt3D执行线程中的所有内容.渲染,逻辑和其他所有东西都有自己的线程,并且并行执行(除非您告诉它不要这样做).

  1. 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有一个前端(您在代码中使用的内容)和一个后端.前端节点被转换为后端节点.看看渲染器的后端节点,例子.渲染线程收集所有渲染后端节点,并在渲染阶段执行它们.所有其他线程对其后端节点(逻辑,输入等)执行相同的操作.每当前端节点发生更改时,它们都会通知后端节点,以便它们可以相应地修改其内容,或者被删除或创建.

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.

这意味着,您在示例代码中所做的就是快速(因为在微秒内执行了循环)设置了要在射线投射器上投射的射线的方向,但是这不会投射射线还.实际的光线投射发生在处理与您的前端光线投射器节点相对应的后端节点的后端线程执行光线投射时.在for循环执行所需的几微秒内,这永远不会发生. 这就是为什么您需要一个回调函数来获得匹配,而不能简单地投射光线并在下一行代码中获得结果的原因.

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.

解决方案: 您需要做的是从回调函数中投射下一条光线,并在某个位置存储并建立索引,以告诉您何时停止投射新光线,或者您使用间隔为100ms的计时器(对于所有计时器而言,这应该足够了) Qt3D的线程至少要执行一次,因为它可能以30fps的速度运行),从而触发射线投射.

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.

这篇关于信号到插槽的连接:在循环内迭代触发信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆