QGLWidget以不正确的深度呈现文本

时间:2015-07-21 19:51:18

标签: qt opengl text depth qglwidget

我用它来渲染QGLWidget中的文本

QGLWidget::renderText(x, y, z, text, font)

字符串的渲染深度为~0.5(通过glReadPixel()获得)。

然而,在我的情况下它应该更接近~0.9。 当我将x,y,z coords转换为与当前矩阵的屏幕坐标时,我也发现〜0.9的结果。

为什么会出现这样的差异?它使文本始终显示在前面。

我在visual studio中创建了一个简单的QT项目来重现这个问题。 它绘制了一个绿色方块,正方形前后有文字。两个文字都看在广场前面。并且可以通过悬停鼠标来读取像素的深度。

我使用为64位平台构建的Qt 5.5版。

MyGLWidget.h

#include <QGLWidget>
#include <QMouseEvent>

class MyGLWidget : public QGLWidget
{
Q_OBJECT

private:
    float _depth;

public:
    MyGLWidget(QWidget * parent = 0);
    virtual ~MyGLWidget();

    virtual void initializeGL();
    virtual void paintGL();

    void mouseMoveEvent(QMouseEvent * event);

signals:
    void depthRead(float);
};

MyGLWidget.cpp

#include "MyGLWidget.h"
#include <gl/GLU.h>
#include <Qfont>

MyGLWidget::MyGLWidget(QWidget * parent) : QGLWidget(parent)
{    
}

MyGLWidget::~MyGLWidget()
{    
}

void MyGLWidget::initializeGL()
{    
}

void MyGLWidget::paintGL()
{
    // set up projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    float width = this->width();
    float height = this->height();
    glViewport(0, 0, width, height);
    gluPerspective(45, width / height, 1, 100);

    // set up model view
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0,0,5,  // eye
              0,0,0,  // look at
              0,1,0); // up

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    // draw a green square
    glColor4f(0,1,0,1);
    glBegin(GL_QUADS);
    glVertex3f(-1,-1,0);
    glVertex3f(1,-1,0);
    glVertex3f(1,1,0);
    glVertex3f(-1,1,0);
    glEnd();

    // render some blue text behind the square
    QFont font;
    font.setPointSize(20);
    glColor4f(0,0,1,1);
    renderText(-2,-0.5,-1, "BEHIND_BEHIND_BEHIND_BEHIND", font);

    // render some red text in front of the square
    glColor4f(1,0,0,1);
    renderText(-2,0.5,+1, "IN_FRONT_IN_FRONT_IN_FRONT_I", font);
}

void MyGLWidget::mouseMoveEvent(QMouseEvent * event)
{
    int x = event->x();

    // flip y for QT origin is top left while OpenGL origin is bottom left
    int y = this->height() - event->y();

    // read pixel depth
    glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &_depth);

    // update ui
    emit depthRead(_depth);
}

rendertexttest.h

#ifndef RENDERTEXTTEST_H
#define RENDERTEXTTEST_H

#include <QtWidgets/QMainWindow>
#include "ui_rendertexttest.h"
#include "MyGLWidget.h"

class RenderTextTest : public QMainWindow
{
    Q_OBJECT

public:
    RenderTextTest(QWidget *parent = 0);
    ~RenderTextTest();

public slots:
    void onDepthRead(float depth);

private:
    Ui::RenderTextTestClass ui;
    MyGLWidget * _glwidget;
};

#endif // RENDERTEXTTEST_H

rendertexttest.cpp

#include "rendertexttest.h"

RenderTextTest::RenderTextTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    _glwidget = new MyGLWidget(this);
    _glwidget->setMouseTracking(true);

    QObject::connect(_glwidget, SIGNAL(depthRead(float)),
                     this, SLOT(onDepthRead(float)));

    ui._mainLayout->addWidget(_glwidget);
}

RenderTextTest::~RenderTextTest()
{

}

