I am trying to display HUD over my 3D game. For starters, I am just trying to display "Hello World", but I haven't had any success yet! The scene freezes / flickers once I am done.
I am using Qt/C++ and QGLWdiget / QPainter to get this done. I have used overpainting example as my reference to get started. Here is what I do:
override paintEvent(...) in my own subclassed GameGL Class ( GameGL : public QGLWidget )
Push openGL ModelView matrix as the current matrix
enable parameters as gl_depth_test
render my game (:: paintGL1() )
disable the modelview parameters
pop modelview matrix
Make QPainter object
invoke paint.drawText()
Flush using paint.end()
This is pretty much the same as mentioned in the example. However, when I run this code, it experiences freezing / flickering and is highly un-responsive. Would anyone have any idea as to why this might be happening ? I'd really appreaciate any help.
Code:makeCurrent();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
//Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//.50f, 1.0f );
//glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
m_pLight->SetupLight(GL_AMBIENT | GL_DIFFUSE | GL_SPECULAR);
glEnableClientState( GL_INDEX_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
resizeGL( width(), height() );
paintGL1();
//glShadeModel(GL_FLAT);
glDisable(GL_DEPTH_TEST);
//glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisableClientState( GL_INDEX_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.drawText(100, 50, QString("Hello"));
painter.end();
Thank you
For anyone who is still struggling with this and came across this post: here is how I solved it::
Please follow the overpainting example as is. If you look over at the code in the example, you would notice in the constructor, a timer timeout() SIGNAL is connected to animate() SLOT. If you look closely at the animate() slot, it in-turn calls update() a.k.a GLWidget::update(). If you follow the documentation for GLWidget::update(); this in-turn calls paintEvent(...).
This background is important and was the missing piece to my problem. I was earlier using paintGL(...) to draw my scene since I had overriden GLWidget. To support animation or updates to my scene, I had connected the timer to updateGL(). This was in-turn invoking paintGL() via glDraw(). This was the root cause of all the problems.
The code as I had written was calling paintGL() again and again. Following overpainting example, I got rid of paintGL method completely and switched to paintEvent(...) rendering methodology instead. Thus, to keep things in-sync, I had to call update() (instead of updateGL() ) to make things work. The minute I made this transition, things started working as expected. (GLWidget::update() calls paintEvent(...) )
I hope it has helped you any bit. If it still doesn't work for you or need firther explanaition, leave me a comment here and I will try to help.
Related
I am doing an excercise where I draw three boxes across three windows using GLUT. They draw individually, but in the same project, the three windows display correctly, but immediately close the program with code 1.
glutInitWindowPosition(x,y);
windowOne = glutCreateWindow("windowOne");
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glOrtho(-400, 400, -400, 400, -500, 500);
glutInitWindowPosition(x,y);
windowTwo = glutCreateWindow("windowTwo");
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glFrustum(-60, 60, -60, 60, 60, 200);
gluLookAt(0, 0, 120, 0, 0, 0, 0, 1, 0);
With each window in a separate file loaded in by itself, they each display exactly as they are meant to. I have a feeling I should be setting the window at some point between each init, but I don't know why. I do not have a draw function in at the moment, as I wanted to confirm this happens without the drawing code.
I should also note that I have to create separate windows, exactly as I have done, so other window drawing functions are useless.
I found the answer scouring through examples, so I'll post it just in case anyone else is having similar problems.
the draw function needs to be added after each window, in the style of
// window one
glutInitWindowPosition(50, 50);
WindowOne = glutCreateWindow("orthogonal projection");
glutDisplayFunc(drawWindowOne);
// window two
glutInitWindowPosition(650, 50);
WindowThree = glutCreateWindow("3D viewing system with glFrustum()");
glutDisplayFunc(drawWindowTwo);
I was using a draw function that shuffles through each window and generates its specific draw after using glutSetWindow. each draw takes place after each window is initialized, and multiple glutDisplayFunc() can be called after eachother.
I originally thought I was using glutDisplayFunc to set a pointer, so that when the display routine went through for the frame, it would only generate the last display function called, as opposed to all of them.
Never do OpenGL drawing operations in the same function in which you also create GLUT windows. It doesn't work. You need to register a display callback function for each window and do all drawing there. Calling glutMainLoop is mandatory if you want to see something sensible using GLUT.
I'm stumped. I have a widget inside the mainwindow on a QT 4.6 application which has been configured as a openGL widget. It draws just fine except I am unable to clear the background between frames. I get a black background when he window opens and it never clears after that, so I get a jumbled mess of rendered objects as time goes along. I'm also having to call swapBuffers() at the end of the paintGL() function to get the widget to show the most recent frame which has me puzzled as I was under the impression that swapBuffers() was called automatically. I am set up for double buffering and the widget is not shared. Here is the relevant code:
void GLWidget::paintGL ( )
{
m_Input.Draw();
QGLWidget::swapBuffers();
}
void GLWidget::initializeGL ( )
{
qglClearColor(QColor(0,0,255,128));
glClear(GL_COLOR_BUFFER_BIT);
}
It does seem there's something not right with the double buffering. Clearing the screen to a background color is pretty basic. But it's driving me nuts as to why it's not working. The remainder of the drawing code is working fine. Any ideas? (This is on a Linux system.)
glClear is a drawing operation. It doesn't belong into initializeGL but into paintGL. The clearing color should be set right before calling glClear as well, so move that [q]glClearColor along.
Update
The paintGL method should look like this:
void GLWidget::paintGL()
{
qglClearColor(QColor(0,0,255,128));
glClear(GL_COLOR_BUFFER_BIT);
// you probably also want to clear the depth and stencil buffers
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
m_Input.Draw();
QGLWidget::swapBuffers();
}
Of course you must make sure that m_Input.Draw() doesn't mess things up again. You didn't show the code for that, so I'm in the blind here.
I'm experiencing some weird graphical corruption with my SDL2 + OpenGL GUI application. Now I apologize if I'm not using the appropriate term to describe the situation. It seems that the front buffer is being invalidated and other applications are being drawn in the buffer?
Important note: this corruption only occurs in Windows XP or when using the Windows Basic theme in Windows 7.
The corruption can be reproduced in a few ways:
by moving the window around. It seems that the front buffer gets corrupted with the image of other applications in front or behind it.
if there's an application behind, it'll occasionally flash into the front buffer.
I can load up a google webpage in Chrome above the opengl application, close the chrome process, and then move the opengl application around and I'll see the google homepage covering the whole inside of the window.
by moving another application over the opengl window.
It seems that I also see the corruption when I'm moving other windows around, even if they don't overlap the opengl window, so long as I've already tried one of the ones posted just above.
inline int UI::RenderingThread()
{
UI::Window::Instance().RenderingThreadEnter();
while( UI::Window::Instance().RenderingThreadActive() )
{
unsigned int ticks = SDL_GetTicks();
UI::Window::Instance().RenderingThreadUpdate();
UI::Window::Instance().RenderingThreadRender();
ticks = SDL_GetTicks() - ticks;
if( ticks < 33 )
{
SDL_Delay( 33 - ticks );
}
}
UI::Window::Instance().RenderingThreadExit();
return 0;
}
As you probably guessed, I'm using multithreading and I have my rendering in a separate thread. Within the RenderingThreadRender() function, I only redraw if there's a change in content, or I've requested a redraw.
case SDL_WINDOWEVENT:
switch( sdl_event.window.event )
{
default:
UI::Window::Instance().Redraw();
break;
}
This is done to allow all SDL_WINDOWEVENT events to redraw in hopes that one of them would fix the problem. Unfortunately that has not solved the issue.
I'm hesitant to simply constantly redraw my application at 30 or 60 fps since I've noticed that by doing so, other application would be sluggish when moving them around.
Initialization:
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
this->window = SDL_CreateWindow( this->caption.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight(),
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight());
// Set the OpenGL view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( 0, UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight(), 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glDisable( GL_DITHER );
Rendering:
if( this->redraw )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// a few DrawArrays
SDL_GL_SwapWindow( this->window );
}
Does anyone have any idea what could be causing this issue, and how to fix it?
EDIT: Some more research has pointed me to the following two questions:
https://superuser.com/questions/316738/what-happens-with-the-off-screen-front-buffers-in-windows-7-when-dwm-is-disabled
C++ OpenGL window only tracks background
However, this doesn't solve my problem since I'm already using Double Buffering.
I've found the solution to my problem. It's unlikely that anyone will experience the same issue that I was having, but you never know. Essentially a C# Window of size equal or larger than my application, was being created before. This window was hidden, however because XP has a global framebuffer instead of a composition, there was a conflict causing the corruption.
All in all, if you're having a similar issue, make sure there isn't another context.
I've looked at a ton of articles and SO questions about OpenGL not drawing, common mistakes, etc. This one is stumping me.
I've tried several different settings for glOrtho, different vertex positions, colors, etc., all to no avail.
I can confirm the OpenGL state is valid because the clear color is purple in the code (meaning the window is purple). gDEBugger is also confirming frames are being updated (so is Fraps).
Here is the code. Lines marked as "didn't help" were not there originally, and were things that I tried and failed.
QTWindow::QTWindow( )
{
// Enable mouse tracking
this->setMouseTracking(true);
}
void QTWindow::initializeGL()
{
// DEBUG
debug("Init'ing GL");
this->makeCurrent(); ///< Didn't help
this->resizeGL(0, 0); ///< Didn't help
glDisable(GL_CULL_FACE); ///< Didn't help
glClearColor(1, 0, 1, 0);
}
void QTWindow::paintGL()
{
// DEBUG
debug("Painting GL");
this->makeCurrent(); ///< Didn't help
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0,1,1);
glBegin(GL_TRIANGLES);
glVertex2f(500,100);
glVertex2f(100,500);
glVertex2f(0,0);
glEnd();
this->swapBuffers(); ///< Didn't help
}
void QTWindow::resizeGL(int width, int height)
{
// DEBUG
debug("Resizing GL");
this->makeCurrent(); ///< Didn't help
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1000, 0, 1000, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
The triangle is not being displayed at all, even with culling turned off. However, all three debug logs are called exactly how they should be.
What am I missing?
Try calling glViewport() function at the very beginning of the QTWindow::resizeGL() function:
glViewport(0, 0, width, height);
And don't ever call resizeGL() with width and height set to 0 ;) Besides that, it is not necessary for you to call resizeGL() directly as it is being called by Qt whenever the window is being resized.
You can remove all calls to the swapBuffers() function - it is being called internally by Qt.
The makeCurrent() function should be called before all other GL calls, so it is good that you have called it in initializeGL(), but you don't have to call it in the paintGL() function (unless paintGL() is being called from another thread, but I bet it isn't in your code).
The issue ended up being versions. The version string returned with glGetString(GL_VERSION) indicated 4.2 compatibility context was being used.
Since the triangle calls in the paintGL method were removed in 3.1 (if I recall correctly), it was obvious why they weren't drawing anything. Further, no errors were being thrown because it was in compat. mode.
Because I couldn't get the version down below 3.0 on the QGLWidget (due to the fact that QT requires 2.1, as I was informed on another message board), I set the version to 3.0 and tried using some 3.0 drawing calls and it ended up working.
I'm using win32 and opengl and I have a window set up with the projection at glOrtho of the window's coordinates. I have double buffering enabled, tested it with glGet as well. My program always seems to tear any primitives that I try to draw on it if it's being constantly translated.
Here is my OpenGL initialization function:
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, 640, 480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 640, 0, 480, 0, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDrawBuffer(GL_BACK);
glLoadIdentity();
And this is my rendering function, gMouseX and gMouseY are the coordinates of the mouse:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTranslatef(gMouseX, gMouseY, 0.0f);
glColor3f(0.5f, 0.5f, 0.5f);
glBegin(GL_TRIANGLES);
glVertex2f(0.0f, 128.0f);
glVertex2f(128.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glEnd();
SwapBuffers(hDC);
The same tearing problem occurs regardless of how often the rendering function runs. Is there something I'm doing wrong or missing here?
If you're just rendering one or two trianges, you're going to have an insanely high framerate (in the thousands of FPS probably), which means it's SwapBuffering like hell, which means you're probably always swapping during the screen refresh (even with double buffering on). Once your scene gets going with more content and the framerate falls to more realistic values, it should stop tearing. Alternatively, look in to enabling V-Sync, such as with wglSwapIntervalEXT on Windows.
This issue doesn't have to be strictly connected to VSync, as all people around the internet try to suggest. In my case the problem was caused by the way in which the window was initialized. I noticed, that getting rid off dwStyle=WS_POPUP solved the problem, but only partially because then the window wasn't in the fullscreen mode. What worked for me in the end was using SetWindowLong(hwnd, GWL_STYLE, 0); after creating the window. It basically clears the window style. So my code for initializing the window looks like that:
dwStyle=WS_POPUP; //Windows Style
ShowCursor(FALSE); //Hide Mouse Pointer
//Create the Window
hwnd= CreateWindowEx(NULL,
"GLClass",
appName,
dwStyle,
0, 0,
(long)windowWidth,
(long)windowHeight,
NULL,
NULL,
hInstance,
NULL);
SetWindowLong(hwnd, GWL_STYLE, 0);
After this modification all my problems with tearing and also not being able to PrintScreen, were solved. I didn't need to touch VSync anywhere.
When defining your win32 application window styles, don't include WS_POPUP
After debugging a problem where full screen would introduce screen tearing, I discovered the styles for full screen, after removing WS_POPUP it seemed to have stop tearing single handedly, without having to force the rendering loop to the refresh rate. WS_POPUP is known for being problematic, I guess. It would also block any full screen screenshots to complete white.
Tearing is caused by not synchronizing your updates with the monitor's vertical blanking interval. It's a bit hardware dependent in OpenGL (I think, not an expert), start with looking for glXWaitVideoSyncSGI. Googling "opengl sync to vblank" pays off too.
Try to putting a cap / limiting on the frame rate or yielding it probably (if you don't have a vsync):
Here is the pseudo code:
let tick equals new_tick
if tick is less than last_tick do
yield
done
calculate last_tick
Try the sleep function and setting it to one, so to yield:
Sleep(1);
Also remember limiting or capping frame rate is not that advisable as there is certain functions that are really meant for reducing frame calculations.