Discussion:
QOpenGLWidget and text
(too old to reply)
Matthew Woehlke
2015-04-01 13:42:06 UTC
Permalink
I've been working on porting a Qt4 GL application to Qt5, using the new
QOpenGL classes instead of the old and deprecated QGL classes.

Some of it was really easy. Some of it is requiring MASSIVE amounts of work.

I refer specifically to the removal of the text rendering methods. Since
these are removed, what is the easiest way to go about drawing
non-scaled, billboarded text in a GL scene? (Note: I am on Qt 5.4 at
present; no Qt3D.)

If I go the route of pre-rendering the text into a QImage, what is the
easiest way, using only the modern QOpenGL classes (since there is no
longer bindTexture either), to get that into an OpenGL texture?

Actually using this stuff in anger, I am finding myself less than
convinced that the new class is an improvement... implicit context
sharing is nice, but the loss of convenience methods is really, really
painful. (And I'll include qgl[Clear]Color in that list...)
--
Matthew
Giuseppe D'Angelo
2015-04-01 14:28:04 UTC
Permalink
Post by Matthew Woehlke
If I go the route of pre-rendering the text into a QImage, what is the
easiest way, using only the modern QOpenGL classes (since there is no
longer bindTexture either), to get that into an OpenGL texture?
A rough game plan is this:

* Create a QImage of a suitable size (depending on your needs)
* Fill it with color or trasparency
* Use QPainter to draw on it (using a font of a suitable size)
* Create/upload it into a QOpenGLTexture
* Create a suitable set of VBOs using QOpenGLBuffer containing vertex
coordinates as well as texture coordinates for a rectangle (you'll need
to triangulate it!)
* Optionally create an IBO using QOpenGLBuffer containing indexes for
your vertexes
* Create a suitable shader program by combining a vertex shader (which
may optionally do the billboarding, unless you generated vertex
coordinates in the right positions) and a fragment shader (which samples
from the texture using the interpolated texture coordinates which are
emitted by the vertex shader) and bind it
* Create a QOpenGLVertexArrayObject and bind it
* Enable and configure the attribute arrays on your shader program by
binding the VBOs and specifying their format
* Optionally bind the IBO into the VAO

(setup complete)

To draw:

* Bind the VAO
* Bind (use) the shader program
* Get the texture into the program, f.i. by binding the texture +
setting the texture unit index as a uniform value on the right uniform
sampler2D object in your program
* Draw the quad via glDrawArrays / glDrawElements (depending if you used
an IBO or not)

Depending on your needs you may need alpha blending enabled,
alpha-discard in your fragment shader, as well as alpha-to-coverage to
smooth antialiased edges.

Isn't Modern OpenGL lovely? ;)

Cheers,
--
Giuseppe D'Angelo | ***@kdab.com | Software Engineer
KDAB (UK) Ltd., a KDAB Group company | Tel: UK +44-1625-809908
KDAB - The Qt Experts
Matthew Woehlke
2015-04-01 18:39:35 UTC
Permalink
Post by Matthew Woehlke
If I go the route of pre-rendering the text into a QImage, what is the
easiest way, using only the modern QOpenGL classes (since there is no
longer bindTexture either), to get that into an OpenGL texture?
[snip really lengthy process]
Isn't Modern OpenGL lovely? ;)
Can someone please explain to me how this is an improvement over having
a renderText() method? (Being serious... see also previous comment; I
don't see how losing the convenience functions of QGLWidget is an
improvement...)

I have another application that needs to support Qt 5.3 that is
currently using QGLWidget. After my experiences with QOpenGLWidget it is
clear that I would be rather insane to try to port it.
--
Matthew
Till Oliver Knoll
2015-04-02 17:45:00 UTC
Permalink
Post by Matthew Woehlke
Post by Matthew Woehlke
If I go the route of pre-rendering the text into a QImage, what is the
easiest way, using only the modern QOpenGL classes (since there is no
longer bindTexture either), to get that into an OpenGL texture?
[snip really lengthy process]
Isn't Modern OpenGL lovely? ;)
Can someone please explain to me how this is an improvement over having
a renderText() method?
I only speak for myself, but introducing a new API - and QOpenGL is just that, even when meant to replace an existing one - there is always the chance to drop "misplaced functionality".

IMHO the sole QOpenGLWidget's purpose is to "provide system resources to display raw OpenGL". And let you share those system resources (OpenGL Context) with other GL widgets. Not more, not less.

Sure, having a "drawText" function is /very/ convenient. Likely a "bindTexture" function. But what's next? A "drawButton"? "drawBitmap"? In a Widget?!

Surely that's not the right place.

In fact, someone already pointed out that you can use a QPainter and "draw over the OpenGL rendered scene".

In fact, you might be interested in this example:

http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html

Not only can you draw text "over OpenGL", but /anything/ that QML has to over - even animated!

That's the way to draw "over OpenGL" - not with a restricted "drawText" convenience method which happened to be placed in some random API (QGLWidget) over a decade ago ;)

And once you got used to "Modern OpenGL" (in case you haven't yet), be prepared to discard everything and learn from scratch the new "Vulkan" API being in work with the Khronos group - we'll see what that brings us ("closer to the hardware" - read: "Bring Your Own Graphic Card Driver" - BYOGCD).

;)

Cheers,
Oliver
Matthew Woehlke
2015-04-03 15:26:01 UTC
Permalink
Post by Till Oliver Knoll
Post by Matthew Woehlke
Post by Matthew Woehlke
If I go the route of pre-rendering the text into a QImage, what is the
easiest way, using only the modern QOpenGL classes (since there is no
longer bindTexture either), to get that into an OpenGL texture?
[snip really lengthy process]
Isn't Modern OpenGL lovely? ;)
Can someone please explain to me how this is an improvement over having
a renderText() method?
Sure, having a "drawText" function is /very/ convenient. Likely a
"bindTexture" function. But what's next? A "drawButton"? "drawBitmap"?
In a Widget?!
Yes. And why not? QGraphicsView already does this sort of thing. (Well,
it wouldn't be literally "drawButton", but I can readily imagine Qt
sprouting an easy and convenient way to render a QWidget in a 3D
scene... either as "truly" 3D geometry, i.e. transformed and scaled, or
billboarded and rendered at fixed pixel size, but potentially still
using the GL depth buffer. I'm not even sure what Qt3D can't *already*
do this.)
Post by Till Oliver Knoll
In fact, someone already pointed out that you can use a QPainter and "draw over the OpenGL rendered scene".
That's the way to draw "over OpenGL" - not with a restricted "drawText" convenience method which happened to be placed in some random API (QGLWidget) over a decade ago ;)
The problem is I don't *want* to draw "over" GL¹. I *need* to draw *in*
GL, specifically I need to specify the text location in terms of the GL
modelview space.

(¹ Well, I have another use case that *is* drawing over, but I already
was using QPainter for that.)

Overpainting techniques are fine... *for overpainting*. That's not what
I'm doing.
--
Matthew
Till Oliver Knoll
2015-04-04 09:57:08 UTC
Permalink
Post by Matthew Woehlke
Post by Till Oliver Knoll
..... But what's next? A "drawButton"? "drawBitmap"?
In a Widget?!
Yes. And why not?
Because the class name sais *Widget, and not *Painter or *WhateverItem.

A Widget's responsibility - much like the one of a View; we'll come to that in a second... - is to provide a /surface/ to draw onto, and to manage the underlying system resources (we'll deliberately skip over other functionality, such as layout management).

The important point to take away here is that a /Widget/ itself never exposes functionality to /draw/ something (exceptions might prove my thesis ;)). You may draw /onto/ a Widget - but /how/, that's the responsibility of some other class.
Post by Matthew Woehlke
QGraphicsView already does this sort of thing.
It's funny that you mention that /View/ class, since it does exactly /not/ "this sort of thing".

Check again the API of

http://doc.qt.io/qt-5/qgraphicsview.html

You won't find a single "drawWhatever" method there. Why? In analogy to QOpenGLWidget, same reasoning: it's responsibility is to /manage/ items, not to /draw/ them. That's the responsibility of each item itself.
Post by Matthew Woehlke
(Well,
it wouldn't be literally "drawButton", but I can readily imagine Qt
The reason why I mentioned a hypotetical "drawButton" in QOpenGLWidget's API was to merely illustrate my point how absurd it was to have any "draw" functionality therein. The existence of a single "drawText" would justify future additions of similar "drawWhatever" functions (because "hey! QOpenGLWidget already has a drawText, why not add my drawFoo method there, too?").

And clearly such an API would get messy and would not scale.

So as convenient as "drawText" was, IMHO it is a Good Thing(tm) to leave it out of QOpenGLWidget's API (same goes for bindTexture).
Post by Matthew Woehlke
sprouting an easy and convenient way to render a QWidget in a 3D
scene... either as "truly" 3D geometry, i.e. transformed and scaled, or
billboarded and rendered at fixed pixel size, but potentially still
using the GL depth buffer. I'm not even sure what Qt3D can't *already*
do this.)
That sounds to me you really want to look into Qt3D, if you want this kind of convenience.
Post by Matthew Woehlke
Post by Till Oliver Knoll
...
That's the way to draw "over OpenGL" - not with a restricted "drawText" convenience method which happened to be placed in some random API (QGLWidget) over a decade ago ;)
The problem is I don't *want* to draw "over" GL¹. I *need* to draw *in*
GL, specifically I need to specify the text location in terms of the GL
modelview space.
...
Overpainting techniques are fine... *for overpainting*. That's not what
I'm doing.
Clearly I cannot predict your application's requirements, but "overpainting", that's exactly what you were doing apparently, all the time. You said so yourself, you were using

http://doc.qt.io/qt-4.8/qglwidget.html#renderText

I've never used this method myself, but from what I gather you specify the text coordinates in /window/ coordinates - /not/ world (or model) coordinates!

So all the "renderText" does is it "overpaints" the given text into the current GL buffer (by disabling the depth test).

You get exactly the same result (probably even a better one due to better anti-aliasing) by using a QPainter and "overpaint" at the same window coordinates.

So this method did not do what you now tell us what your requirements are. So one reason more to quickly remove it (before people come and request to please extend the API such that the coordinates could be specified also in model/world coordinates ;)).


