Primitives example with magnum+Qt

294 views
Skip to first unread message

Alex Moreno

unread,
Jun 14, 2018, 11:54:30 AM6/14/18
to Magnum C++/OpenGL Graphics Engine
Hi,

I'm new to Magnum and I'm trying to create a demo app in Qt to get familiar with the tool. I have attached it (simplest CMake file + demo.cpp)

Steps:
  • I downloaded from magnum bootstrap the Qt branch. It compiles perfect and works. 
  • Then I added the code to view a simple triangle from magnum-examples. It works perfect too.
  • Then I tried to render a cube using Shaders::Phong as in the example "Primitives" and I don't see anything on the screen, just the right color for he background.
  • I have compile the Primitives example without changing anything (so using Magnum SDL2 application) and it works. 

using the #if condition on line 53 you can activate/deactivate the triangle of the cube example ("#if 1" works, "#if 0" doesn't)
using the #if condition on line 98 you can activate/deactivate the MeshTools:: compile or creating the GL::Buffers manually. I guess both should work th same but none of them are working.

Can anyone help me to spot what I'm doing wrong?

Thanks in advance.
Regards,
Alex
CMakeLists.txt
demo.cpp

Vladimír Vondruš

unread,
Jun 14, 2018, 2:00:19 PM6/14/18
to Alex Moreno, Magnum C++/OpenGL Graphics Engine
Hi,

took me a while, because while trying to get this to work, I apparently uncovered a strange crash bug in the Mesa driver involving GL::Framebuffer::clearDepth(). Oh well.

Your problem boils down to the following: compared to the Primitives example in Magnum, you move your object the other direction, which puts it effectively behind the camera. If I change the translation back to Vector3::zAxis(-10.0f), it draws the object correctly.

(In case you are also on Mesa, the clearDepth()/clearColor() functions don't seem to work correctly on the default framebuffer, causing the object to not be shown and crashing in some rare occasions as well. I will look into this, in the meantime you can work around that by using the (older) GL::*Framebuffer::clear() functionality.)

Cheers!
mosra

______________________________________________________________
> Od: Alex Moreno <amore...@gmail.com>
> Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com>
> Datum: 14.06.2018 17:54
> Předmět: [magnum] Primitives example with magnum+Qt
>
>Hi,
>
>I'm new to Magnum and I'm trying to create a demo app in Qt to get familiar
>with the tool. I have attached it (simplest CMake file + demo.cpp)
>
>Steps:
>
> - I downloaded from magnum bootstrap the Qt branch. It compiles perfect
> and works.
> - Then I added the code to view a simple triangle from magnum-examples.
> It works perfect too.
> - Then I tried to render a cube using Shaders::Phong as in the example
> "Primitives" and I don't see anything on the screen, just the right color
> for he background.
> - I have compile the Primitives example without changing anything (so
> using Magnum SDL2 application) and it works.
>
>
>using the #if condition on line 53 you can activate/deactivate the triangle
>of the cube example ("#if 1" works, "#if 0" doesn't)
>using the #if condition on line 98 you can activate/deactivate the
>MeshTools:: compile or creating the GL::Buffers manually. I guess both
>should work th same but none of them are working.
>
>Can anyone help me to spot what I'm doing wrong?
>
>Thanks in advance.
>Regards,
>Alex
>
>--
>You received this message because you are subscribed to the Google Groups "Magnum C++/OpenGL Graphics Engine" group.
>To unsubscribe from this group and stop receiving emails from it, send an email to magnum-engin...@googlegroups.com.
>To post to this group, send email to magnum...@googlegroups.com.
>Visit this group at https://groups.google.com/group/magnum-engine.
>For more options, visit https://groups.google.com/d/optout.
>
>

Vladimír Vondruš

unread,
Jun 14, 2018, 3:14:35 PM6/14/18
to Alex Moreno, Magnum C++/OpenGL Graphics Engine
Followup: got it working properly after reading the Qt documentation a bit. There's also no crash bug in any driver :)

What you need to do here (apart from that sign flip I mentioned before) is the following: the GL context in the QOpenGLWidget class doesn't have any default framebuffer, so instead of using GL::defaultFramebuffer from Magnum, you need to use the one provided by Qt. ID of that framebuffer is accessible through defaultFramebufferObject() on the widget and as the documentation states, this framebuffer gets recreated on every resize (and when reparenting the object, but in that case the context gets recreated as well and you should get the resize event after that anyway).

One possibility is to store a "placeholder" for the GL::Framebuffer instance in the class, e.g. like this (or you can also use Optional as you did for the other members, these two approaches are roughly equivalent):

GL::Framebuffer _framebuffer{NoCreate};

and then the resizeGL() would correctly populate it, wrapping the framebuffer coming from Qt:

void Viewer::resizeGL(int w, int h) {
_framebuffer = GL::Framebuffer::wrap(defaultFramebufferObject(), {{}, {w, h}});
}

then in the paintGL you would clear this framebuffer instead of the default one.

Also, here are some unsolicited further notes since I spent quite some time with the code:

- instead of Optional you can use the NoCreate tag to defer initialization of those objects until after the GL context is created. It's a bit less typing overhead (you don't need to use the * or -> things), but less safety also, as this won't blow up if you access a not-yet-created instance (it will just silently not work, probably)
- your shader instance is leaking (but i guess you know that)
- depending on what version are you on, this code: _mesh = std::get<0>( MeshTools::compile(cube, GL::BufferUsage::StaticDraw) ); will issue a deprecation warning in master (it got simplified to just _mesh = MeshTools::compile(cube); recently). In 2018.04 the vertex/index buffer gets destructed before the mesh is drawn and that could cause either a blank render or even a driver crash. If you are on 2018.04 and can't use master, you should save also the buffer instances somewhere.
- the projection matrix aspect ratio will be probably calculated incorrectly, as the framebuffer has some initial bogus size (100x100 in my case) and gets resized after. I would move the projection matrix setup to the resizeGL() function, where you get current values.

Hope this helps :)
mosra

