Rendering Questions

Don’t know where to stick these questions and comments but -

I have been working through the code and got to qtextrenderstrategy and was rying to figure out how it tied in to the drawing code - and I could not. Then I looked at the current binary Avogadro2 version for the Mac and found there was no Label function in the Display types. So I could not turn on any atom labels. If you have a new way to doing this it is not obvious and I find this to be an essential function - particularly atom numbers and atom types (for MM calculations).

Comment- there are no version numbers on the shaders so it is not clear which (if any) version of OpenGL is being targeted/supported.

I wrote some test programs to use either Qt OGLWidget or the newer QOpenGLWidget. QT suggests using the newer widget and for the most part I could easily interchange them. However the newer QOpenGLWidget behaves differently on a Retina display MacBook Pro with the image being 1/4 the expected size. I have not seen a discussion here but the 1.90 code uses the older QGLWidget and I wondered why.

I’ll leave some of this to @mhanwell to address. There’s nothing particularly special about atomic labels. There’s currently a patch in review for those:

As for the GLSL, I believe it’s targeted for OpenGL ES 2.0, but @mhanwell can address that. It’s probably worth updating some of the code towards newer versions, although Apple doesn’t support much beyond v.2.1 / GLSL v 1.20

When dealing with retina screens, remember that there’s a difference in scaling:

Specifically, you’ll want to scale things using devicePixelRatio():