Happy Easter!
Oliver
Adam Light
2015-04-06 13:02:11 UTC
Permalink
On Sat, Apr 4, 2015 at 2:57 AM, Till Oliver Knoll <
Post by Till Oliver Knoll
Post by Till Oliver Knoll
...
That's the way to draw "over OpenGL" - not with a restricted "drawText"
convenience method which happened to be placed in some random API
(QGLWidget) over a decade ago ;)
The problem is I don't *want* to draw "over" GL¹. I *need* to draw *in*
GL, specifically I need to specify the text location in terms of the GL
modelview space.
...
Overpainting techniques are fine... *for overpainting*. That's not what
I'm doing.
Clearly I cannot predict your application's requirements, but
"overpainting", that's exactly what you were doing apparently, all the
time. You said so yourself, you were using
http://doc.qt.io/qt-4.8/qglwidget.html#renderText
I've never used this method myself, but from what I gather you specify the
text coordinates in /window/ coordinates - /not/ world (or model)
coordinates!
So all the "renderText" does is it "overpaints" the given text into the
current GL buffer (by disabling the depth test).
You get exactly the same result (probably even a better one due to better
anti-aliasing) by using a QPainter and "overpaint" at the same window
coordinates.
So this method did not do what you now tell us what your requirements are.
So one reason more to quickly remove it (before people come and request to
please extend the API such that the coordinates could be specified also in
model/world coordinates ;)).
I think you missed this overload of renderText:
http://doc.qt.io/qt-4.8/qglwidget.html#renderText-2

