OpenGL Depth Testing in Qt not working - qt

I set the format with:
QGLFormat format = QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer);
setFormat(format);
in the constructor.
Then in initializeGL I set depthTesting on.
void VoxelEditor::initializeGL()
{
glClearDepth(2000.0); // Enables Clearing Of The Depth Buffer
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
}
In paintGL I clear the depth buffer.
void VoxelEditor::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw();
}
I remember it used to work with less vertices, so it might be that I'm using too many for the depthbuffer to handle(?).
I have 32*32*32 voxels which are drawn half of most of the time, so 98304 quads.
Depth testing however still does not work and shows the quads in order of execution.

so it might be that I'm using too many for the depthbuffer to handle(?).
The depth buffer is oblivious to vertices. All it sees are incoming fragments and it doesn't matter how many.
void VoxelEditor::initializeGL()
{
glClearDepth(2000.0); // Enables Clearing Of The Depth Buffer
This line does not enable clearing. It set's the value the depth buffer is cleared to. The value must be in the range 0…1. The clearing depth is in Normalized Device Coordinates, i.e. after modelview, projection and homogenous divide have been applied. The default value is 1.
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glShadeModel(GL_SMOOTH) // Enables Smooth Color Shading
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
No, that's not what is does. Perspective is just a linear transformation and always works the same. What it means is, that texture coordinates may be interpolated in a different way to enhance quality.
}
I always recommend putting those calls in the drawing functions, because they don't initialize anything. They set drawing state. OpenGL is a state machine and a important rule of state machines is, that either you keep track of their state or you must put them into a known state whenever you're going to use it.

I fixed this by setting setDepthTest in draw().
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);

Related

OpenGL / QT : Need help in Converting from QImage to Opengl format and render the pixels

