-
Notifications
You must be signed in to change notification settings - Fork 287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OSG shadows #978
OSG shadows #978
Conversation
Codecov Report
@@ Coverage Diff @@
## release-6.4 #978 +/- ##
===========================================
Coverage 56.7% 56.7%
===========================================
Files 310 310
Lines 23958 23958
===========================================
Hits 13585 13585
Misses 10373 10373
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generally looks good to me! Thanks for making this change.
I see several inconsistent code style in this change with the DART's code style, but it would be good to resolve it using clang-format once the style related PRs (#979, #981) are merged.
In general, I would prefer using a setting function for shadow technique instead of using enum
for better flexibility (e.g., Viewer::setShadowTechnique(osg::ref_ptr<osgShadow::ShadowTechnique> newShadowTechnique)
); with the current design, we have to change the code to use a new shadow technique. However, I'm okay with the current design because I don't expect OSG will add new techniques soon.
@mxgrey It would be nice to hear from you since OSG GUI was introduced by you! 😛
Thanks for the quick feedback.
OK. Let's let clang-format do its job! 😄
I can do this change later today.. |
@jslee02 I followed your advice about setting the shadow technique. I also had to expose the light sources of the viewer so that someone can use them in the shadow techniques (some of them recommend/require to set which light you want to use for shadowing). |
@costashatz Looking at the code, I found that there is another issue that |
We could add a flag to the |
To complement the shadow flag, we would probably need to add an update function to the |
dart/gui/osg/Viewer.hpp
Outdated
/// Constructor for dart::gui::osg::Viewer. This will automatically create the | ||
/// default event handler. | ||
Viewer(const ::osg::Vec4& clearColor = ::osg::Vec4(0.9,0.9,0.9,1.0)); | ||
Viewer(const ::osg::Vec4& clearColor = ::osg::Vec4(0.9,0.9,0.9,1.0), bool shadowsOn = false, ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique = nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to get rid of the shadowsOn
flag and allow a nullptr
for shadowTechnique
to indicate that shadows should be off? Then if someone passes in a non-null value for shadowTechnique
, we have it default to shadows being on?
Also, if there's a default native osgShadow::ShadowTechnique
that we can recommend to users, it would be nice if we referred to it in the documentation of this function.
dart/gui/osg/Viewer.hpp
Outdated
const ::osg::ref_ptr<::osg::Group>& getPhysicsGroup() const; | ||
|
||
bool isShadowed() const; | ||
void enableShadows(bool _enable = true, ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique = nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These default values seem very counter-intuitive to me. Is it possible to have shadows with a nullptr
for the osgShadow::ShadowTechnique
? I would assume that providing a nullptr
will make it impossible for OSG to render shadows, so it wouldn't make sense to have them enabled. Or is the shadowTechnique
something extra that can be applied on top of the default OSG shadowing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These default values seem very counter-intuitive to me. Is it possible to have shadows with a nullptr for the osgShadow::ShadowTechnique? I would assume that providing a nullptr will make it impossible for OSG to render shadows, so it wouldn't make sense to have them enabled. Or is the shadowTechnique something extra that can be applied on top of the default OSG shadowing?
You need the ShadowTechnique
in order to have shadows..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, which is why this API seems deceptive. It's simultaneously telling the Viewer "I want you to enable shadows" and "I don't want you to have a ShadowTechnique
".
I understand now that we're interpreting a nullptr
as "use some default ShadowTechnique
", but that isn't clear without digging into the source code of this function.
dart/gui/osg/Viewer.cpp
Outdated
mShadowed = _enable; | ||
} | ||
|
||
void Viewer::setShadowTechnique(::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now that if the user passes a nullptr
, we replace it with a default osgShadow::ShadowMap
.
I think that's a bit opaque, so what if we instead make an osg::ref_ptr<osgShadow::ShadowMap>
instance the default value for these function arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm further realizing that the initialization of the ShadowMap
is using one of the member variables of the Viewer
class, mLight1
.
Maybe an alternative approach would be to make overloads of the functions that take no ShadowTechnique
argument, and then document to the user that it will create a ShadowMap
by default, using the mLight1
member of the Viewer
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a bit opaque, so what if we instead make an osg::ref_ptrosgShadow::ShadowMap instance the default value for these function arguments?
Yes we can do this..
I'm further realizing that the initialization of the ShadowMap is using one of the member variables of the Viewer class, mLight1.
That's why I exposed the LightSources
so that users can define their own ShadowTechnique
s and be able to choose the light source that will cast the shadows. We can't do it generically because not all of the techniques have the setLight()
functionality..
Hmm.. I didn't pay attention to the
We cannot do this, because as OSG docs say: "Not all of the techniques respect the shadowing flags". In practice, most of them ignore at least one flag (either caster or receiver of shadow).! |
When I say "shadow flag" I'm just talking about a simple boolean within the DART API. It would be agnostic towards the underlying rendering engine. The shadowing flag of the We could even set it up so that every rendering loop it checks whether that flag has changed for each This assumes that my understanding is correct: Only objects in |
Yes.. At least that's what is said by the OSG docs and matches what I tried so far... |
I like this idea. Let me try to see what happens.. |
I implemented @mxgrey 's idea and it works nicely for the I didn't manage to make |
After some more investigation, I think that we need to create a version of
Personally I prefer either of the 2 first options because I am not using the |
I'm okay with either of the first two options. I wouldn't consider this (nor ImGui) to be a critical feature of DART, so correctness and compatibility between the two isn't a high priority. Shadows are definitely a desirable feature, and it's mostly unrelated to the ImGui feature, so I don't see any reason to block it. |
dart/gui/osg/WorldNode.hpp
Outdated
@@ -67,7 +68,8 @@ class WorldNode : public ::osg::Group | |||
friend class Viewer; | |||
|
|||
/// Default constructor | |||
explicit WorldNode(std::shared_ptr<dart::simulation::World> _world = nullptr); | |||
/// Shadows are disabled by default | |||
explicit WorldNode(std::shared_ptr<dart::simulation::World> _world = nullptr, ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique = nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still a little bit leery about having shadowTechnique = nullptr
secretly mean "Let us choose a default shading technique for you".
However, we do already have a precedent of this pattern where passing in a nullptr
for ResourceRetriever
means that we will use a default LocalResourceRetriever
.
I might feel better about this pattern if we rename the argument from shadowTechnique
to something like alternativeTechnique
. That will at least tell the user that they are specifying an alternative rather than specifying the technique to use. Then passing a nullptr
naturally says "I don't want to use an alternative", and so we apply the default shading technique.
Sorry if this sounds petty, but without something along these lines, a user would have to look into the source code to actually understand how these functions should be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if this sounds petty, but without something along these lines, a user would have to look into the source code to actually understand how these functions should be used.
No worries. I understand what you say. Nevertheless, in this version of the code, nullptr
means no shadow (not a default shadow behavior).. The user has to specify their own ShadowTechnique
. I could create a static default technique if you like..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, sorry, I didn't notice that part of the recent change.
I actually liked providing a default shadow technique; I just wasn't comfortable with the semantics of "giving a nullptr
technique means we should use a default". Sorry for not communicating that well.
I'm not clear on how a static default would work, since it seems to need information about the Viewer that's using it. I guess we could make it a factory function that takes a Viewer*
argument and returns a ref_ptr<ShadowTechnique>
? We wouldn't be able to use that function as the default argument for this constructor, but it could at least make it easy for users to enable shadows. We could add a comment in the documentation of this function that refers to the default ShadowTechnique factory.
Since the shadows conflict with the ImGui feature, I suppose we should have shadows turned off by default anyway. It would've been nice to have shadows on by default, but we can tackle that later once we've fixed the ImGui conflict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not clear on how a static default would work, since it seems to need information about the Viewer that's using it. I guess we could make it a factory function that takes a Viewer* argument and returns a ref_ptr? We wouldn't be able to use that function as the default argument for this constructor, but it could at least make it easy for users to enable shadows. We could add a comment in the documentation of this function that refers to the default ShadowTechnique factory.
That's exactly what I had in mind.. A static member function that creates a default ShadowTechnique
(given a Viewer*
) that users can use.. I'll do that asap..
ince the shadows conflict with the ImGui feature, I suppose we should have shadows turned off by default anyway. It would've been nice to have shadows on by default, but we can tackle that later once we've fixed the ImGui conflict.
I agree on this and that's the reason I left the shadows disabled by default.. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also thinking of modifying the osgOperationalSpaceControl
example to be able to enable/disable shadows interactively (with a simple event handler). What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a great place to put an example of this, thanks!
I'm also fine with any of the first two options! |
I went with the second option (warning when enabling shadows in Scanning dependencies of target check-format
Checking 4 files...
Every file seems to comply with our code convention.
Done.
Built target check-format So I guess the styling should be ok! @jslee02 @mxgrey let me know if you have anything to add or you want me to fix something. |
@costashatz Regarding the style, we're just checking four files in The current change looks good to me. I think we can merge this on approval of @mxgrey. |
I'll do one last careful review tonight as soon as I get the chance, but it's looking very good to me as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some nitpick comments
dart/gui/osg/Viewer.hpp
Outdated
/// Get one of the LightSources of this Viewer | ||
/// index either 0 or 1 | ||
/// Useful for shadowing techniques | ||
const ::osg::ref_ptr<::osg::LightSource>& getLightSource(unsigned int index = 0) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please use std::size_t
for index parameters.
dart/gui/osg/WorldNode.hpp
Outdated
@@ -67,7 +68,8 @@ class WorldNode : public ::osg::Group | |||
friend class Viewer; | |||
|
|||
/// Default constructor | |||
explicit WorldNode(std::shared_ptr<dart::simulation::World> _world = nullptr); | |||
/// Shadows are disabled by default | |||
explicit WorldNode(std::shared_ptr<dart::simulation::World> _world = nullptr, ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique = nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please remove the leading underscore from _world
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had one nitpick, but it's not nearly important enough to block on.
Thanks, @costashatz, for this excellent (and frequently requested) addition to DART!
dart/gui/osg/WorldNode.cpp
Outdated
shadowedScene->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask); | ||
shadowedScene->setCastsShadowTraversalMask(CastsShadowTraversalMask); | ||
|
||
// set the physics group |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: This is called normal group
now rather than physics group
.
This is a better version of #976, where:
dart::gui::osg::Viewer
class to be able to enable/disable shadows. Edit: I mean that now there's noShadowedWorldNode
and you can enable/disable shadows directly from the viewerThere are two issues (one minor and one major):
mLight1
as the light that casts shadows (because this one is higher in the up direction). I am not an OSG expert and I do not know how to combine multiple lights to produce shadows. I think this is minor as it should mostly be ok. Here's one example:ImGuiViewer
is not working properly once you enable shadows (either black or distorted views on the ImGui panels). Here's an example:I am investigating why this happens and I will try to provide a fix..
@jslee02 let me know what you think..