void RenderTextTest::onDepthRead(float depth)
{
    ui._lblDepth->setText(QString::number(depth));
}

ui_rendertexttest.h

/********************************************************************************
** Form generated from reading UI file 'rendertexttest.ui'
**
** Created by: Qt User Interface Compiler version 5.3.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_RENDERTEXTTEST_H
#define UI_RENDERTEXTTEST_H

#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_RenderTextTestClass
{
public:
    QWidget *centralWidget;
    QWidget *verticalLayoutWidget;
    QVBoxLayout *_mainLayout;
    QLabel *_lblDepth;

    void setupUi(QMainWindow *RenderTextTestClass)
    {
        if (RenderTextTestClass->objectName().isEmpty())
            RenderTextTestClass->setObjectName(QStringLiteral("RenderTextTestClass"));
        RenderTextTestClass->resize(600, 438);
        centralWidget = new QWidget(RenderTextTestClass);
        centralWidget->setObjectName(QStringLiteral("centralWidget"));
        verticalLayoutWidget = new QWidget(centralWidget);
        verticalLayoutWidget->setObjectName(QStringLiteral("verticalLayoutWidget"));
        verticalLayoutWidget->setGeometry(QRect(9, 9, 581, 381));
        _mainLayout = new QVBoxLayout(verticalLayoutWidget);
        _mainLayout->setSpacing(6);
        _mainLayout->setContentsMargins(11, 11, 11, 11);
        _mainLayout->setObjectName(QStringLiteral("_mainLayout"));
        _mainLayout->setSizeConstraint(QLayout::SetDefaultConstraint);
        _mainLayout->setContentsMargins(0, 0, 0, 0);
        _lblDepth = new QLabel(centralWidget);
        _lblDepth->setObjectName(QStringLiteral("_lblDepth"));
        _lblDepth->setGeometry(QRect(10, 410, 581, 16));
        RenderTextTestClass->setCentralWidget(centralWidget);

        retranslateUi(RenderTextTestClass);

        QMetaObject::connectSlotsByName(RenderTextTestClass);
    } // setupUi

    void retranslateUi(QMainWindow *RenderTextTestClass)
    {
        RenderTextTestClass->setWindowTitle(QApplication::translate("RenderTextTestClass", "RenderTextTest", 0));
        _lblDepth->setText(QApplication::translate("RenderTextTestClass", "Depth:", 0));
    } // retranslateUi

};

namespace Ui {
    class RenderTextTestClass: public Ui_RenderTextTestClass {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_RENDERTEXTTEST_H

2 个答案:

答案 0 :(得分:0)

可能有3个问题

1-目标深度在QGLWidget :: renderText()中正确计算,并通过setTranslateZ()传递给paintEngine。但是,顶点着色器不会直接在顶点剪切坐标中设置此值。相反,它会转换为此值。

2- translateZ的标志似乎不正确。这可以解释为什么当文本靠近时文本像素的深度会增加。

3-似乎剪切的坐标[0,1]被映射到范围[0.5,1]但是我没有在Qt的源中看到对glDepthRange()的任何调用。

如果我们使用以下内容更改qglengineshadersource_p.h中的qglslCo​​mplexGeometryPositionOnlyVertexShader的代码,则可以解决问题。

static const char* const qglslComplexGeometryPositionOnlyVertexShader = "\n\
    uniform highp mat3 matrix; \n\
    uniform highp float translateZ; \n\
    attribute highp vec2 vertexCoordsArray; \n\
    void setPosition(void) \n\
    { \n\
      vec3 v = matrix * vec3(vertexCoordsArray, 1.0); \n\
      v.z = (-translateZ - 0.5f) * 2.0f; \n\
      gl_Position = vec4(v.xyz, 1.0);\n\
    } \n";

答案 1 :(得分:0)

我发现一个很好的解决方法是将文本渲染为纹理。然后在场景中显示该纹理。

如果文本在纯色背景上呈现,则效果很好。 QGLWidget似乎没有写入alpha通道。