We are migrating from Old OpenGl to Modern OpenGL. I am trying to port two functions which uses QT/OpenGL and want to convert to Modern OpenGL. QImage content should be converted to OpenGL Format. Then I want to read the pixels of QImage and render in OpenGL. How to do this in Modern OpenGL. I know glcopypixels() / glDrawPixels() is deprecated. Any pointers? I have the following code but it is in old OpenGL. Basically the whole idea is writing to back buffer and restoring the back buffer and render pixels to avoid redraw. I am using QOpenglWidget Class given by QT Framework (QT 5.1). I have tried many things converting to OpenGL format from QImage. But it did not work. Need your help. Thanks in Advance.
QImage _savedBackBuffer;
void SaveBackBuffer()
{
glReadBuffer(GL_BACK);
QImage buf = this->grabFramebuffer();
_savedBackBuffer = convertToGLFormat(buf); // convertToGLFormat is not available in
QOpenGLWidget class
}
void restoreBackBuffer()
{
glDrawBuffer(GL_BACK);
**glDrawPixels**( _savedBackBuffer.width(), _savedBackBuffer.height(),
GL_RGBA, GL_UNSIGNED_BYTE, _savedBackBuffer.bits() ); ---> glDrawPixels is Deprecated. How to handle this call.
}
flush () {
glReadBuffer (GL_BACK);
glDrawBuffer(GL_FRONT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
**glCopyPixels**(0, 0, _scrWidth, _scrHeight, GL_COLOR); // glCopyPixels Deprecated
...
glflush();
}
I have added below code to grab the Framebuffer. But still I am getting an Empty QImage. Anything wrong with my code.
saveBackBuffer()
{
_bSavingBackBuffer = true;
QString fileName("C:\\Users\\ey617e\\Desktop\\yourFile.png");
QFile file(fileName);
file.open(QIODevice::WriteOnly);
glReadBuffer(GL_BACK);
makeCurrent();
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
QOpenGLFramebufferObject * fbo = new
QOpenGLFramebufferObject(_scrWidth, _scrHeight, format);
fbo->bind();
paintGL();
_savedBackBuffer = fbo->toImage();
_savedBackBuffer.save(file.fileName(), "PNG");
fbo->release();
}
paintGL()
{
QOpenGLPaintDevice fboPaintDev(_scrWidth, _scrHeight);
QPainter painter(&fboPaintDev);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.beginNativePainting();
drawDisplayLists(_underIllusDisplayLists);
drawDisplayLists(_illusDisplayLists);
painter.endNativePainting();
painter.drawText(20, 40, "Foo");
painter.end();
}
You can create a QOpenGLTexture object directly from a QImage: https://doc.qt.io/qt-5/qopengltexture.html#QOpenGLTexture-1
You can then use that texture directly for any image related OpenGL operations.
Basically the whole idea is writing to back buffer and restoring the back buffer and render pixels to avoid redraw.
Don't do that! It will actually impair performance, since drawing on top of previously rendered content introduces implicit synchronization points, thereby eliminating options to render new contents in parallel to advancing the presentation swap chain.
As "counterintuitive" as it may sound, just redraw the whole thing, each and every frame. If your codebase is that old, then the complexity of what you're drawing very likely is going to be so low, that you could easily render thousands of frames per second.
On the other hand retaining the contents of the backbuffer constitutes a cache and thus introduces the complexity of deciding upon cache invalidation.
I bet, that just redrawing using modern methods (geometry in buffer objects, index buffers, untangling of sync points) and simplifying the rendering code path by mere elimination the code that's responsible for determining when to actually redraw portions of the picture will actually vastly outperform anything what you had before.

QOpenGLWidget overriding projection matrix

I am using Qt 5.4 and setting up the projection matrix and viewport as follows in my resizeGL function override:
glViewport(_off_x, _off_y, _width, _height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, _width, 0, _height, -1, 1);
I can verify this and when I print out the projection matrix as follows, it shows the correct value:
GLdouble projection[16];
glGetDoublev(GL_PROJECTION_MATRIX, projection );
// printing this shows the correct projection matrix.
However, somewhere this is getting overridden. When I print the projection matrix in the paintGL() function, it shows it as identity.
Interestingly, I switched to the old QGLWidget and it performs as expected.
However, somewhere this is getting overridden. When I print the projection matrix in the paintGL() function, it shows it as identity.
And you're surprised exactly why? Qt5 may use OpenGL for drawing its stuff. Which means that Qt will have to set the state of the OpenGL context according to its needs.
What you observed is what is to be expected, so don't be surprised.
I am using Qt 5.4 and setting up the projection matrix and viewport as follows in my resizeGL function override:
You should not be doing that. As with every state based system it's essential to set the state right when you need it to what you need it – or keep track of all of the state changes, which is much more difficult.
Do the right thing and move everything you did in resizeGL to where it belongs: paintGL. The sole purpose of resizeGL is to update resources like FBO renderbuffers and to reflect the new size. But don't use it to set drawing related OpenGL state.

Refreshing MainWindow in a loop to simulate a move of QWidget in QT

I am new in QT and my problem is to refresh the page in a loop to make a move on QWidget.
In detail, I have too many points (It is the path which will be followed by an ellipse and they will be drawn as line) and I have an ellipse which will move on the screen according to given two points. During its move, the path is changed. So lines will be drawn again according to new path and the ellipse should follow the new path. What I did as follows:
void MainWindow::paint(...){
painter.drawEllipse(circle) //circle is QRectF
//Also I need to draw lines according to pathPlanned
}
bool MainWindow::replan(){
//it calculates the planned path and if the ellipse does not reached the destination it can change the planned path here
}
void MainWindow::execute(){
while(replan()){
for (it = plannedPath->begin(); it != plannedPath->end(); it++){
//Lines should be redraw according to new pathPlanned
}
circle(...) // new position of ellipse is changed here
// I tried to put QThread::msleep(10) but I learned that it blocks GUI and then deleted it.
}
}
My problem is that loop is working so fast (as usual) and it can not refresh the page until it finishes everything. Then Immediately ellipse is drawn on the destination. I can not see the moves of ellipse.
How can I fix that?
Instead of using QThread::msleep(10), use following
QEventLoop loop;
QTimer::singleShot(100, &loop, SLOT(quit()));
loop.exec();
This will process events after each redraw of ellipse so UI will get updated
You need to use Qt animation framework for that. There are a lot of samples in official documentation. In this case you will not block main event loop and your animations will be smooth.
If you use custom drawing, don't forget to call QWidget::repaint() or QWidget::update() to refresh widget content.
Don't use long time loops in main thread. Use timers + slots.

Drawing with OpenGL in OOP

I try to code an OpenGL project with Qt (v5.1.1) on OS X 10.9, in the manner of the modern pipeline implementation. The program is supposed to be a multi-agent based system or particle system. However I lack in understanding how to draw something out of another class.
In cinder there were some simple drawThisAndThat() command you could call. I read the 6th edition of the 'OpenGL Superbible'. From this and several tutorials all examples seem to cover just programs where all modifications are made out of the class that initializes OpenGL.
I would like to instantiate some objects moving on a grid and draw pixel to display their position. I know I have to call void glVertexAttrib4fv(GLuint index, const GLfloat * vi); but this is not sufficient.
Do I need to call glEnableVertexAttribArray(1); and glDrawArrays(GL_POINTS, 0, 3); as well and what else?
Am I right, to instantiate the class controlling the particles after instantiating OpenGL and bevor the main loop?
How do I manage that the particle draws himself while erasing the position he was drawn bevor?
The program is based on this code.
To answer your questions completely I would have to write a wall of text, I will try to only point out the most important aspects. I hope this will help you enough to use your knowledge and probably further reading to get it to work.
all modifications are made out of the class that initializes OpenGL
You can encapsulate update(time) and draw() methods for your Objects which you then call in your main loop.
Do I need to call glEnableVertexAttribArray(1); and glDrawArrays(GL_POINTS, 0, 3); as well and what else?
I would put all particles into one vertex array to avoid rebinding of different vertex arrays after each particle. Then you would have to use glBindVertexArray(vaid); and glDrawArrays(GL_POINTS, 0, vertexCount); in your draw() call. Be careful with vertexCount, it's not the number of floats (as your question implies) but the number of vertices, which should be 1 in your example or the number of particles in my suggested approach (If I'm correct in assuming that the 3 stands for "x, y, and z of my vertex").
And since you only have particles glDrawElements(...); would probably already fit your needs.
Am I right, to instantiate the class controlling the particles after instantiating OpenGL and bevor the main loop?
Probably your instantiation order is correct that way. You definitely should do all instantiations before calling the main loop in your case.
How do I manage that the particle draws himself while erasing the position he was drawn bevor?
If understand your last question correctly: Simply by changing the elements in your buffer objects (glBufferData(...);). Since you will clear the screen and swap buffers after each loop this will make them move. Just update their position with an update(time) call, e.g. pos = pos + dir * time;, put the new positions into a buffer and push that buffer with glBufferData(...) to the vertex array. Remember to bind the vertex array before pushing the buffer.
Some additional things I'd like to point out.
glEnableVertexAttribArray(1); is to enable a vertex attribute in your shader program to be able to pass data to that attribute. You should create a shader program
id = glCreateProgram()
// ... create and attach shaders here
// then bind attribute locations, e.g. positionMC
glBindAttribLocation(id, 0, "positionMC");
glLinkProgram(id);
And after initializing the vertex array with glGenVertexArrays(); you should enable all attributes your vertex array needs in your shader program. In this example positionMC would be at location 0, so you would call something like
glUseProgram(pid);
glBindVertexArray(vaid);
glEnableVertexAttribArray(1);
glVertexAttribPointer(...);
This has only to be done once, since OpenGL stores the state for every particular vertex array. By rebinding a vertex array you will restore that state.
In the main loop all you have to do now is calling your update and draw methods, e.g.:
handleInputs();
update(deltaTime);
glClear(...);
draw();
swapBuffers();

