The new Animation Framework in Qt 4.6+ is based on QTimeLine which has 'void setUpdateInterval(int interval)' public function. Based on QTimeLine as well, QGraphicsItemAnimation could access this function, but the new animation framework classes (e.g. QPropertyAnimation) can't! Is the animation framework locked to the about 60 updates per second which corresponds to a pixel-by-pixel transition of 60 pixels on screen per second only (for QPropertyAnimation animating position property) or is there a way to increase this without reimplementing everything?
I think there are some hardware limitations and also some limits with how the OS/Qt handles some of the painting. The Qt Main Loop has something to do with it also.
In my experience, double buffering and repainting only the regions that need to be repainted will give you the smoother animations that you are looking for. Also make sure that your graphics are close to the size that you are actually painting them. Increasing the interval of refresh won't help most monitors because they don't refresh faster than 60 Hz.
Here is a link that may be helpful.
Qt works hard to optimize and get the graphics to look nice on a lot of platforms, and I know that as they are preparing for Qt 5, that there are some more changes to how the raster engine works.
I've also seen a demonstration similar to what is discussed here in person where they showed the frames per seconds of refreshes they could get with painting tiles in a game. Here is a link to a video discussing it. It goes into tweaking the performance of Qt for a particular game implementation, and what helps and what doesn't.
Here's my solution for Qt 4.8:
// You need qt source code to access QUnifiedTimer for QAnimationDriver
// Alternatively, copy'n'paste only the declaration for QUnifiedTimer class.
#include <qt/src/corelib/animation/qabstractanimation_p.h>
...
// In the animation thread, set the update timing interval.
// The smaller the interval, the more updates and more CPU consumption.
int animationTimingInterval = update_interval_in_msecs_u_want;
QUnifiedTimer::instance()->setTimingInterval(animationTimingInterval);
Related
This is one of the things that still confuses me about QML / QtQuick: How shall I implement a simple game like pong that uses a loop?
I googled a bit and looked through similar questions here but none of them addressed the following:
I want to create a simple game like pong that uses a loop. In this loop first all the objects are updated (in case of pong the ball and the bars) and then everything is rendered. For the rendering part I think QML will do the job once all the properties are set.
I want to use QML and QtQick and not QGraphicsScene.
I have seen some examples that just use a timer and then adjust the properties, for example this one: https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml But is this really the way to do it. In this case you would have the loop that updates the QML properties and the timer as well and I don't understand how the work together.
Also there are some game engines that use QML. I would like to know how to use QML within a game loop. For example could you write the game loop in C++ and then have QML on top of it? Or what is the recommended way of doing it. Sadly I could not find this in any of the Qt documentation.
I had a similar question when I first started with Qt and got the same answers you're getting (which are correct). It's a different way of thinking than if you had come from using say, SDL.
I want to add an approach that lets you have some control over the updates. It's been a while since someone shared this with me, but from what I remember, it has something to do with ensuring a consistent update frequency.
Regardless of whether or not it's an improvement over just using a simple timer or not, having some actual code will help get you started. In addition, having the delta (to calculate the position of the ball and paddles) is something you'd have to do yourself, which this code already does for you.
Here's the meat of GameTimer:
void GameTimer::doUpdate()
{
// Update by constant amount each loop until we've used the time elapsed since the last frame.
static const qreal delta = 1.0 / mFps;
// In seconds.
qreal secondsSinceLastUpdate = mElapsedTimer.restart() * 0.001;
mRemainder += secondsSinceLastUpdate;
while (mRemainder > 0) {
emit updated(delta);
mDateTime = dateFromSimulatedTime();
mRemainder -= delta;
mSimulatedTime += delta;
}
}
It's used in C++ like this:
void DirectPather::timerUpdated(qreal delta)
{
QHashIterator<QuickEntity*, DirectPathData> it(mData);
while (it.hasNext()) {
it.next();
QuickEntity *entity = it.key();
DirectPathData pathData = it.value();
if (mSteeringAgent->steerTo(entity, pathData.targetPos, delta)) {
mData.remove(entity);
}
}
}
Since this example (quickpather) is QML-based, it has a complex setter for connecting to the timer. If you don't need stuff to be in QML like the example is, you can just create the timer in C++ and connect to its update signal directly wherever necessary:
connect(mTimer, &GameTimer::updated, foo, &MyGameObject::update);
// ...
connect(mTimer, &GameTimer::updated, bar, &MyOtherGameObject::update);
The delta is in seconds (1.0 == one second).
You can take anything you need from the example to help you get started with your game.
To answer some of your questions directly:
I have seen some examples that just use a timer and then adjust the properties, for example this one: https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml But is this really the way to do it. In this case you would have the loop that updates the QML properties and the timer as well and I don't understand how the work together.
I wouldn't recommend doing the logic in QML/JavaScript as this game does. C++ is better suited to this (aka faster) than JavaScript. Things like scripting are well suited for JavaScript though.
Also there are some game engines that use QML. I would like to know how to use QML within a game loop. For example could you write the game loop in C++ and then have QML on top of it? Or what is the recommended way of doing it. Sadly I could not find this in any of the Qt documentation.
My "engine" uses C++ for all of the logic (except scripts, which are kept relatively small) and QML for the GUI and also the entities (animations, sprites, etc.).
I don't think there's any documentation about this exact topic (games written in C++ with QML frontends), but there are some QML-based game examples:
http://doc.qt.io/qt-5/qtquick-demos-maroon-example.html
http://doc.qt.io/qt-5/qtquick-demos-samegame-example.html
You don't need a game loop in QML, the whole thing is event driven and powered by an underlying event loop anyway.
You can readily tap into that, use timers, signals, animations and what not out of the box.
Game loop are locking in nature. And in QML you can only use the main thread. And thou shalt not lock the main thread - it has to spin or your app will stop responding.
I am using Qt to build a ray tracer with GUI. The ideal effect is to paint a pixel immediately after computing the RGB value of that pixel, as in most professional renderer. But I find out that my tracer could only display the entire rendered image after the loop below:
for(int i=0; i<row; ++i)
for(int j=0; j<column; ++j) {
compute pixel value;
painter.drawPoint(i, j);
}
I am drawing to the central widget of the mainwindow. I reimplemented QWidget paintEvent function and put the loop above in this function. It seems that paintEvent only display the whole screen after being executed once and in the process it gives me this:
I don't know if this is just how paintEvent works or I am doing something wrong.
Anyway, it cannot display pixel in real time. And this is very unsatisfying for an interactive tracer. I hope you guys can provide some explanations and/or solutions. A million thanks!
The OS is giving you the "not responsive" alert because you are doing all the calculation in the GUI thread.
This means that the event loop is stuck at doing your havy calculations and can't process other events.
On a Windows system, this means it won't react to Windows messages. That's why after a certain time the OS tells you that the application is not responsive.
You should perform your heavy calculations in a separated thread, pass the results to the GUI thread when you want to update the GUI and let the GUI thread perform the rendering.
Apart from that, you should consider painting to a backbuffer, as suggested in the comments (although please note that QPixmap is not thread safe).
QPainter::drawPoint() is very slow and it is an unefficient way to paint the whole central area.
Please have a look at the documentation here for more details on how to keep the GUI responsive.
The problem mainly is determined in the title. I tried out the Qt's example (2dpainting) and noticed, that the same code consumes more CPU power if I try to draw on QGLWidget and less if I try to draw simply on QWidget. I thought that the QGLWidget should be faster. And one more interesting phenomenon: In QGLWidget the antialiasing hint seems to be ignored.
OpenGL version: 3.3.0
So why is that?
Firstly, note this text at the bottom of the documentation that you link to:
The example shows the same painting operations performed at the same
time in a Widget and a GLWidget. The quality and speed of rendering in
the GLWidget depends on the level of support for multisampling and
hardware acceleration that your system's OpenGL driver provides. If
support for either of these is lacking, the driver may fall back on a
software renderer that may trade quality for speed.
Putting that aside, hardware rendering is not always guaranteed to be faster than software rendering; it all depends upon what the renderer is being asked to do.
An example of where software can exceed hardware is if the goal of the item being rendered is constantly changing. So, if you have a drawing program that draws a line being created by the mouse being constantly moved and it is implemented by adding points to a painter path that is drawn every frame, a hardware renderer will be subject to constant pipeline stalls as new points are added to the painter path. Setting up the graphics pipeline from a stall takes time, which is not something a software renderer has to deal with.
In the 2dPainting example you ask about, the helper class, which performs the paint calls, is doing a lot of unnecessary work; saving the painter state; setting the pen / brush; rotating the painter; restoring the brush. All of this is a bigger overhead in hardware than software. To really see hardware rendering outperform software, pre-calculating the objects' positions outside of the render loop (paint function) and then doing nothing put actually rendering in the paint function is likely to display a noticeable difference here.
Finally, regarding anti-aliasing, the documentation that you linked to states: "the QGLWidget will also use anti-aliasing if the required extensions are supported by your system's OpenGL driver"
I'm porting over a OpenGL application from a win32 project to a Qt project.
In the win32 project I simply had a mainloop that kept executing the next frame as soon as the previous was finished.
In the tutorials I find about Qt and OpenGL, they're using timers to control the update of the scene. However, I'd like to render as many frames as frequent as possible - how to do that?
However, I'd like to render as many frames as frequent as possible - how to do that?
Not with Qt. Qt takes full control of the event loop thus not giving you any means of directly performing idle operations. The standard way to perform idle operations in Qt is to use a QTime with a timeout of 0.
Another possibility was using a second thread just for OpenGL operations. However to work reliably you should create a dedicated OpenGL context for that one thread.
Qt simply is not the right toolkit for those kinds of program where the primary task of the main loop is rendering pictures and input and event management are only secondary.
Try calling update() at the end of your paint handler.
That will queue up another repaint event.
The intrinsic principles of Qt and OpenGL are not about rendering as soon as possible, but it's rendering whenever we want (huge difference).
You have to ask for the system max framerate (search for samples in OpenGL i'm sorry I don't rememember where I saw that). Once you've done that, just create a timer based on this max framerate, so you'll get what you want.
However, I'd like to render as many frames as frequent as possible - how to do that?
Use QTimer with zero interval.
I am trying to develop am map application for scientific purposes at my university. Therefor I got access to a lot of tiles (256x256). I can access them and save them to an QImage in a seperate QThread. My Problem is, how can I actually manage to load the QImage into a texture within the seperate QThread (not the GUI main thread)? Or even better give me a Tipp how to approach this problem.
I though about multithreaded OpenGL but I also require OpenGL picking and I did not fall over anything usefull for that.#
Point me to any usefully example code if you feel like, I am thankfull for everything that compiles on Linux :)
Note1: I am using event based rendering, so only if the scene changes it gets redrawn.
Note2: OSG is NOT an option, it's far to heavy for that purpose, a leightweight approach is needed.
Note3: The Application is entirely written in C++
Thanks for any reply.
P.S. be patient, I am not that adavanced as this Topic may (or may not) suggest.
OpenGL is not thread-safe. You can only use one GL context in one thread at a time. Depending on OS you also have to explicitely give up on the context handle in one thread to use it in another.
You cannot speed up the texture loading by threading given that the bottleneck here is the bandwidth to the graphics card.
Let your delivery thread(s) that load the tiles fill up a ring buffer. The GL thread feeds from the ring buffer. With two mutexes it is easy to control the ring buffer to make this thread-safe operation.
That would be my suggestion.
Two tricks I use to speed things up:
pixel buffer objects: map GPU memory so the loading thread can write directly to gpu;
sync objects: with a sync object I know when the texture is really ready to be used (glTexImage2D with PBO is async so there is no guarantee the texture is ready to be binded, ie, when binding a texture, it blocks if DMA didn't finish updating texture data)