Solved glUunproject and QOpenGLShader problem.
-
Hi Great Gurus.
I having some battle with QOpenGL shaders and GLU...
Long story short I decided to go forward and instead using locked pipeline OpenGL from QGLWidget and direct calls to draw into the widget, and I will use shaders, VBO & all this fancy new stuff in modern OpenGL, that QT can offer.
Drawing antialiasing etc works great apart glUunproject which I used to unProject my mouse pointer from ortho projection stops working it seems whatever MVP ( Model Vertec Projection ) matrixes I will set in shader it always take it as unity and glUunproject return ( from range -1 to 1 in x and y )
I noticed if in f.g paintGL() use old initialization of glOrtho, then calls from glut works on those parameters.glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(_left,_right,_bottom,_top,_near,_far); glMatrixMode(GL_MODELVIEW); glLoadIdentity();
but when I will call this anywhere in initialization / resize / or paint GL, the ortho frame will be set but shader program will use own ortho, so its only correct for static image if I want to pan or zoom mouse coordinate will reflects this parameters called in glOrtho(); if i will coment this section and recompile all ofcourse works but the mouse is calculated glUunproject takes unity projectio matrix and is -1 to 1 where -1,-1 is left mottom corrner and 1,1 top right.
Ok lets look at the code:
simply initializations from header,void initializeGL(); void resizeGL(int _width, int _height); void paintGL(); QOpenGLShaderProgram OGLProgram; QPointF SceneCoordinates(QPoint point); QQuaternion modelRotation; QVector3D modelTranslation; QMatrix4x4 modelMat, viewMat, orthoMat; float modelScale; QOpenGLBuffer m_vertex; QOpenGLVertexArrayObject m_object; QOpenGLShaderProgram *m_program; void Draw2D_object(QVector<QVector3D> _vertex, QVector<QVector3D> _color );
thats my screen to scene coordinate function is caled when QMouseEvent is trigered
QPointF OpenGL_OrthoGL_class::SceneCoordinates(QPoint point) { GLint viewport[4]; double modelview[16]; double projection[16]; double posX, posY, posZ; int winx, winy, winz; glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); glGetIntegerv(GL_VIEWPORT,viewport); winx = point.x(); winy = viewport[3] - point.y(); winz = 1.0; glReadPixels( winx, winy, 1 ,1, GL_DEPTH_COMPONENT, GL_FLOAT, &winz); gluUnProject( winx, winy, winz, modelview, projection, viewport, &posX, &posY, &posZ ); return (QPointF(posX,posY)); }
and that's my GL code
void OpenGL_OrthoGL_class::initializeGL() { glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glEnable(GL_SMOOTH); glEnable(GL_MULTISAMPLE); glEnable(GL_TEXTURE_2D); glClearColor(0.3f , 0.3f , 0.3f , 1.0); glViewport(0,0,this->width(),this->height()); Q_ASSERT(OGLProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/new/shaders/OrthoShader.vert")); Q_ASSERT(OGLProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/new/shaders/OrthoShader.frag")); Q_ASSERT(OGLProgram.link()); Q_ASSERT(OGLProgram.bind()); }
. the ortho is a struct and its set wit default document size and later wehn mew project is created it filed with size of 2d plane near and fare plane always are -100.0f and 100.0f
void OpenGL_OrthoGL_class::paintGL(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); orthoMat.setToIdentity(); orthoMat.ortho(ortho.left,ortho.right,ortho.bottom,ortho.top,ortho.near_plane,ortho.far_plane); orthoMat.translate(pan_x ,pan_y, 0.0f); orthoMat.scale( zoom_k ); viewMat.setToIdentity(); modelMat.setToIdentity(); draw_PolyLine(); }
calling draw functions to draw elements. I had a dxf loader pushing data into flew arrays this is for PolyLine elements ( and Im ussing 2d Draw of looped lines for looped polyLines )
void OpenGL_OrthoGL_class::draw_PolyLine(){ for(int i=0; i < PolyLineVectors.count();i++){ QVector<QVector3D> Loop = PolyLineVectors.at(i); QVector<QVector3D> Color = PolyLineColors.at(i); Draw2D_object(Loop,Color); }}
2D looped line drawing in shader
void OpenGL_OrthoGL_class::Draw2D_object(QVector<QVector3D> _vertex, QVector<QVector3D> _color){ OGLProgram.enableAttributeArray("vertexLocation"); OGLProgram.setAttributeArray("vertexLocation", _vertex.constData()); OGLProgram.enableAttributeArray("vertexColor"); OGLProgram.setAttributeArray("vertexColor", _color.constData()); OGLProgram.setUniformValue("matrixLocation",orthoMat); OGLProgram.setUniformValue("modelViewProjMatrix", orthoMat *viewMat * modelMat); glDrawArrays(GL_LINE_LOOP, 0, _vertex.count()); OGLProgram.disableAttributeArray("vertexLocation"); OGLProgram.disableAttributeArray("vertexColor"); }
and this is my basic shaders, vertex and pixel ( fragment )
attribute highp vec3 vertexLocation; attribute lowp vec3 vertexColor; attribute highp mat4 matrixLocation; uniform highp mat4 modelViewProjMatrix; varying vec3 color; void main(void) { color = vertexColor; gl_Position = modelViewProjMatrix * vec4(vertexLocation, 1.0); }
pixel shader
varying vec3 color; void main(void) { gl_FragColor = vec4(color, 0.5); }
So my question is: Is there any way to get MVP matrix from shader to push to glUunproject or to get the ortho matrix after transformations, and set in in glOrtho so the glut can calc correct mouse pointer position from the scene before I used simply model view transformation for Panning and Scaling
/* glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Reset the model-view matrix glScalef(static_cast<float>(zoom_k),static_cast<float>(zoom_k) , 1); glTranslatef(static_cast<float>(pan_x) ,static_cast<float>(pan_y) ,-1); */
Now I using matrix in shader transformation because there is no direct glMatrix calls so the code above is obsolete as drawing is done by shader.
orthoMat.translate(pan_x ,pan_y, 0.0f); orthoMat.scale( zoom_k );
so my idea is if can get the matrixes from shader and put them here instead of this
glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); glGetIntegerv(GL_VIEWPORT,viewport);
by just assigning
modelview = modelMat * viewMat; projection = orthoMat;
that's should give glUunproject correct matrixes to work with., but of course that's not working because the viewMat modelMat orthoMat are QMatrix4x4 and modelview are simple double arrays.
thanks for looking at my terrible codding -
Hi guys & girls I'm feeling embarrassed after flew hours from posting this I found the solution to this problem.
A simple copy of data with casting them into array did the trick, So In the method, calculation screen mouse pos into word coordinate I've commented this to calls for glGet....
// glGetDoublev(GL_MODELVIEW_MATRIX, modelview); // glGetDoublev(GL_PROJECTION_MATRIX, projection); for(int i=0; i <16 ;i++) { modelview[i] = static_cast<double>( modelMat.constData()[i]); projection[i] = static_cast<double>( orthoMat.constData()[i]); }
It seems to glGetDoublev takes its matrix from old type OpenGL 1.1 it works well for fixed pipeline but not for shaders,
so instead of using those calls to get modelview and matrix i simmply copy with casting to double data from modelMat & orthoMat wich they are QMatrix4x4 ( floats )... Problem solved and i feel embaresed as it was so easy to do if you think strait for 2 min.
Hopefully, maybe someone else will find this useful -
It's probably worth noting that the most recent GLU spec is over 20 years old now, and predates stuff like shaders. Using it in the context of a modern OpenGL app is gonna depend on sheer luck if any parts of it still work well.