Conceptual question: Loose Coupling

I am building a graphic board like project where i am facing a design issue.
Main Class is Board which is a canvas responsible for handling mouse events when drawing shapes. It also has context variables such as currentShape or snapFlag to activate grid magnetism.
To handle the moving / resizing / rotating of the shapes, they inherit from a third party open source tool called ObjectHandles (flex).
I have a baseShape extending ObjectHandles main class to override some of its internal functions, like the onMove function.
When creating a shape (mouse down, move, mouse up) this is handle by the Board and it knows about his own snap flag.
var mouseUpPoint:Point = boardCanvas.globalToLocal(new Point(event.stageX, event.stageY));
var snapMouseUpPoint = snapPoint(mouseUpPoint.x, mouseUpPoint.y);
In my overidden onMove method i would like the shape to be aware of the Board snap flag and when its changing. How do i do this ?
Do i pass the Board as a parameter in my basicShape constructor so that i can check snap ?
Do i pass the flag as a parameter and somehow make all shapes listen for change ?
What is the cleanest solution ?
Thanks a lot.
I would approach this from a slightly different angle. I assume that the Board object traps mouse events first, so that it can decide which shape has been clicked on. I would have the board trap mouse movements as well, passing the correct (snapped or unsnapped) coordinates "down" to the selected Shape object, rather than letting the shape object figure it out.
This leaves the grid snap handling to the Board, and keeps your Shape object onMove method free of clutter.
Not knowing your app:
Is it ever possible for a Shape to have it's own 'snap' behavior? That is, could a Shape be excluded from snapping while others aren't? If so, make snapFlag a member of Shape. When snapFlag is set on the Board, iterate through your Shapes and set or don't set according to your rules.
If snapping behavior applies to all Shapes on the Board, consider an event-driven model (if it's available - I'm a Flex noob). When a Shape moves, have it raise an OnMove event. The Board can then respond and decide to 'snap' the Shape into place if it's appropriate.
If snap behavior applies to all Shapes and events aren't available, I'd just say the hell with loose coupling in this case - make the Shapes Board-aware. It sounds like you're saving a bunch of code by using the ObjectHandle. That benefit may out-weigh the cost of coupling your UI elements.
Just trying to think together with you..
I see no big deal in Shapes having IBoard interface.
Though, I don't like the idea that they have to check the flag on the board...
How would you pass the flag as parameter? In OnMove() method? didn't understood this quite well...could you expand?
Though..
If you try to think a bit about SRP - single responsibility principle...what is the responsibility of Shape classes?
Yea, this is what eJames wrote already.
It feels to me that their main responsibility is probably NOT handling mouse events...here need to know more about your application, but my general feeling is why not someone else get this mouse down and then figure out what the shape should do with it and for instance call Draw() on the Shape with new coordinates?
Let's say you want to apply something like Composite pattern (Shapes inside shapes...) and you want them to be able to handle those mouse events themselves...but then
Then it would be logical if they perceived this mouse event in their local coordinates, but then I think you should provide all the information through this event (local coordinates, mouse status...) so that they don't have to ask for "global" variables on the board...
Passing the flag as a parameter for the shape constructor. But it wont be good since flag is going to change and i have to make each shape to update their flag copy on change.
Its true that shape responsibility is not to know how to handle mouse events. But thats what ObjectHandles do: react to events, update height width rotation parameter of the shape.
Maybe i should transfer some of the library code in my board class to handle shape selection and movement / resizing / rotation.
OnMouseMove ObjectHandles
protected function onMouseMove(event:MouseEvent) : void
{
if( ! visible ) { return; }
if( ! event.buttonDown )
{
setMouseCursor( event.stageX, event.stageY );
return;
}
if(parent == null )
{
return;
}
var dest:Point = parent.globalToLocal( new Point(event.stageX, event.stageY) );
var desiredPos:Point = new Point();
var desiredSize:Point = new Point();
var desiredRotation:Number = 0;
... plenty more
then
if( wasMoved ) { dispatchMoving() ; }
if( wasResized ) { dispatchResizing() ; }
if( wasRotated ) { dispatchRotating(); }
So i can not listen for move event and tell the board to snap it since the shape is already moving freely. I should add snap here:
var dest:Point = parent.globalToLocal( new Point(event.stageX, event.stageY) );
All shapes follow the snap rule there can not be one snapping and the other free.
Solved it this way:
Since i overridde onMouseMove in my baseShape class and i am using PureMVC framework, i just made baseShape aware of my boardMediator.
override protected function onMouseMove(event:MouseEvent) : void
{
[...]
// added on override
var board:BoardMediator = ApplicationFacade.getInstance().retrieveMediator(BoardMediator.NAME) as BoardMediator;
Then
desiredPos = board.snapPoint(desiredPos.x, desiredPos.y);
Maybe not super pretty but it works, o
Overridding the globalToLocal method in my board view did work too but some more calculations were done inside onMouseMove resulting in an out of alignment snap move.
Use ObjectHandles Version 2, and then create a constraint to do what you want.

Resources