I am trying to develop an application with Qt 5.5 and OpenGL. The basic work of the application will be to load simple objects, modify their positions in a scene and save them together with other attributes (material, name, parents/child relations etc...).
The only thing I am struggling about for a week now is that I really don't know how I should take on the problem of synchronizing data. Let's say I have some kind of SceneGraph class which takes care of all SceneObjects. Those SceneGraphs should be rendered in a SceneView-Widget which can be used to modify it's Objects via transformations. Now how would I tell every SceneView that an Object changed it's position?
I thought of the Model/View architecture for a moment but I am not really sure how this implementation should look like.
What would be the best way to handle Objects like that in different Windows/Widgets but still have one single piece of data?
SceneObject:
Holds the mesh-information (verticies, uvs, etc..)
Has a name (QString)
Has a material
Has a transform storing position, rotation and scaling information
(Important: these datatypes should be synchronized in all views)
SceneGraph:
Contains different SceneObjects and is passed to SceneViews
SceneView:
The QWidget responsible for drawing the Scene correctly in any QWindow.
Has it's own camera to move around.
Handles UserInput and allows transformation of SceneObjects.
You could use the signal and slot to observe position updates of SceneObjects and process them in SceneView.
Related
This question and answer, in Oct 2015, implies it is possible to change Qt3D mesh and update it:
Question
I want to use Qt3d in a situation that involves dynamic runtime
changes of geometric data on the application side.
What is the best way to dynamically change a mesh for an entity?
I'd rather do all this on the C++ side, but QMesh doesn't seem to
provide an API for changing the mesh data.
I looked at some other examples of making a custom QAbstractMesh class
and QAbstractMeshFunctor. It looks like I could possibly make a custom
mesh type to do what I need but I have a question. If I keep a
reference to the QMeshDataPtr that I make from the functor, can I
simply modify the mesh data whenever I want and the entities that
reference it will update automatically?
Answer
The API for this has changed a little in 5.6. The geometric data is
now contained in one or more QBuffer objects and is referenced by one
or more QAttributes that describe the data layout in the buffers. The
QAttributes are rendered by adding them to a QGeometryRenderer
component.
You can either update the above objects on the main thread and call
update() or as before you can also use a functor to have the backend
generate the dynamic data.
Now, my question is about calling update(). Exactly what section of Qt3D API is referred to?
There is a test available at Qt installation directory on my Linux machine:
/home/{user}/Qt5.12.6/5.12.6/Src/qt3d/tests/manual/custom-mesh-update-data-cpp/
which I discovered by following this link when searching Google for qt3d mesh update keywords.
The above test is using Qt3DRender::QBuffer API to update mesh data:
void QBuffer::updateData(int offset, const QByteArray &bytes)
Updates the data by replacing it with bytes at offset.
Note: This function can be invoked via the meta-object system and from QML. See Q_INVOKABLE.
Code looks like this:
Qt3DRender::QBuffer *vertexDataBuffer;
// ...
QByteArray updateData;
// ...
vertexDataBuffer->updateData(pos,updateData);
// ...
I've just added a second QGLWidget to my app (both QGLWidgets inherit from the same class). While the first one still works as expected, the second one raises a GL_OUT_OF_MEMORY, in the glDrawArrays() method of my paintGL()method, whatever the data which filled the buffers
I manage to solve this in adding the first QGLWidget as a "share widget" when creating the second one:
http://doc.qt.io/qt-4.8/qglwidget.html#QGLWidget
However, now, it seems that the two QGLWidgets are linked/synchronized (especially the camera but only when switching to a widget to another).
My question is thus more general as I would like to know how I should handle my two QGLWidgets, to avoid conflicts, knowing that they only share the same shaders code (vertex and fragment) but no data (they do not write/read the same buffers).
EDIT: I use PyQt4
The problem comes to the fact that when I switch from a window to another (my GLWidgets being on different windows), the paintGL() method is called and, as the context is share, they also share the same camera matrices. Thus, at the beginning of each paintGL() method I call my updateCamera() method.
Both can create objects dynamically.
When should Loader be preferred over Qt.createQmlObject and vice versa in QML?
The Loader can be regarded as a placeholder for a particular object. It also gives you the ability to reference the underlying object through the Loader's id.
Qt.createQmlObject is generally more powerful than a Loader, because you can instantiate as many objects as you want, and also it doesn't have the overhead of the Loader. But you have to take care to keep track of what you create in order to be able to reference it.
The other functions Qt.createComponent() and then createObject() offer similar advantages, plus the possibility to pass properties to be used in the object's creation instead of setting them only after it has been created.
I personally see very little point in Loader and rarely use it, if at all in production code. IMO it was introduced for the sake of the "non-programmer" much like most of the recent development, such as the new designer and QML .ui files, which I find kind of annoying, but it is understandable - trying to increase adoption by non-programmers.
I have a lot of 2D, time-variant data (aka a movie) that I'd like to visualise inside a Qt interface. The idea is that the results can be viewed as a movie, browsed using a time-slider and then individual data points should be selectable to get more information about that point. (The data being shown is generated from simulations, and then converted to RGB through some colormap, so I'm not really looking for a component that plays mp4)
I have some experience using a QGraphicsScene, which makes it easy to get the cursor location & react to mouse events. But is it suitable for video? Or am I better off with some kind of QImage directly on a widget?
Ok, so it works well in PyQt, not so well in PySide.
I'm using a QPixmap wrapped in a QPixmapItem that gets added to the scene. To update the frame, I change the contents of the pixmap object and call update() on the scene.
Performance is good enough for video (although I don't need high frame rates for this project).
In PySide I ran into weird issues when I used more than 1 pixmap item, in PyQt it works just fine.
I'm creating a CAD-like app (Qt-based), it will be a multiple document interface and each document will contain about 5 viewports (derived from QGLWidget). As such I need my flat shader to be shared across the entire application, and then the 3D assets (models stored as VBOs) to be shared across each document i.e. the 5 viewports.
I thought as long as I shared around the shader program and VBO GLuint addresses all will automagickly work - it doesn't. I think because each viewport/context has it's own address space on the graphics card, if anyone knows better please inform!
I would like to have the shader compiled on application start, but this is proving difficult as I need a valid QGLWidget to get OpenGL into a valid state beforehand. But as I need to share the QGLWidgets (through their constructor) to have them share resources, one needs to be created and shown before the others can be instantiated. But this is highly impractical as multiple views to be shown at once to the user.
This must be easier than I'm making out because it's hardly groundbreaking stuff, but I am really struggling - can anyone point me in the right direction?
Thanks, Cam
Here's what usual CAD/MDI applications are doing:
they create a shared context that serves for well, sharing resources.
they use wglShareLists when creating a new OpenGL rendering context for giving access to the resource ids of the shared context.
wglShareLists can be used for sharing VBOs, textures, shaders, etc, not only display lists (sharing DLs is the legacy usage, hence the function name).
I don't remember if you need to create resources with the shared context or if you can create them on any contexts.
If you're not on windows, see glXCreateContext. That should put you on track.
Edit:
I've looked at Qt, it looks like it's abstracted with member QGLContext::create.