______________________________________________________________
> Od: Vladimír Vondruš <mo...@centrum.cz>
> Komu: Alex Moreno <amore...@gmail.com>, Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com>
> Datum: 14.06.2018 20:00
> Předmět: Re: [magnum] Primitives example with magnum+Qt

Alex Moreno

unread,
Jun 14, 2018, 3:54:33 PM6/14/18
to Magnum C++/OpenGL Graphics Engine
Hope this help?
Mate... you are incredible. Thank you so much for expending even some minutes on this.
I will try it later and let you know about all your suggestions in a longer replay.
Cheers!
Alex

Alex Moreno

unread,
Jun 14, 2018, 7:49:56 PM6/14/18
to Magnum C++/OpenGL Graphics Engine
Attached the new working version in case you want to use it in anyway.

Ok. Let me go step by step with the changes and my comments:
- Using NoCreate instead of Optional works perfect (very nice trick, I love C++). It took me a while to understand how to do And now I understand what you meant with "placeholder". I'm instantiating a new object, calling the constructor but passing the pointer to the class member (it´s brilliant) so the createImplementation function is called. (i.e. new (&_vertexBuffer) GL::Buffer{};)
- The shader was not leaking, there was a delete on the Viewer destructor ;-). Now it´s gone as it´s not needed anymore.
- Regarding compile vs interleave/combine, I think compile is really useful for getting quick results but, in my case, I want full control on buffers so I prefer to play more the second approach. 
- translation (the one with the sign flipped, damn, what a silly one) moved from projection to transformation. Makes more sense to me :)
- projection matrix updated and passed to the shader on resizeGL: it works perfect now. resizeGL looks like this now
void Viewer::resizeGL(int w, int h) {
    _framebuffer = GL::Framebuffer::wrap(defaultFramebufferObject(), {{}, {w, h}});
    _shader->setProjectionMatrix( Matrix4::perspectiveProjection(35.0_degf, static_cast<float>(w)/h, 0.01f, 100.0f) );
}
 
I think that's all by now. Next step is to use the SceneGraph to control the camera and then straight to the picking. I´ll let you know.

Thanks a lot for your help and congratulations for this really impressive library.
Please, don't tell me you have done all this in your spare time.

Best regards,
Alex 
demo.cpp

Vladimír Vondruš

unread,
Jun 14, 2018, 8:26:41 PM6/14/18
to Alex Moreno, Magnum C++/OpenGL Graphics Engine
With NoCreate it's even simpler (actually, you *might* get some leaks when using placement-new like that), just move-construct a new instance:

GL::Buffer buffer{NoCreate}; // this is a placeholder
buffer = GL::Buffer{}; // this is a live instance now

The same is possible with Platform::GLContext, but for implementation reasons there it's not move-constructible and you have to call create() on the instance instead. Some more info about these tags is here: http://blog.magnum.graphics/announcements/2018.02/#full-control-over-initialization-and-ownership

Yes, MeshTools::compile() is more for "oh i have to load a generic model which might contain just anything" cases, you get all of the genericity yet none of the control.