It targets OpenGL 2.1, I am hoping to move it forward to the OpenGL 3.3 core profile and GLSL 1.50 (if memory serves) soon. This is well supported on macOS, Linux, and Windows by most modern cards (and has been the minimum in VTK for 2+ years now (I think, didn’t verify but from memory/roughly).

We use QOpenGLWidget in Avogadro 2 master, and also in VTK. Please look at master, and I will push a new release out soon as I think it is important to get that tested by more people. A release is overdue at this point.

I thought the code I had (1.90.0) might be out of date so I downloaded the latest master(yesterday) and the GLWidget in this version is based on QOpenGLWIdget. So then I looked for where you were setting the devicePixelRatio and I could not find it. The setting function is in the Camera code but it is never called. In the 1.90.0 version this was done in the GLWidget constructor - last line. The new code for the GLWidget constructor is identical except for the last line (and the change from OGLWIdget to QOpenGLWidget). I then searched all the code in QtOpenGL and Rendering and could find no call to set the devicePixelRatio. Then I checked AvogadroApp master both main and mainwindow and it is not there.

The version number on the shader is more like a comment than anything useful. I am more concerned with covering my rear - old users with old computers - than I am with pushing ahead with OpenGL.

I would still love to see the atomlabeling code to see how you are implementing text in an opengl window. I did find a solution on StackOverflow which seems to work. I added a routine - addText(position,color,QString) to the rendering code, analogous to addLine, addCylinder and addSphere. I was then able to render all the text with a loop inside a QPainter. Surprisingly it worked on all platforms even while rotating structures. It only works with a QOpenGLWidget. With a QGLWidget the code works on Linux and WIndows but on the Mac there are significant artifacts when I try to display text and rotate a structure. It works but - I don’t trust or understand QPainter and it looks more like an immediate mode solution. The purpose of this exercise was to pack everything into a vbo and ship it all to the graphics card in one call. I may look into a freetype-gl solution but I would still like to see how you solve this problem.

It has been a while since I wrote that code, but I don’t think that QOpenGL* based widgets needed to worry about the device pixel ratio - it was baked into the widgets. We use a bill boarding technique as I remember it, and I can tidy up the label branch and get it merged soon. The basic approach is to rasterize the text into an image, set it as a texture, and add it to the scene. There are lots of options in how that is achieved, whole strings, lookup tables, font kerning etc.

Are you seeing issues with retinal displays in master, or you are just trying to follow the logic. Last I checked this was all working great on the retinal display mac I have access to.

Hi Marcus,

The problem is the opengl widget on retina display macs. If you don’t
take into account the pixelRatio the opengl widget is 1/4 the expected
size with a QOpenGLWidget. If I just switch my test program from
OGLWidget to QOpenGLWidget and do a setMinimumSize - with the OGLWidget
the window size and the widget size are the same. With a QOpenGLWidget
on a retina display mac the window size is 800x600 but my molecule fits
in the lower left quarter of the window. On the retina display Mac the
devicePixelRatio is 2. The resizeGL call is in device independent units
(800x600) so I multiply the height and width by the pixel ratio and use
this in the glViewport call (0,0,1600,1200) and it all works. The
pixelRatio is also used in camera->unProject.

I have not tried to recompile the master code on the mac just following
the logic. As I said it was in the 1.90.0 version.

I try really hard not to install too many packages because I forget that I
have installed them code works until I move it to a clean machine. For
example I am not using GLEW but the qt version initializeOpenGLFunctions.
There were no problems until I got to Windows 10/MSVC-2015/qt5.9.1 which
complained that glDrawRangeElements was undefined. Looks like a qt problem
and I did not mention it because you are using GLEW and would not see it.
I substituted glDrawElements and the windows code compiled and ran


This works on retina display macOS machines to the best of my knowledge, I will double check when I get a chance but I know Geoff and others use retina displays frequently. I am well aware of the scaling issues, I was involved in porting VTK to work on retina displays, as well as Avogadro 2 work. It has just been a while since I did it, hence no instant recall on exactly where we account for it. I do remember testing it quite a bit at the time.

Qt gets a little convoluted, but I think it effectively always supplies device pixels to OpenGL based classes as it knows they need them rather than logical. Hence when you stay in that world I think things became simpler, and less logic was needed in our code.

I just took a look at what I was last working on, and forcing it to low res mode gave noticeably pixelated display of the 3D scene (along with text etc). It is also using the entire widget area, but I admit there are very few references to pixel ratios. See my commit where I removed much of the logic last year.

I built the avogadro-master code today and can confirm that it works just
fine. Don’t know why yet. I can setup the default format exactly the same
but I still need to set the pixelRatio explicitly. Right now I am looking
into whether embedding the glwidget inside another layout widget makes a
difference (you add the glwidget to the multiview widget). I don’t have
any better ideas yet.

You might also be better served asking questions on a more general forum like StackExchange or the Qt forum.

From the Qt documentation:

On macOS and iOS, applications use high DPI scaling that is an alternative to the traditional DPI scaling. In the traditional approach, the application is presented with an DPI value used to multiply font sizes, layouts, and so on. In the new approach, the operating system provides Qt with a scaling ratio that is used to scale graphics output: allocate larger buffers and set a scaling transform.

The advantage of this approach is that that vector graphics and fonts scale automatically and existing applications tend to work unmodified. For raster content, high-resolution alternative resources are needed, however.

Scaling is implemented for the QtQuick and QtWidgets stacks, as well as general support in QtGui and the Cocoa platform plugin.

The OS scales window, event, and desktop geometry. The Cocoa platform plugin sets the scaling ratio as QWindow::devicePixelRatio() or QScreen::devicePixelRatio(), as well as on the backing store.

For QtWidgets, QPainter picks up devicePixelRatio() from the backing store and interprets it as a scaling ratio.

However, in OpenGL pixels are always device pixels. For example, geometry passed to glViewport() needs to be scaled by devicePixelRatio().

So Qt widgets hide the DPI scaling but OpenGL does not.

To figure out what was going on in Avogadro2 I put in a resizeEvent in the MainWindow and there I could query the size of the total layout, the multiViewWidget, the qopenglwidget and the glViewport each time I resized the mainwindow. The devicePixelRatio for my hardware is 2 (2017 MBP retina displayed on a 4K monitor). For the Avogadro-master code:

Layout - 1356x804 multiView 1099x708 glWidget 1099x708 glViewport 1099x708.

And the molecule fills the display window and picking works. In my test program if the glwidget size and the glViewport size are the same numerically than the image only fills 1/4 of the window. glWidget is in device independent pixels and glViewport is in pixels.

So I changed the glWidget constructor to get the devicePixelRatio and set the value in the camera. I also changed resizeGL to multiply the width and height by the devicePixelRatio and then pass the new values to the render. So now when I resize the mainwindow the values are:

Layout - 1372x817 multiView 1115x720 glWidget 1115x720 glViewport 2230x1440.

And the molecule fills the screen and picking works. So Avogadro2 works either way!

It looks to me that your code takes any size glViewport and maps it full screen to the glWidget. How I don’t know. Qt does have several device independent pixel formats including a QOpenGLPaintDevice - but I don’t think you are using any of them. I am still confused as to how this works. But my code works according to the Qt documentation so I am just going to make a note of this problem until something breaks and move on to figuring out how to do side by side stereo with the new rendering routines.