1

I am implementing a custom QOpenGLWidget in Qt6 and have overridden paintGL() and mouseMoveEvent() to render a triangle that follows the movement of the mouse.

However, I notice that the triangle is always lagging a frame or more "behind" the position of the mouse pointer. I can see this more clearly when moving the mouse around quickly, as the gap between the triangle and the mouse pointer is larger. Is there any way to alleviate this latency? The latency is subtle, but it gives the app a sluggish feel.

If it matters, I am using the latest Qt6 community edition installed with the online installer for Debian 11.7 x64 on an Intel XEON E5-2697 with 64GiB memory and an nVidia Quadro P400 graphics card.

Here is my implementation spesifics:

void SpaceViewWidget::mouseEvent(QMouseEvent *event){
    auto buts = event->buttons();
    for(int i = 0; i < 3; ++i){
        auto buttonName = buttonNames[i];
        const bool last = buttonsPressed[i];
        const bool next = buts & buttonName;
        if(last != next){
            buttonsPressed[i] = next;
            if(next){
                buttonsPressedLocation[i] = event->position() + pan;
            }
        }
    }
}


void SpaceViewWidget::mousePressEvent(QMouseEvent *event){
    mouseEvent(event);
}


void SpaceViewWidget::mouseReleaseEvent(QMouseEvent *event){
    mouseEvent(event);
}


void SpaceViewWidget::mouseMoveEvent(QMouseEvent *event){
    // Middle button pressed
    if(buttonsPressed[2]){
        auto deltaPos = buttonsPressedLocation[2] - event->position();
        pan = deltaPos;
        viewDirty = true;
        update();
        qDebug()<<deltaPos;
    }
}


void SpaceViewWidget::updateViewMatrix(){
    if (viewDirty) {
        viewDirty = false;
        auto sz = QSizeF(size());
        auto sz2 = sz / 2;
        modelMat.setToIdentity();
        float sc=static_cast<float>(1<<chunkDepth);
        modelMat.scale(sc, sc, 1.0);
        viewMat.setToIdentity();
        projectionMat.setToIdentity();
        auto frustum = QRectF(-sz2.width(), -sz2.height(), +sz.width(), +sz.height() );
        projectionMat.ortho(frustum);
        auto center= chunks.center();
        viewMat.translate(-center.x()*sc, -center.y()*sc, 0.0);
        viewMat.translate(-pan.x(), -pan.y(), 0.0);
    }
}

void SpaceViewWidget::paintGL(){
    clearBackground();
    updatePolygonMode();
    updateViewMatrix();
    program.bind();
    textureArray.bind();
    vao.bind();
    vbo.bind();
    program.setUniformValue("modelMat", modelMat);
    program.setUniformValue("viewMat", viewMat);
    program.setUniformValue("projectionMat", projectionMat);
    const auto num_quads = chunks.flags.size()*4;
    f->glDrawArrays(GL_TRIANGLES, 0, num_quads);
}

And the vertex shader uses the view matricies as customary:

void main(){
    /*...*/
    gl_Position = 
              projectionMat
            * viewMat
            * modelMat
            * vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

EDIT: Here is a capture made with "peek"

It is captured at 60fps while my native screen refresh rate is 29.97 fps. At first I center the mouse on the corner of the triangle and then I "drag" it around displaying the lagging.

Peek screencapture showing lag between mouse cursor and OpenGL rendering in Qt QOpenGLWidget

Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95
  • You're mouse event handling requests an update which will end up in a paint event added to the event queue and processed after returning from mouse event handling. Hence, some time lag cannot be prevented though it shouldn't be that dramatically. There is in fact a work around: You could ask for the current mouse coordinates in the paint event itself ([QCursor::pos()](https://doc.qt.io/qt-6/qcursor.html#pos)) and update the matrices there. So, the rendering should consider the mouse position at the time the paint event is processed. I doubt that you can be much more in time. – Scheff's Cat Jun 16 '23 at 06:32
  • 2
    Could you provide a demo? May be a snapshot or GIF animation? (I still would consider the other possibility that the processing of mouse move events accumulates some errors.) So, for 3d navigation, I usually remember start coordinates (mouse 2d as well as scene 3d) at mouse press and do all further calculations based on these start coordinates. I came to this habit because just accumulating deltas resulted in a very unsatisfying "user experience" in my 3d view - especially for rotations (orbit navigation). – Scheff's Cat Jun 16 '23 at 06:40
  • Like what Scheff's Cat suggested, this is probably an issue with floating point inaccuracies, not latency. Although you could probably do some computations _once_ at startup and then reuse the results, such as setting the projection matrix. You could also compute `projectionMat * viewMat * modelMat` on the CPU and upload the result as a uniform matrix. – Yun Jun 16 '23 at 08:13
  • @Scheff'sCat: I have updated the post with a recording – Mr. Developerdude Jul 04 '23 at 10:06

0 Answers0