qt - QGraphicsScene & OpenGL Fragment Shader Not Working -


i have large qgraphicsscene can contain large number of graphics. i'm using qglwidget viewport can leverage opengl try improve how things rendered. have created custom qgraphicsitem can use draw several quads same texture in 1 render call rather having hundreds or thousands of different qgraphicsitems in scene drawn same way, in different locations. in custom qgraphicsitem's paint() method, called beginnativepainting() , endnativepainting() , of opengl calls between them.

i want use shader programs can manipulate vertices within vertex shader, copied qt's opengl textures example uses shader program draw 6 textured quads. example works fine is, when try use same approach within qgraphicsitem's paint() method, of quads drawn white. best guess fragment shader isn't getting used. i've tried hardcoding color within fragment shader , nothing changes.

here's source code of custom qgraphicsitem class.

class batchgraphics : public qgraphicspixmapitem {   enum {program_vertex_attribute = 0,         program_texcoord_attribute = 1};  public:   batchgraphics()     : _program(0),       _texture(0),       _dirty(false)   {   }    // returns custom bounding rect item encompasses quads   qrectf boundingrect() const   {     return _boundingrect;   }    // add quad batch.  center point necessary   void addquad(int id, float x, float y)   {     _quads.insert(id, qpointf(x, y));     updateboundingrect();     _dirty = true;   }    // remove quad batch.   void removequad(int id)   {     if (_quads.contains(id))     {       _quads.remove(id);       updateboundingrect();       _dirty = true;     }   }    // return number of quads in batch   int count() {return _quads.count();}    // paint batch using custom implementation.   void paint(qpainter *painter, const qstyleoptiongraphicsitem *option, qwidget *widget)   {     // if item dirty (has been modified, update geometry)     if (_dirty) {       updategeometry();     }      if (_program)     {       painter->beginnativepainting();        // enable gl states       //glenable(gl_texture_2d);        // set mvp matrix       _program->setuniformvalue("matrix", painter->transform());        // enable , set vertex , texture attributes       _program->enableattributearray(program_vertex_attribute);       _program->enableattributearray(program_texcoord_attribute);       _program->setattributearray(program_vertex_attribute,   gl_float, _vertices.constdata(),   3, 5*sizeof(glfloat));       _program->setattributearray(program_texcoord_attribute, gl_float, _vertices.constdata()+2, 2, 5*sizeof(glfloat));        // bind texture       _texture->bind();        // draw arrays       gldrawarrays(gl_triangles, 0, _quads.count()*6); // 6 vertices per quad        painter->endnativepainting();     }   }  private:   // initialize shader , texture   void initialize()   {     // create opengl texture     _texture = new qopengltexture(pixmap().toimage());      // vertex shader     qopenglshader *vshader = new qopenglshader(qopenglshader::vertex);     const char *vsrc =         "attribute  highp    vec4  vertex;\n"         "attribute  mediump  vec4  texcoord;\n"         "varying    mediump  vec4  texc;\n"         "uniform    mediump  mat4  matrix;\n"         "void main(void)\n"         "{\n"         "    gl_position = matrix * vertex;\n"         "    texc = texcoord;\n"         "}\n";     vshader->compilesourcecode(vsrc);      // fragment shader     qopenglshader *fshader = new qopenglshader(qopenglshader::fragment);     const char *fsrc =         "uniform           sampler2d  texture;\n"         "varying  mediump  vec4       texc;\n"         "void main(void)\n"         "{\n"         "    gl_fragcolor = texture2d(texture, texc.st);\n"         "}\n";     fshader->compilesourcecode(fsrc);      // program     _program = new qopenglshaderprogram;     _program->addshader(vshader);     _program->addshader(fshader);     _program->bindattributelocation("vertex",   program_vertex_attribute);     _program->bindattributelocation("texcoord", program_texcoord_attribute);     _program->link();      _program->bind();     _program->setuniformvalue("texture", 0);   }    // update vertex array.  calls initialize first time.   void updategeometry()   {     if (_program == 0) {       initialize();     }      _vertices.clear();      // half pixmap size     qpointf s = qpointf(pixmap().width()/2, pixmap().height()/2);      // build vertex data each quad     foreach (const qpointf& point, _quads)     {       // top left       _vertices << point.x()-s.x(); // x       _vertices << point.y()-s.y(); // y       _vertices << 1;               // z       _vertices << 0;               // tu       _vertices << 1;               // tv        // top right       _vertices << point.x()+s.x(); // x       _vertices << point.y()-s.y(); // y       _vertices << 1;               // z       _vertices << 1;               // tu       _vertices << 1;               // tv        // bottom left       _vertices << point.x()-s.x(); // x       _vertices << point.y()+s.y(); // y       _vertices << 1;               // z       _vertices << 0;               // tu       _vertices << 0;               // tv        // top right       _vertices << point.x()+s.x(); // x       _vertices << point.y()-s.y(); // y       _vertices << 1;               // z       _vertices << 1;               // tu       _vertices << 1;               // tv        // bottom left       _vertices << point.x()-s.x(); // x       _vertices << point.y()+s.y(); // y       _vertices << 1;               // z       _vertices << 0;               // tu       _vertices << 0;               // tv        // bottom right       _vertices << point.x()+s.x(); // x       _vertices << point.y()+s.y(); // y       _vertices << 1;               // z       _vertices << 1;               // tu       _vertices << 0;               // tv     }      _dirty = false;   }  private:   // updates bounding rect based on quads in batch.   void updateboundingrect()   {     preparegeometrychange();      double left = 9999;     double right = -9999;     double top = 9999;     double bottom = -9999;      double w = pixmap().width()/2;     double h = pixmap().width()/2;      foreach (const qpointf& p, _quads)     {       left   = qmin(left,   p.x()-w);       right  = qmax(right,  p.x()+w);       top    = qmin(top,    p.y()-h);       bottom = qmax(bottom, p.y()+h);     }      _boundingrect = qrectf(left, top, (right-left), (bottom-top));   }  private:   qopenglshaderprogram* _program;   qopengltexture* _texture;   qrectf _boundingrect;   qmap<int, qpointf> _quads;   qvector<glfloat> _vertices;   bool _dirty; }; 

i understand basics of render pipeline , how use shaders, far dependencies between things , other opengl methods must called when using features i'm pretty clueless on. can quads rendered texture using fixed function pipeline approach, that's old school , said, want able manipulate vertices in vertex shader once working.

i'm not doing special when creating qglwidget, , qglformat ends being 2.0. i'v tried calling glenable(gl_texture_2d), makes quads rendered black instead of white. i've tried binding program each time paint() called, thinking perhaps qt binding different shader somewhere else behind scenes, causes nothing appear.

can provide please? can't figure out why approach works fine in qt's textures example not when try inside of qgraphicsitem.

i figured out after looking @ qt's source code , happens when beginnativepainting(). first, did have bind shader each time paint() called, , second had correct mvp matrix.

i trying pass qpainter's transform shader act modelview projection matrix, transform modelview matrix. needed projection matrix well, qt sets when beginnativepainting() called.

i got project , modelview matrices opengl directly , combined them pass shader after binding texture , presto! worked!

here relevant changes had make:

painter->beginnativepainting();  // enable gl states //glenable(gl_texture_2d);  // === begin new code ====== // bind program _program->bind();  qmatrix4x4 proj; glgetfloatv(gl_projection_matrix, proj.data());  qmatrix4x4 model; glgetfloatv(gl_modelview_matrix, model.data());  // set mvp matrix _program->setuniformvalue("matrix", proj * model); // === end new code ======  // enable , set vertex , texture attributes _program->enableattributearray(program_vertex_attribute); _program->enableattributearray(program_texcoord_attribute); _program->setattributearray(program_vertex_attribute,   gl_float, _vertices.constdata(),   3, 5*sizeof(glfloat)); _program->setattributearray(program_texcoord_attribute, gl_float, _vertices.constdata()+2, 2, 5*sizeof(glfloat)); 

Comments