Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Classes principales  ·  Annotées  ·  Classes groupées  ·  Modules  ·  Fonctions  · 

Drawing into framebuffer objects

The Nesting example shows how Qt3D can be used to draw into a framebuffer object and then use the associated texture in subsequent drawing operations. It is assumed that the reader is already familar with the following examples:

  • Hello Teapot - drawing a basic object in 3D.
  • Cube - applying transformations and materials to objects.

In this example we are going to draw two rotating and transparent cubes. One cube will display a simple texture as in the Cube example, and the other cube will display a nested scene containing a rotating teapot.

As with the other examples, we start by creating the geometric objects we need in the constructor (we will share the cube geometry between the two cubes we will be drawing):

 CubeView::CubeView(QWindow *parent)
     : QGLView(parent)
     , fbo(0)
     , tangle(0.0f)
     , cangle(0.0f)
     , oangle(0.0f)
 {
     QGLBuilder builder;
     builder.newSection(QGL::Faceted);
     builder << QGLCube(1.5f);
     cube = builder.currentNode();
     cube->setObjectName(QLatin1String("Cube"));

     builder.newSection();
     builder << QGLTeapot();
     teapot = builder.currentNode();
     teapot->setObjectName(QLatin1String("Teapot"));

     scene = builder.finalizedSceneNode();
     scene->setParent(this);

We also need three QPropertyAnimation objects to drive our animations; rotation angle for the teapot, rotation angle for the cube; orbit angle of the two cubes around each other:

     QPropertyAnimation *animation;

     animation = new QPropertyAnimation(this, "teapotAngle", this);
     animation->setStartValue(0.0f);
     animation->setEndValue(360.0f);
     animation->setDuration(1000);
     animation->setLoopCount(-1);
     animation->start();

     animation = new QPropertyAnimation(this, "cubeAngle", this);
     animation->setStartValue(0.0f);
     animation->setEndValue(360.0f);
     animation->setDuration(5000);
     animation->setLoopCount(-1);
     animation->start();

     animation = new QPropertyAnimation(this, "orbitAngle", this);
     animation->setStartValue(0.0f);
     animation->setEndValue(360.0f);
     animation->setDuration(5000);
     animation->setLoopCount(-1);
     animation->start();

The final step in the constructor is to create a camera for the nested scene we will be drawing into the framebuffer object. This is in addition to the default QGLView::camera() object that provides the camera for the main scene.

     innerCamera = new QGLCamera(this);
 }

To draw the nested scene, we of course need a framebuffer object, which we create in the initializeGL() method:

 void CubeView::initializeGL(QGLPainter *)
 {
     fbo = new QOpenGLFramebufferObject(512, 512, QOpenGLFramebufferObject::Depth);
     fboSurface.setFramebufferObject(fbo);

Note that we also set the framebuffer object on an instance of QGLFramebufferObjectSurface. We will use this fact later when we render the nested scene.

For the other cube, we need a regular texture. And we'll also turn on blending to make our cubes transparent:

     QImage textureImage(QLatin1String(":/qtlogo.png"));
     qtlogo.setImage(textureImage);

     glEnable(GL_BLEND);
 }

Now it is time to paint the scene in paintGL(). The first thing we want to do is draw the teapot into the framebuffer object. To do that, we need to establish a nested drawing state:

 void CubeView::paintGL(QGLPainter *painter)
 {
     painter->modelViewMatrix().push();
     painter->projectionMatrix().push();
     painter->pushSurface(&fboSurface);

In the code above, we first push the main scene's modelview and projection matrices. And then we push a new drawing surface onto the painter's surface stack. Everything we draw from now on will be written to fboSurface and thus the framebuffer object. To do that, we set the inner camera position, adjust the painter state, clear the framebuffer object, and draw the teapot:

     painter->setCamera(innerCamera);
     painter->modelViewMatrix().rotate(tangle, 0.0f, 1.0f, 0.0f);

     painter->setFaceColor(QGL::AllFaces, QColor(170, 202, 0));
     painter->setStandardEffect(QGL::LitMaterial);

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     teapot->draw(painter);

Now that the nested scene has been drawn to the framebuffer object, we pop the surface and matrix stacks to return to the main scene:

     painter->popSurface();
     painter->projectionMatrix().pop();
     painter->modelViewMatrix().pop();

Because our cubes are transparent, we need to make sure we draw the objects in the scene from back to front. Otherwise the result will not look correct. To do this, we check which of the cube mid-points is furtherest away from the camera and draw that cube first (the more negative the z value, the further away it is):

     painter->modelViewMatrix().rotate(oangle, 0.0f, 1.0f, 0.0f);
     QMatrix4x4 m = painter->modelViewMatrix();
     QVector3D cube1pos(-1.5f, 0.0f, 0.0f);
     QVector3D cube2pos(1.5f, 0.0f, 0.0f);

     if (m.map(cube1pos).z() < m.map(cube2pos).z()) {
         drawCube1(painter, cube1pos);
         drawCube2(painter, cube2pos);
     } else {
         drawCube2(painter, cube2pos);
         drawCube1(painter, cube1pos);
     }
 }

Drawing the first cube with the simple texture is very similar to the Cube example:

 void CubeView::drawCube1(QGLPainter *painter, const QVector3D &posn)
 {
     painter->modelViewMatrix().push();

     qtlogo.bind();
     painter->setFaceColor(QGL::AllFaces, QColor(202, 100, 0, 150));
     painter->setStandardEffect(QGL::LitDecalTexture2D);

     painter->modelViewMatrix().translate(posn);
     painter->modelViewMatrix().rotate(cangle, 1.0f, -1.0f, 1.0f);

     glCullFace(GL_FRONT);
     glEnable(GL_CULL_FACE);
     cube->draw(painter);
     glCullFace(GL_BACK);
     cube->draw(painter);
     glDisable(GL_CULL_FACE);

     painter->modelViewMatrix().pop();
 }

The main interesting wrinkle is that we draw the cube twice, once with front faces culled, and the second time with back faces culled. This effectively causes the cube to be drawn back to front for proper blending.

The second cube is drawn in a similar way except that we bind the framebuffer object's texture to the state instead of a static texture:

 void CubeView::drawCube2(QGLPainter *painter, const QVector3D &posn)
 {
     painter->modelViewMatrix().push();

     painter->setFaceColor(QGL::AllFaces, QColor(0, 160, 202, 125));
     painter->setStandardEffect(QGL::LitDecalTexture2D);
     glBindTexture(GL_TEXTURE_2D, fbo->texture());
     glEnable(GL_TEXTURE_2D);

     painter->modelViewMatrix().translate(posn);
     painter->modelViewMatrix().rotate(cangle, 1.0f, 1.0f, 1.0f);

     glCullFace(GL_FRONT);
     glEnable(GL_CULL_FACE);
     cube->draw(painter);
     glCullFace(GL_BACK);
     cube->draw(painter);
     glDisable(GL_CULL_FACE);

     glBindTexture(GL_TEXTURE_2D, 0);
     glDisable(GL_TEXTURE_2D);

     painter->modelViewMatrix().pop();
 }

Face culling is a simple way to draw transparent objects, but it really only works on non-intersecting convex objects like our cubes. For concave objects (like the teapot) or objects that intersect, we would need to break the objects up into smaller convex pieces and then order the pieces from back to front.

Return to Examples.

Files:

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 5.0-snapshot
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web