Over the years this project turned from a "spare time side-project" to a thing that I can actually make my living with. Working on it full-time now.

Cheers
mosra

______________________________________________________________
> Od: Alex Moreno <amore...@gmail.com>
> Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com>
> Datum: 15.06.2018 01:49
> Předmět: Re: [magnum] Primitives example with magnum+Qt
>
>Attached the new working version in case you want to use it in anyway.
>
>Ok. Let me go step by step with the changes and my comments:
>- Using NoCreate instead of Optional works perfect (very nice trick, I love
>C++). It took me a while to understand how to do And now I understand what
>you meant with "placeholder". I'm instantiating a new object, calling the
>constructor but passing the pointer to the class member (it´s brilliant) so
>the createImplementation function is called. (i.e. new (&_vertexBuffer) GL::
>Buffer{};)
>- The shader was not leaking, there was a delete on the Viewer destructor
>;-). Now it´s gone as it´s not needed anymore.
>- Regarding compile vs interleave/combine, I think compile is really useful
>for getting quick results but, in my case, I want full control on buffers
>so I prefer to play more the second approach.
>- translation (the one with the sign flipped, damn, what a silly one) moved
>from projection to transformation. Makes more sense to me :)
>- projection matrix updated and passed to the shader on resizeGL: it works
>perfect now. resizeGL looks like this now
>
>void Viewer::resizeGL(int w, int h) {
>
> _framebuffer = GL::Framebuffer::wrap(defaultFramebufferObject(), {{}, {w, h}});
>
> _shader->setProjectionMatrix( Matrix4::perspectiveProjection(35.0_degf, static_cast<float>(w)/h, 0.01f, 100.0f) );
>
>}
>
>
>I think that's all by now. Next step is to use the SceneGraph to control
>the camera and then straight to the picking. I´ll let you know.
>
>Thanks a lot for your help and congratulations for this really impressive
>library.
>Please, don't tell me you have done all this in your spare time.
>
>Best regards,
>Alex
>
>
>
>
>
>
>
>
>
>On Thursday, 14 June 2018 20:14:35 UTC+1, mosra wrote:
>>
>> > Od: Vladimír Vondruš <mo...@centrum.cz <javascript:>>
>> > Komu: Alex Moreno <amore...@gmail.com <javascript:>>, Magnum C++/OpenGL
>> Graphics Engine <magnum...@googlegroups.com <javascript:>>
>> > Datum: 14.06.2018 20:00
>> > Předmět: Re: [magnum] Primitives example with magnum+Qt
>> >
>> >Hi,
>> >
>> >took me a while, because while trying to get this to work, I apparently
>> uncovered a strange crash bug in the Mesa driver involving
>> GL::Framebuffer::clearDepth(). Oh well.
>> >
>> >Your problem boils down to the following: compared to the Primitives
>> example in Magnum, you move your object the other direction, which puts it
>> effectively behind the camera. If I change the translation back to
>> Vector3::zAxis(-10.0f), it draws the object correctly.
>> >
>> >(In case you are also on Mesa, the clearDepth()/clearColor() functions
>> don't seem to work correctly on the default framebuffer, causing the object
>> to not be shown and crashing in some rare occasions as well. I will look
>> into this, in the meantime you can work around that by using the (older)
>> GL::*Framebuffer::clear() functionality.)
>> >
>> >Cheers!
>> >mosra
>> >
>> >______________________________________________________________
>> >> Od: Alex Moreno <amore...@gmail.com <javascript:>>
>> >> Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com
>> <javascript:>>
>> an email to magnum-engin...@googlegroups.com <javascript:>.
>> >>To post to this group, send email to magnum...@googlegroups.com
>> <javascript:>.
>> >>Visit this group at https://groups.google.com/group/magnum-engine.
>> >>For more options, visit https://groups.google.com/d/optout.
>> >>
>> >>
>> >
>> >--
>> >You received this message because you are subscribed to the Google Groups
>> "Magnum C++/OpenGL Graphics Engine" group.
>> >To unsubscribe from this group and stop receiving emails from it, send an
>> email to magnum-engin...@googlegroups.com <javascript:>.
>> >To post to this group, send email to magnum...@googlegroups.com
>> <javascript:>.

Alex Moreno

unread,
Jun 15, 2018, 3:33:34 AM6/15/18
to Magnum C++/OpenGL Graphics Engine
Got it. Much simpler.

Congratulation again! Only a few gifted people manage to live from something which started as a hobby.
Best of luck on this. 

Cheers,
Alex
Reply all
Reply to author
Forward
0 new messages