This takes object coordinates, including a z value.

The removal of this overload of renderText() was a significant blow to our
efforts in moving from 4.8 to 5.

Adam
Giuseppe D'Angelo
2015-04-06 15:31:52 UTC
Permalink
Post by Adam Light
The removal of this overload of renderText() was a significant blow to our
efforts in moving from 4.8 to 5.
Given there's enough interest into bringing this functionality back,
and that I strongly doubt it'll come back into QOpenGLWidget (as it's
not even remotely its role), how about starting working on it in a
standalone Qt addon?
--
Giuseppe D'Angelo
Matthew Woehlke
2015-04-06 15:15:33 UTC
Permalink
Post by Till Oliver Knoll
Post by Matthew Woehlke
..... But what's next? A "drawButton"? "drawBitmap"? In a Widget?!
Yes. And why not?
Because the class name sais *Widget, and not *Painter or *WhateverItem.
A Widget's responsibility - much like the one of a View; we'll come to that in a second... - is to provide a /surface/ to draw onto, and to manage the underlying system resources (we'll deliberately skip over other functionality, such as layout management).
Please don't be overly pedantic. The point isn't whether the ability is
particularly a member of QOpenGLWidget, but whether it is available *at
all* (in a non-deprecated class, anyway) without the user having to
concoct a complicated system for providing it.

Hopefully Qt3D will bring back these features. It's still a shame that
5.4 gets left out in the cold.
Post by Till Oliver Knoll
The important point to take away here is that a /Widget/ itself never exposes functionality to /draw/ something (exceptions might prove my thesis ;)). You may draw /onto/ a Widget - but /how/, that's the responsibility of some other class.
Post by Matthew Woehlke
QGraphicsView already does this sort of thing.
It's funny that you mention that /View/ class, since it does exactly /not/ "this sort of thing".
Actually it does. It does it via a helper class, but as above, that's
not really the point. (And anyway, what I meant was 'the QGV-based
graphics framework'.)
Post by Till Oliver Knoll
That sounds to me you really want to look into Qt3D, if you want this kind of convenience.
Well, yes, but doesn't help 5.4.
Post by Till Oliver Knoll
Post by Matthew Woehlke
The problem is I don't *want* to draw "over" GL¹. I *need* to draw *in*
GL, specifically I need to specify the text location in terms of the GL
modelview space.
...
Overpainting techniques are fine... *for overpainting*. That's not what
I'm doing.
Clearly I cannot predict your application's requirements, but "overpainting", that's exactly what you were doing apparently, all the time. You said so yourself, you were using
http://doc.qt.io/qt-4.8/qglwidget.html#renderText
True, and it does happen that the QGLWidget method is also technically
overpainting. Fortunately for my use case, this was not an issue (the
bit I'm drawing is itself an overlay, albeit a 3D one that needs to be
rendered with GL), but for this case it would be technically preferable
to actually rendering the text into the GL depth buffer (if unlikely to
make a practical difference).

In fact that has been the case for every time I've used renderText (in
multiple applications); I am drawing annotations *in GL world
coordinates* that are expected to be visible 'on top' anyway.
Post by Till Oliver Knoll
I've never used this method myself, but from what I gather you specify the text coordinates in /window/ coordinates - /not/ world (or model) coordinates!
That is *one option*, and not the one I use. Look again; there is an
overload that takes *world* coordinates. This is the one I use, and I
can assure you it works.
Post by Till Oliver Knoll
You get exactly the same result (probably even a better one due to better anti-aliasing) by using a QPainter and "overpaint" at the same window coordinates.
Actually, not better; exactly the same :-).
--
Matthew
Allan Sandfeld Jensen
2015-04-06 16:40:27 UTC
Permalink
Post by Matthew Woehlke
Post by Till Oliver Knoll
Post by Matthew Woehlke
..... But what's next? A "drawButton"? "drawBitmap"? In a Widget?!
Yes. And why not?
Because the class name sais *Widget, and not *Painter or *WhateverItem.
A Widget's responsibility - much like the one of a View; we'll come to
that in a second... - is to provide a /surface/ to draw onto, and to
manage the underlying system resources (we'll deliberately skip over
other functionality, such as layout management).
Please don't be overly pedantic. The point isn't whether the ability is
particularly a member of QOpenGLWidget, but whether it is available *at
all* (in a non-deprecated class, anyway) without the user having to
concoct a complicated system for providing it.
Hopefully Qt3D will bring back these features. It's still a shame that
5.4 gets left out in the cold.
Post by Till Oliver Knoll
The important point to take away here is that a /Widget/ itself never
exposes functionality to /draw/ something (exceptions might prove my
thesis ;)). You may draw /onto/ a Widget - but /how/, that's the
responsibility of some other class.
Post by Matthew Woehlke
QGraphicsView already does this sort of thing.
It's funny that you mention that /View/ class, since it does exactly
/not/ "this sort of thing".
Actually it does. It does it via a helper class, but as above, that's
not really the point. (And anyway, what I meant was 'the QGV-based
graphics framework'.)
Post by Till Oliver Knoll
That sounds to me you really want to look into Qt3D, if you want this
kind of convenience.
Well, yes, but doesn't help 5.4.
Post by Till Oliver Knoll
Post by Matthew Woehlke
The problem is I don't *want* to draw "over" GL¹. I *need* to draw *in*
GL, specifically I need to specify the text location in terms of the GL
modelview space.
...
Overpainting techniques are fine... *for overpainting*. That's not what
I'm doing.
Clearly I cannot predict your application's requirements, but
"overpainting", that's exactly what you were doing apparently, all the
time. You said so yourself, you were using
http://doc.qt.io/qt-4.8/qglwidget.html#renderText
True, and it does happen that the QGLWidget method is also technically
overpainting. Fortunately for my use case, this was not an issue (the
bit I'm drawing is itself an overlay, albeit a 3D one that needs to be
rendered with GL), but for this case it would be technically preferable
to actually rendering the text into the GL depth buffer (if unlikely to
make a practical difference).
In fact that has been the case for every time I've used renderText (in
multiple applications); I am drawing annotations *in GL world
coordinates* that are expected to be visible 'on top' anyway.
Post by Till Oliver Knoll
I've never used this method myself, but from what I gather you specify
the text coordinates in /window/ coordinates - /not/ world (or model)
coordinates!
That is *one option*, and not the one I use. Look again; there is an
overload that takes *world* coordinates. This is the one I use, and I
can assure you it works.
Post by Till Oliver Knoll
You get exactly the same result (probably even a better one due to better
anti-aliasing) by using a QPainter and "overpaint" at the same window
coordinates.
Actually, not better; exactly the same :-).
So why not use a QPainter?

