2015-01-21 12 views
10

Desidero disegnare un singolo elemento nella scena QtQuick utilizzando chiamate OpenGL non elaborate. Ho deciso di adottare l'approccio suggerito in this question.Problema con il disegno di un oggetto Qml con chiamate OpenGL non elaborate

Ho creato una voce di rapida Qt derivanti da QQuickFramebufferObject ed esposti a QML come Renderer: (il codice si basa su esempio Qt: Scene Graph - Rendering FBOs) File

class FboInSGRenderer : public QQuickFramebufferObject { 
    Q_OBJECT 
public: 
    Renderer *createRenderer() const; 
}; 

fonte:

class LogoInFboRenderer : public QQuickFramebufferObject::Renderer { 
    public: 
     LogoInFboRenderer() { } 

     void render() { 
      int width = 1, height = 1; 
      glEnable(GL_BLEND); 
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
      glColor4f(0.0, 1.0, 0.0, 0.8); 
      glBegin(GL_QUADS); 
      glVertex2f(0, 0); 
      glVertex2f(width, 0); 
      glVertex2f(width, height); 
      glVertex2f(0, height); 
      glEnd(); 

      glLineWidth(2.5); 
      glColor4f(0.0, 0.0, 0.0, 1.0); 
      glBegin(GL_LINES); 
      glVertex2f(0, 0); 
      glVertex2f(width, height); 
      glVertex2f(width, 0); 
      glVertex2f(0, height); 
      glEnd(); 

      update(); 
     } 

     QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) { 
      QOpenGLFramebufferObjectFormat format; 
      format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); 
      format.setSamples(4); 
      return new QOpenGLFramebufferObject(size, format); 
     } 
}; 

QQuickFramebufferObject::Renderer *FboInSGRenderer::createRenderer() const { 
    return new LogoInFboRenderer(); 
} 

In Qml Lo uso come segue:

import QtQuick 2.4 
import SceneGraphRendering 1.0 

Rectangle { 
    width: 400 
    height: 400 
    color: "purple" 
    Renderer { 
     id: renderer 
     anchors.fill: parent 
    } 
} 

I wa s in attesa di vedere che ha reso "X" riempirà tutta la scena, ma invece ho ottenere il risultato presentati qui di seguito:

enter image description here

Altri esperimenti sembrano confermare che ha attirato forma ha sempre la sua dimensione (larghezza/altezza) diviso da 2.

Ho anche verificato che il parametro size in createFramebufferObject ha il valore corretto.

L'esame dei documenti mi ha portato alla proprietà textureFollowsItemSize nella classe QQuickFramebufferObject, ma per impostazione predefinita è true.

Sto facendo qualcosa di sbagliato o dovrei considerare questo comportamento come Qt bug?

+0

Non so QQuick, ma OpenGL e non vedo che hai impostato sia una macchina fotografica (proiezione o modelview) o un viewport. Se si utilizza la fotocamera opengl predefinita, guarda verso il basso l'asse Z negativo. Quindi, quando disegno il quadrante positivo x e y, mi aspetterei che il risultato che mostri (ricorda, a occhio aperto è sottosopra). Per eseguire il rendering di alcuni elementi 2D in un framebuffer, impostare una videocamera orto in direzione z e un glViewport con limiti [0,0] a [pixel_width, pixels_height] ad esempio. – Thomas

+0

Ho usato il tuo codice - nel mio caso la cosa verde viene visualizzata una sola volta. Perché? – Pietrko

risposta

2

Il rettangolo disegnato è la metà delle dimensioni che ci si aspetta a causa di coordinate di default intervallo è [-1, 1], non [0, 1] il tuo codice presuppone . Se si desidera utilizzare [0, 1] scalare, allora si dovrebbe opportunamente impostare la matrice di proiezione:

glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); 
+0

Grazie! Ha risolto il mio problema, anche se ne trovo un altro: quando ridimensiono la finestra che contiene quell'elemento, l'oggetto frame-buffer viene riempito con artefatti - l'elemento non è correttamente renderer. Proverò a indagare ulteriormente e se non trovassi la risposta probabilmente invierò una nuova domanda. – pawel

+0

Hai trovato una soluzione riguardo al nuovo problema, riguardo il ridimensionamento della finestra? – Mauri

0

Come documentazione Qt dice: "Warning: It is crucial that OpenGL operations and interaction with the scene graph happens exclusively on the rendering thread, primarily during the updatePaintNode() call. The best rule of thumb is to only use classes with the "QSG" prefix inside the QQuickItem::updatePaintNode() function." lo faccio in questo modo:

* .h

class MyQuickItem : public QQuickItem 
{ 
    Q_OBJECT 
public: 
    MyQuickItem(); 
    ~MyQuickItem(); 

protected: 
    QSGNode *updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData); 
    QSGNode *addNode(QSGGeometry *geometry, const QColor &color); 
}; 

* cpp

MyQuickItem::MyQuickItem() 
{ 
    setFlag(QQuickItem::ItemHasContents,true); 
} 

MyQuickItem::~MyQuickItem() 
{ 

} 

QSGNode *MyQuickItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) 
{ 
    Q_UNUSED(updatePaintNodeData) 

    QSGTransformNode *root = static_cast<QSGTransformNode *>(oldNode); 
    if(!root) root = new QSGTransformNode; 
    QSGNode *node; 
    QSGGeometry *geometry; 

    QSGSimpleRectNode *rect = new QSGSimpleRectNode(); 
    rect->setColor(Qt::green); 
    rect->setRect(boundingRect()); 
    root->appendChildNode(rect); 

    geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2); 
    geometry->setDrawingMode(GL_LINES); 
    geometry->setLineWidth(5.0); 
    geometry->vertexDataAsPoint2D()[0].set(x(), y()); 
    geometry->vertexDataAsPoint2D()[1].set(width(), height()); 
    node = addNode(geometry,Qt::blue); 
    root->appendChildNode(node); 

    geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2); 
    geometry->setDrawingMode(GL_LINES); 
    geometry->setLineWidth(5.0); 
    geometry->vertexDataAsPoint2D()[0].set(width(), y()); 
    geometry->vertexDataAsPoint2D()[1].set(x(), height()); 
    node = addNode(geometry,Qt::blue); 
    root->appendChildNode(node); 

    return root; 
} 

QSGNode *MyQuickItem::addNode(QSGGeometry *geometry, const QColor &color) 
{ 
    QSGFlatColorMaterial *material = new QSGFlatColorMaterial; 
    material->setColor(color); 
    QSGGeometryNode *node = new QSGGeometryNode; 
    node->setGeometry(geometry); 
    node->setFlag(QSGNode::OwnsGeometry); 
    node->setMaterial(material); 
    node->setFlag(QSGNode::OwnsMaterial); 
    return node; 
} 

In principale. cpp

qmlRegisterType<MyQuickItem>("MyObjects", 1, 0, "MyObject"); 

e di utilizzo:

import QtQuick 2.3 
import QtQuick.Window 2.2 
import MyObjects 1.0  

Window { 
    visible: true 
    width: 360 
    height: 360 

    MyObject { 
     anchors.fill: parent 
    } 
} 
+0

Grazie, sfortunatamente non è quello che volevo. Conosco questo approccio, ma nel mio caso ho bisogno di chiamare openGL raw (sto integrando con una libreria esterna che dovrebbe disegnare su quell'articolo). Le cose che sto cercando di fare dovrebbero essere possibili - un esempio che ho menzionato nella mia domanda lo fa anche (Scene Graph - Rendering FBOs). – pawel

Problemi correlati