drawing with QOpenGLWidget
-
Hi,
I am using QOpenGLWidget with a QTtimer and unable to repaint the screen. I tried calling repaint() and update() and paintGL() directly.
https://doc.qt.io/qt-5/qopenglwidget.html#paintGL
What is the recommend approach to use when repainting using a timer?
Thanks,
Mohsin -
So actually repaint() and update() works fine being called from the timer. I didn't realize I had the animation change rate (velocity value) set so slow (smh...) that I didn't notice the change visually.
Also when I minimize and maximize the window, the change is a lot more which made me think it was not repainting in the normal case. Need to dig into this still...
connect(&myTimer, SIGNAL(timeout()),
this, SLOT(update()));myTimer.start(0);
namespace Rendering
{
Renderer : public QOpenGLWidget, protected QOpenGLFunctions
{
static const uint NUM_MAX_GEOMETRIES = 2;
Geometry geometries[NUM_MAX_GEOMETRIES];
uint numGeometries;
static const uint NUM_MAX_RENDERABLES = 3;
Renderable renderables[NUM_MAX_RENDERABLES];
uint numRenderables;
static const uint MAX_BUFFER_SIZE = 1024;
GLuint vertexBufferID;
GLuint indexBufferID;
static const uint MAX_VERTS = 10;protected: void initializeGL(); void paintEvent(); void paintGL(); public: bool initialize(); bool shutdown(); Geometry* addGeometry( Math::Vector3D* vertices, uint numVerts, ushort* indices, uint numIndices, GLenum renderMode = GL_TRIANGLES); Renderable* addRenderable(Geometry* geometry); void renderScene(); };
}
namespace Rendering
{
bool Renderer::initialize()
{
vertexBufferID = -1;
indexBufferID = -1;numGeometries = 0; numRenderables = 0; show(); return true; } void Renderer::initializeGL() { initializeOpenGLFunctions(); glClearColor(0, 0, 0, 1); glGenBuffers(1, &vertexBufferID); glGenBuffers(1, &indexBufferID); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); glBufferData(GL_ARRAY_BUFFER, MAX_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); } bool Renderer::shutdown() { if (vertexBufferID != -1) glDeleteBuffers(1, &vertexBufferID); if (indexBufferID != -1) glDeleteBuffers(1, &indexBufferID); return true; } Geometry* Renderer::addGeometry( Math::Vector3D* vertices, uint numVerts, ushort* indices, uint numIndices, GLenum renderMode) { assert(numGeometries != NUM_MAX_GEOMETRIES); Geometry& g = geometries[numGeometries++]; g.vertices = vertices; g.numVerts = numVerts; g.indices = indices; g.numIndices = numIndices; g.renderMode = renderMode; return &g; } Renderable* Renderer::addRenderable(Geometry* geometry) { assert(numRenderables != NUM_MAX_RENDERABLES); Renderable& r = renderables[numRenderables++]; r.what = geometry; return &r; } void Renderer::renderScene() { update(); } void Renderer::paintEvent() { // do nothing here } void Renderer::paintGL() { glClear(GL_COLOR_BUFFER_BIT); Vector3D transformedVerts[MAX_VERTS]; for (uint i = 0; i < numRenderables; i++) { const Renderable& r = renderables[i]; //Indices glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(ushort) * r.what->numIndices, r.what->indices); //Vertices for (uint j = 0; j < r.what->numVerts; j++) transformedVerts[j] = r.where * r.what->vertices[j]; glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector3D) * r.what->numVerts, transformedVerts); glDrawElements(r.what->renderMode, r.what->numIndices, GL_UNSIGNED_SHORT, 0); } }
}
-
Hi,
What is your implementation ?
Did you use any example as a base ? -
@MohsinM. When you say "unable to repaint the screen", what actual symptom are you seeing? What are you doing?
That said, it's pretty much never correct to call paintGL directly. Just call update() and Qt will invoke paintGL at the appropriate time. start with a simple glClear() after a glClearColor() so you can see that your code is being properly invoked so you can differentiate between a bug in how you are using QOpenGLWidget vs a bug in the actual openGL drawing code you want to use.
How are you using the QTimer? Does it trigger when you expect if you just attach it to a slot that outputs "Hello World" and ignore the OpenGL part of things?
-
So actually repaint() and update() works fine being called from the timer. I didn't realize I had the animation change rate (velocity value) set so slow (smh...) that I didn't notice the change visually.
Also when I minimize and maximize the window, the change is a lot more which made me think it was not repainting in the normal case. Need to dig into this still...
connect(&myTimer, SIGNAL(timeout()),
this, SLOT(update()));myTimer.start(0);
namespace Rendering
{
Renderer : public QOpenGLWidget, protected QOpenGLFunctions
{
static const uint NUM_MAX_GEOMETRIES = 2;
Geometry geometries[NUM_MAX_GEOMETRIES];
uint numGeometries;
static const uint NUM_MAX_RENDERABLES = 3;
Renderable renderables[NUM_MAX_RENDERABLES];
uint numRenderables;
static const uint MAX_BUFFER_SIZE = 1024;
GLuint vertexBufferID;
GLuint indexBufferID;
static const uint MAX_VERTS = 10;protected: void initializeGL(); void paintEvent(); void paintGL(); public: bool initialize(); bool shutdown(); Geometry* addGeometry( Math::Vector3D* vertices, uint numVerts, ushort* indices, uint numIndices, GLenum renderMode = GL_TRIANGLES); Renderable* addRenderable(Geometry* geometry); void renderScene(); };
}
namespace Rendering
{
bool Renderer::initialize()
{
vertexBufferID = -1;
indexBufferID = -1;numGeometries = 0; numRenderables = 0; show(); return true; } void Renderer::initializeGL() { initializeOpenGLFunctions(); glClearColor(0, 0, 0, 1); glGenBuffers(1, &vertexBufferID); glGenBuffers(1, &indexBufferID); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); glBufferData(GL_ARRAY_BUFFER, MAX_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); } bool Renderer::shutdown() { if (vertexBufferID != -1) glDeleteBuffers(1, &vertexBufferID); if (indexBufferID != -1) glDeleteBuffers(1, &indexBufferID); return true; } Geometry* Renderer::addGeometry( Math::Vector3D* vertices, uint numVerts, ushort* indices, uint numIndices, GLenum renderMode) { assert(numGeometries != NUM_MAX_GEOMETRIES); Geometry& g = geometries[numGeometries++]; g.vertices = vertices; g.numVerts = numVerts; g.indices = indices; g.numIndices = numIndices; g.renderMode = renderMode; return &g; } Renderable* Renderer::addRenderable(Geometry* geometry) { assert(numRenderables != NUM_MAX_RENDERABLES); Renderable& r = renderables[numRenderables++]; r.what = geometry; return &r; } void Renderer::renderScene() { update(); } void Renderer::paintEvent() { // do nothing here } void Renderer::paintGL() { glClear(GL_COLOR_BUFFER_BIT); Vector3D transformedVerts[MAX_VERTS]; for (uint i = 0; i < numRenderables; i++) { const Renderable& r = renderables[i]; //Indices glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(ushort) * r.what->numIndices, r.what->indices); //Vertices for (uint j = 0; j < r.what->numVerts; j++) transformedVerts[j] = r.where * r.what->vertices[j]; glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector3D) * r.what->numVerts, transformedVerts); glDrawElements(r.what->renderMode, r.what->numIndices, GL_UNSIGNED_SHORT, 0); } }
}