QPainter p(qoglwidget);
p.renderText()?

`Allan
Matthew Woehlke
2015-04-06 16:52:56 UTC
Permalink
Post by Allan Sandfeld Jensen
Post by Matthew Woehlke
Post by Till Oliver Knoll
I've never used this method myself, but from what I gather you specify
the text coordinates in /window/ coordinates - /not/ world (or model)
coordinates!
That is *one option*, and not the one I use. Look again; there is an
overload that takes *world* coordinates. This is the one I use, and I
can assure you it works.
Post by Till Oliver Knoll
You get exactly the same result (probably even a better one due to better
anti-aliasing) by using a QPainter and "overpaint" at the same window
coordinates.
Actually, not better; exactly the same :-).
So why not use a QPainter?
QPainter p(qoglwidget);
p.renderText()?
Please read what you are replying to; as has been mentioned *several*
times, one of the needs is to specify the location in GL world space,
not screen space.

In the long run, I hope that Qt3D will bring this functionality back,
only "the right way" (i.e. using a billboarded sprite rendered in GL...
the texture can of course be created using QPainter).
--
Matthew
Allan Sandfeld Jensen
2015-04-07 11:35:34 UTC
Permalink
Post by Matthew Woehlke
Post by Allan Sandfeld Jensen
Post by Matthew Woehlke
Post by Till Oliver Knoll
I've never used this method myself, but from what I gather you specify
the text coordinates in /window/ coordinates - /not/ world (or model)
coordinates!
That is *one option*, and not the one I use. Look again; there is an
overload that takes *world* coordinates. This is the one I use, and I
can assure you it works.
Post by Till Oliver Knoll
You get exactly the same result (probably even a better one due to
better anti-aliasing) by using a QPainter and "overpaint" at the same
window coordinates.
Actually, not better; exactly the same :-).
So why not use a QPainter?
QPainter p(qoglwidget);
p.renderText()?
Please read what you are replying to; as has been mentioned *several*
times, one of the needs is to specify the location in GL world space,
not screen space.
QGLWidget::renderText is using QPainter. It disables depth test, sets a
viewport and draws using qpainter. It is not a lot of code.

It is also not implemented for OpenGL/ES. It is not the cleanest of neither
API nor implementation.

`Allan
Till Oliver Knoll
2015-04-06 20:19:44 UTC
Permalink
Post by Matthew Woehlke
Post by Till Oliver Knoll
Post by Matthew Woehlke
..... But what's next? A "drawButton"? "drawBitmap"? In a Widget?!
Yes. And why not?
Because the class name sais *Widget, and not *Painter or *WhateverItem.
A Widget's responsibility - much like the one of a View; we'll come to that in a second... - is to provide a /surface/ to draw onto, and to manage the underlying system resources (we'll deliberately skip over other functionality, such as layout management).
Please don't be overly pedantic. The point isn't whether the ability is
particularly a member of QOpenGLWidget, but whether it is available *at
all* (in a non-deprecated class, anyway) without the user having to
concoct a complicated system for providing it.
Sorry, my bad then. I thought the whole discussion was /exactly/ about bringing back renderText() to the new class QOpenGLWidget.

You: "I am finding myself less than
convinced that the new class is an improvement... implicit context
sharing is nice, but the loss of convenience methods is really, really
painful."

So I concluded that you must have been talking about QOpenGLWidget (alone).

Off course I never argued against the usefulness of said renderText (and /yes/, I missed the overload which takes world coordinates ;)).

