Overpainting a view

Forums: 

Hi,

I've been working on an example [1] where I'm using (Python)OCC ( still on 6.8.0 ) and (Py)Qt4 to overpaint a V3d_View.

The objective here is to be able to embed Qt widgets in the opengl view.
I've had a 1st success: I'm able to use QPainter to overpaint the V3d_View, huzzzaaah ;)

Now, this would be peachy, if it wasn't for the V3d_View Rotation' method.
When I call the Rotation method, the view is redrawn, frankly, much against my expectations.
The issue is clear: whenever the view is rotated, now my overpainting is not called, and now there is flickering going on, since the background thread kicks in, and the view is once again redraw, now with the overpainting procedure.

So, I've been delving into the code...

Now, this snippet is part of the V3d_View::Rotation, got me by surprise:

#else
myImmediateUpdate = Standard_False;
Rotate(dx/rx, dy/ry, 0., gx, gy, gz, Standard_False);
ZFitAll (Zmargin); //Don't do that, perf improvment
myImmediateUpdate = Standard_True;
ImmediateUpdate();
#endif
}

Hmmmm... seems that the method is messing with state that's gone undocumented...

So a few comments:

- its important to point out that this (might, on which conditions exactly?) invoke a redraw of the viewer
- its also not particularly elegant that the state (myImmediateUpdate) is altered in this method call, that's not very transparant to the user

So, how to go about this? The very cool android and iOS apps work perfectly with overpainting the opengl viewer, so clearly there's a proper way of handling this.

I've studied the android sample, and great care has been taken in managing the OpenGL context.
This could be a hint, another aspect I've noticed is that OcctJniView.java invokes the Rotation methods like so:

queueEvent (new Runnable() { public void run() { myRenderer.onStartRotation (aStartX, aStartY); }});

by adding it to the event queue.

So these have been clues from provided samples, which has been educational.

Still, I would like to know whether its possible to update the camera without invoking a redraw ( the .Rotation method, without the implicit opengl call )

Finally, I hope the doc strings could become a little more complete, this method is a little too magic, if you consider the what can be expected from readings the doc string.

-jelle

[1] https://github.com/tpaviot/pythonocc-core/blob/master/examples/core_visu...

Kirill Gavrilov's picture

Combining several rendering engines is always tricky, and should be avoided when possible. Most things can be drawn by OCCT itself or by low-level OpenGL code within custom OpenGl_Element objects.

- its also not particularly elegant that the state (myImmediateUpdate) is altered in this method call, that's not very transparant to the user

you have quoted lines from old version of OCCT, moreover it is actually a "dead code" escaped by #ifdef.

The idea of changing myImmediateUpdate=false within this code is to temporarily disable several implicit updates (within Rotate() and ZFitAll()) followed by single implicit update after myImmediateUpdate=true. Of course the second assignment is incorrect - it should return the flag to the previous state. But this does not matter since this code has been inactive for a long time and has been already removed ;).

Still, I would like to know whether its possible to update the camera without invoking a redraw ( the .Rotation method, without the implicit opengl call )

but you have already found the key to answer of your question! Flag myImmediateUpdate (true by default) can be changed by the method V3d_View::SetImmediateUpdate().

Implicit update is a nice feature allowing to get up-to-date image on screen regardless of involved logic of 3D viewer. It is enabled by default within V3d_View and you may notice that most AIS_InteractiveContext methods have optional argument to update viewer which is set to true as well.

However implicit updates have obvious drawback - having more viewer updates than it might be necessary. And your case is particular example when implicit updates should be avoided everywhere.

jelle's picture

Many thanks for your detailed reply Kirill, much appreciated...

- Right, for entities in the viewer, indeed, it would be a questionable decision to step out of the comfort of OCC. What I'm trying to achieve is overpainting widgets ( a HUD style interface, much like what we see in OCC's CadAssistant ). Building these kind of widgets in Qt is really straightforward, hence delving in this direction.

- Correct, I'm on OCC 6.7.0 right now, looking fwd to move to 6.8.0 / 6.9.1 shortly, these days its hard to keep up with the OCC team ;)

- I've noticed that the OCC 6.9.0 code is much cleaner and lots has been achieved, especially when it comes to handling of OpenGL. Btw, I've much enjoyed your post on optimizing immediate drawing [1]. A really cool contribution, I'm looking fwd to further explore this, interesting. I've been looking into optimizing some rendering calls, and this is just the ticket ( I'm doing exactly, animation, well, rendering robots ), so that's great.

- Strangly enough, when I set the V3d_View.:SetImmediateUpdate(True) from pythonocc, just before calling the .Roation method the previous value ( False ) is returned ( correct ), but I see no change in behaviour ( calling to .Rotation still triggers a redraw of the viewport )

- However, as you state, implicit updates arent such a bad idea after all ;)
Here's how I solved the problem:

1) mouseMoveEvent is invoked by the Qt framework ( someone is re-orienting the view )
2) mouseMoveEvent stores the event data and invokes the .update method
this is an important detail, since now event are pushed in the event queue, following Qt's idiom
3) the update method invoked the .paintEvent method, here we spot event data; that the mouse has been moved with the left-mouse-button ( which invokes re-orienting the view ), so the .StartRotation and .Rotation methods are called, the buffer is swapped after which the overpainting routine is called.
4) this all works out just peachy, see this video [3]

This experiment is based on Qt's opengl overpainting example [4]
The cool thing is that Qt lets you embed widget in an OpenGL viewport, so that really paves the way for more exciting HUD displays like [5], Catia's operations tree which is rendered transparently on top of the OpenGL viewport.

Thanks again for the interesting input Kirill,

-jelle

[1] http://dev.opencascade.org/index.php?q=node/1080
[2] http://git.dev.opencascade.org/gitweb/?p=occt.git;a=blob;f=samples/qt/Co...
[3] https://www.youtube.com/watch?v=QKMgXK7t8rg
[4] https://doc.qt.io/archives/4.6/opengl-overpainting.html
[5] http://goo.gl/KBh7BL

Kirill Gavrilov's picture

Current OCCT (6.8.0+) also provides option OpenGl_Caps::buffersNoSwap, which can be used to leave control over window buffer to external rendering API (e.g. Qt5 / QML).

jelle's picture

Hi Kirill,

This is a valuable pointer, I noticed the usage of this call in the Android examples.
Thanks so much for contextualizing this function, that's great...

Actually, this is awesome, since I noticed in 6.8.0 + that controlling the buffering has changed, which in my case causes tearing of the viewport ( which is what happens if your handling buffering correctly ), so you've answered my next question before I could ask it ;)

Thanks!

Stefan Tröger's picture

Nice work! At FreeCAD we are working on a similar thing: https://www.youtube.com/watch?v=wrOP7sLqwiM

As we do not use OCC visualisation I can't help out with code, just thought I mention it. We use QT's QML for a dynamic interfcace, which works really well and gives enough flexibility for a good user interaction. Curenttly the effort is on hold until we migrated to QT5 (QML in 4.8 is lacking), but if you are interested in developing a QML interface for view handling and dockers for a CAD proramm we may be able to share some work.

jelle's picture

Hi Ickby,

Thanks, but yoo much credit ;)
I've been following your progress with great interest, I think you've achieved some amazing progress in modernizing FreeCAD's gui, that's awesome...

Great to find you here, I've been wanting to get in touch sharing in some OCC / Qt ideas... so cool to see you here ;)

Yes, so I'm most definitely heading in this direction ( QGraphicsView, dockers, though I'm interested but not knowledgable of qml )

So, yeah, it would be great to compare notes...

-jelle