使用 glReadPixels 进行颜色拾取可在 Android 上使用偏移量

问题描述 投票:0回答:1
  • Qt 6.6.1
  • Qt 6.7.0 测试版
  • Windows 10

我写了一个简单的例子来说明一个问题。此示例在背景上绘制一个颜色为 (0.2, 0.2, 0.2) 的红色三角形。我实现了

mousePressEvent
方法。当您单击画布时,该示例会将颜色打印到控制台。我在 Windows 10 和 WebAssembly 上测试了这个示例 - 它按预期工作。例如它在 WebAssembly 上的工作原理:

但在 Android 上(两者:通过 USB 电缆连接的真实设备和 Android 模拟器),它可以使用偏移量。所以我在中心画了一个三角形,但看起来我把它画在了右上角。当我触摸三角形时,它会打印 (0.2, 0.2, 0.2) 到控制台,但是当我触摸右上角时,它会像右上角的三角形一样打印 (1, 0, 0)。看起来 glReadPixels 坐标系的起点位于窗口的中心:

    void paintGL() override
    {
        glClearColor(0.2f, 0.2f, 0.2f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT);
        m_program.bind();
        m_vertPosBuffer.bind();
        m_program.setAttributeBuffer(m_aPositionLocation, GL_FLOAT, 0, 2);
        m_program.enableAttributeArray(m_aPositionLocation);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        // qDebug() << glGetError() << "\n";

        if (m_mouseClicked)
        {
            // Read the pixel
            GLubyte pixel[4];
            glReadPixels(m_mouseX, m_mouseY, 1, 1,
                         GL_RGBA, GL_UNSIGNED_BYTE, pixel);
            // qDebug() << glGetError() << "\n";
            qDebug() << pixel[0] / 255.f << pixel[1] / 255.f << pixel[2] / 255.f << "\n";
            qDebug() << m_mouseX << m_mouseY << "\n";
            m_mouseClicked = false;
        }
    }

    void mousePressEvent(QMouseEvent *event) override
    {
        m_mouseX = event->pos().x();
        m_mouseY = height() - event->pos().y() - 1;
        m_mouseClicked = true;
        update();
    }

我不知道这是Qt的bug还是其他什么。我认为 glReadPixels 是一种非常流行的使用“颜色 ID”方法来选取对象的方法,很多人都有同样的问题。也许有人知道如何避免这个问题?我创建了一个错误报告,您可以在其中下载 zip 并尝试我的示例:https://bugreports.qt.io/browse/QTBUG-120648

交叉参考:

android c++ qt opengl-es glreadpixels
1个回答
0
投票

我在此处的评论中找到了解决方案:OS X 上的 OpenGL 支持因高 dpi(Retina)而中断。它适用于 macOS,但也适用于 Android。 Laszlo Agocs 的评论对我有帮助:

您需要根据devicePixelRatio()调整GL位置。如果窗口大小为 N,M 并且 devicePixelRatio() 为 2,则 GL 帧缓冲区、视口的大小均为 2N,2M。尝试将 mouseX 和 mouseY 与 devicePixelRatio() 相乘。

解决方案:

    void mousePressEvent(QMouseEvent *event) override
    {
        m_mouseX = event->pos().x() * devicePixelRatio();
        m_mouseY = (height() - event->pos().y() - 1) * devicePixelRatio();
        m_mouseClicked = true;
        update();
    }

主.cpp

#include <QtGui/QMouseEvent>
#include <QtGui/QOpenGLFunctions>
#include <QtOpenGL/QOpenGLBuffer>
#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtOpenGL/QOpenGLWindow>
#include <QtWidgets/QApplication>

class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
{
    int m_mouseX;
    int m_mouseY;
    bool m_mouseClicked = false;
    QOpenGLBuffer m_vertPosBuffer;
    QOpenGLShaderProgram m_program;

    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(0.2f, 0.2f, 0.2f, 1.f);
        qDebug() << "Device pixel ratio:" << devicePixelRatio();

        QString vertexShaderSource =
            "attribute vec2 aPosition;\n"
            "void main()\n"
            "{\n"
            "    gl_Position = vec4(aPosition, 0.0, 1.0);\n"
            "}\n";

        QString fragmentShaderSource =
            "#ifdef GL_ES\n"
            "precision mediump float;\n"
            "#endif\n"
            "void main()\n"
            "{\n"
            "    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
            "}\n";

        m_program.create();
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex,
                                          vertexShaderSource);
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment,
                                          fragmentShaderSource);
        m_program.link();
        m_program.bind();

        float vertPositions[] = {
            -0.5f, -0.5f,
            0.5f, -0.5f,
            0.f, 0.5f
        };
        m_vertPosBuffer.create();
        m_vertPosBuffer.bind();
        m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));

        m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2);
        m_program.enableAttributeArray("aPosition");
    }

    void paintGL() override
    {
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        if (m_mouseClicked)
        {
            // Read the pixel
            GLubyte pixel[4];
            glReadPixels(m_mouseX, m_mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
            // qDebug() << glGetError() << "\n";
            qDebug() << pixel[0] / 255.f << pixel[1] / 255.f << pixel[2] / 255.f;
            m_mouseClicked = false;
        }
    }

    void mousePressEvent(QMouseEvent *event) override
    {
        m_mouseX = event->pos().x() * devicePixelRatio();
        m_mouseY = (height() - event->pos().y() - 1) * devicePixelRatio();
        m_mouseClicked = true;
        update();
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    OpenGLWindow w;
    w.show();
    return app.exec();
}

选择简单三角形的颜色-qopenglwindow-qt6-cpp.pro

QT += core gui opengl widgets

win32: LIBS += -lopengl32

CONFIG += c++17

SOURCES += \
    main.cpp

TARGET = app
© www.soinside.com 2019 - 2024. All rights reserved.