I was merely defending the position that QOpenGLWidget is not the place for it, and that it was hence a good decision to drop it there.

As for the question where to place it: anywhere but *Widget!

Heck, it'd consider any "drawWhatever" functionality "high-level", read: "does not belong into Qt core OpenGL functionality", but rather another module: something between QtGui and Qt3d (or in the later itself).

The "Qt core OpenGL" functionality should just provide a surface to draw raw OpenGL into, a GL context and some convenience methods to convert Qt data structures (e.g. QImage) into "GL compatible buffer data". QMatrix and friends is nice, too.

Cheers,
Oliver
Matthew Woehlke
2015-04-07 21:06:04 UTC
Permalink
Post by Till Oliver Knoll
Post by Matthew Woehlke
Please don't be overly pedantic. The point isn't whether the ability is
particularly a member of QOpenGLWidget, but whether it is available *at
all* (in a non-deprecated class, anyway) without the user having to
concoct a complicated system for providing it.
Sorry, my bad then. I thought the whole discussion was /exactly/ about bringing back renderText() to the new class QOpenGLWidget.
You: "I am finding myself less than
convinced that the new class is an improvement... implicit context
sharing is nice, but the loss of convenience methods is really, really
painful."
So I concluded that you must have been talking about QOpenGLWidget (alone).
Fair enough. That being the case, let me clarify; I don't mind features
moving around. What I'm not entirely happy about is that a feature that
was important to me *disappeared entirely*.

