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.
Related
I'm using QML, and wanted to run custom OpenGL code. I created a custom Widget in C++ (extending QQuickItem) and overrided the paint function().
When I run my application, the console prints
QSGContext::initialize: depth buffer support missing, expect rendering errors
QSGContext::initialize: stencil buffer support missing, expect rendering errors
And just as it predicted, I do get rendering errors. I'll use a spider model as an example. Here's what it should like
And here's what I'm getting
I also don't know exactly how to describe it, but basically the opposite face (which should be blocked by the front face) is showing through as I rotate it.
I've managed to get rid of the depth buffer error with this:
void MyGLWidget::handleWindowChanged(QQuickWindow *win)
{
if (win) {
connect(win, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection);
connect(win, SIGNAL(sceneGraphInvalidated()), this, SLOT(cleanup()), Qt::DirectConnection);
win->setClearBeforeRendering(false);
QSurfaceFormat glFormat;
glFormat.setVersion(3,2);
glFormat.setProfile(QSurfaceFormat::CoreProfile);
/*I'm showing everything for context, but this is the key line*/
glFormat.setDepthBufferSize(1);
win->setFormat(glFormat);
}
}
So now I'm only getting the stencil error, but that causes a different issue. One side is completely black, and doesn't show any of the lighting.
Some other background info: I'm displaying a QQuickView. My OpenGLWidget is imported into QML and embedded like so:
MyGLWidget {
id: glWidget
}
In the paint() of my renderer, I am calling glEnable(GL_DEPTH_TEST) and glEnable(GL_STENCIL_TEST) at the top, but that doesn't seem to do anything. Maybe I'm calling that in the wrong context? I don't know where else I would be able to call it, however.
As it turns out, all of my models (including the spider) had incorrect vertex normals, hence the shading issues. I should have checked them out in other rendering software.
glFormat.setDepthBufferSize(1) was the real fix
Try
glDepthMask(GL_TRUE);
// your paintings here
glDepthMask(GL_FALSE);
See also Scene Graph and Rendering.
i'm continue my dialog with openGL and c++ and for a now i want to make "scenes", that will change each other. for example screen with button "go next", i push button and then begin game.
What is the best approach with openGL in c++ for this ? The main question is what make with glut initialization commands like :
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(screenWidth, screenHeight);
glutInitWindowPosition(0,0);
glutCreateWindow("Puzzle quest!");
// Registration
glutDisplayFunc(Draw);
glutIdleFunc(Draw);
Is i need to implement this method in both classes, or only in one, and then only "show start button/ hide game functionality, hide start button/ show game functionality+start timer" ?
I do not mess with screen settings during scene/mode changes. Screen setings is changed on resize of the OpenGL window not on some button event...
You have to write your visualization and UI logic stuff dependent on some variables for example:
enum _game_screens_enum
{
_game_screen_main_menu=0,
_game_screen_game,
_game_screen_game_over,
_game_screen_help,
_game_screen_intro,
_game_screen_redefine_keys,
_game_screen_high_score,
_game_screen_exit,
};
int screen=_game_screen_main_menu;
Now in draw,update and UI handling functions just add appropriate ifs for example:
void draw()
{
if (screen==_game_screen_main_menu)
{
// draw main menu ...
}
else if (screen==_game_screen_game)
{
// draw in game screen stuff...
}
else ...
}
And that is it ...
Are you looking for a fade effect or some sort of transition where they are blended? Fade effect should be easy if using alpha channel... enable blend... draw black quad in front of everything as its alpha value increases from 0 to 1 over whatever time frame you want the fade to occur. The fade in would be the opposite. Not sure about the blending scenes effect... maybe accum buffer, or read pixels and then draw pixels if you can change alpha values.
Otherwise, glutDisplayFunc is the correct way to switch between scenes/drawing functions.
Try just fading effect, it could be of great help.
You should only initialize glut once.
Normally, the display and idle callbacks would do different things depending on what state you're in.
On a high level:
void idle()
{
if (showingMenu)
menu.idle();
else
currentScene.idle();
}
You could do it by switching functions, but I think that makes debugging more difficult.
(You should probably not use the same function for drawing and idling, though.)
I am trying to rotate a 3d object but it doesnt update when applying transforms in a for loop.
The object jumps to the last position.
How does one update a 3d object's position in a sequence of updates if it wont update in a for loop?
Just calling glTranslate, glRotate or such won't change things on the screen. Why? Because OpenGL is a plain drawing API, not a scene graph. All it knows about are points, lines and triangles that draws to a pixel framebuffer. That's it. You want to change something on the screen, you must redraw it, i.e. clear the picture, and draw it again, with the changes.
BTW: You should not use a dedicated loop to implement animations (neither for, nor while, nor do while). Instead perform animation in the idle handler and issue a redraw event.
I reckon you have a wrong understanding what OpenGL does for you.
I'll try to outline:
- Send vertex data to the GPU (once)
(this does only specify the (standard) shape of the object)
- Create matrices to rotate, translate or transform the object (per update)
- Send the matrices to the shader (per update)
(The shader then calculates the screen position using the original
vertex position and the transformation matrix)
- Tell OpenGL to draw the bound vertices (per update)
Imagine programming with OpenGL like being a web client - only specifying the request (changing the matrix and binding stuff) is not enough, you need to explicitly send the request (send the transformation data and tell OpenGL to draw) to receive the answer (having objects on the screen.)
It is possible to draw an animation from a loop.
for ( ...) {
edit_transformation();
draw();
glFlush(); // maybe glutSwapBuffers() if you use GLUT
usleep(100); // not standard C, bad
}
You draw, you flush/swap to make sure that what you just drew is sent to the screen, and you sleep.
However, it is not recommended to do this in an interactive application. The main reason is that while you are in this loop, nothing else can run. Your application will be unresponsive.
That's why window systems are event-based. Every few miliseconds, the window system pings your app so you can update your state, for example do animation. This is the idle function. When the state of your program changed, you tell the window system that you would like to draw again. It is then up the the window system to call your display function. You do your OpenGL calls when the system tells you to.
If you use GLUT for communicating with the window system, this looks like the code below. Other libraries like GLFW have equivalent functions.
int main() {
... // Create window, set everything up.
glutIdleFunc(update); // Register idle function
glutDisplayFunc(display); // Register display function
glutMainLoop(); // The window system is in charge from here on.
}
void update() {
edit_transformation(); // Update your models
glutPostRedisplay(); // Tell the window system that something changed.
}
void display() {
draw(); // Your OpenGL code here.
glFlush(); // or glutSwapBuffers();
}
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 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.