2015-07-21 1 views
0

J'utilise ceci pour rendre le texte dans un QGLWidgetQGLWidget rend le texte en profondeur incorrecte

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

La chaîne est rendue à une profondeur de ~ 0,5 (obtenu par glReadPixel()).

Cependant, dans mon cas, il devrait être plus proche de ~ 0.9. Quand je convertis les coords x, y, z en coeurs d'écran avec les matrices actuelles, je trouve aussi un résultat de ~ 0.9.

Pourquoi une telle différence? Cela fait apparaître le texte toujours devant. J'ai créé un projet QT simple en studio visuel pour reproduire le problème. Il dessine un carré vert avec du texte devant et derrière le carré. Les deux textes regardent devant le carré. Et la profondeur du pixel peut être lue en survolant la souris. J'utilise la version 5.5 de Qt conçue pour la plate-forme 64bits.

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 
+0

J'ai également remarqué que la profondeur des pixels de texte augmente à mesure que le texte se rapproche de la caméra. Ce devrait être le contraire. – Octo

+0

Description mise à jour avec un scénario de test. – Octo

+0

Apparemment, il s'agit d'un bug QT connu. Toujours pas résolu. https://bugreports.qt.io/browse/QTBUG-31156 https://bugreports.qt.io/browse/QTBUG-42838 – Octo

Répondre

0

Il pourrait y avoir 3 numéros

1- la profondeur cible est correctement calculée QGLWidget :: renderText() et transmis au paintEngine via setTranslateZ(). Cependant, le vertex shader ne définit pas cette valeur directement dans les coordonnées du vertex clipped. Au lieu de cela, il traduit par cette valeur.

2- le signe de translateZ semble incorrect. Cela expliquerait pourquoi la profondeur des pixels du texte augmente lorsque le texte se rapproche. 3- il semble que les coordonnées clippées [0, 1] sont mappées à la plage [0.5, 1] ​​Cependant, je n'ai vu aucun appel à glDepthRange() dans la source de Qt.

Si nous changeons le code de qglslComplexGeometryPositionOnlyVertexShader dans qglengineshadersource_p.h avec ce qui suit, il résout le problème.

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"; 
+0

Posté cette solution de contournement/correction comme une suggestion aux développeurs QT sur le bugtracker. – Octo

0

J'ai trouvé qu'une bonne solution consiste à convertir le texte en texture. Et puis affichez cette texture dans la scène.

Cela fonctionne bien si le texte est rendu sur une couleur d'arrière-plan solide. QGLWidget ne semble pas écrire dans le canal alpha.