I'd like to be able to render text in GL space without jumping through
hoops, in an application that is QOpenGLWidget. Besides that calling
methods from QGLWidget isn't likely to work well, I don't care how that
happens :-).
Post by Till Oliver Knoll
As for the question where to place it: anywhere but *Widget!
Again, I expect that in the long term, Qt3D will be the answer.
Unfortunately that doesn't help until (at least) Qt 5.5 is in distros.
--
Matthew
Yves Bailly
2015-04-01 14:55:54 UTC
Permalink
-----Original Message-----
Sent: Wednesday, April 01, 2015 3:42 PM
To: ***@qt-project.org
Subject: [Interest] QOpenGLWidget and text
I've been working on porting a Qt4 GL application to Qt5, using the new QOpenGL classes instead of the old and deprecated QGL classes.
Some of it was really easy. Some of it is requiring MASSIVE amounts of work.
I refer specifically to the removal of the text rendering methods. Since these are removed, what is the easiest way to go about drawing non-scaled, billboarded text in a GL scene? (Note: I am on Qt 5.4 at present; no Qt3D.)
You can use a QPainter to draw on a QOpenGLWidget. You can even create a QLabel having the QOpenGLWidget as parent. This is if you need to draw the text over the 3D scene.

Hope this helps.
Continue reading on narkive:
Loading...