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
Post a Comment