-
Notifications
You must be signed in to change notification settings - Fork 62
Support for textures as binary blobs #642
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
Conversation
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
So based on the current approach, I would expect this: // set texture using old method
SetTexture(tex_name);
// get texture. This returns `tex_name`
auto result = Texture();
// set texture using new method. Clears old tex data.
SetTexture(blob, new_tex_name);
// this returns `new_tex_name`
auto result2 = Texture();
Not sure why two
I think we can assume that users can't change the texture data so we can just share them.
If we want to support this, i think it is better to just to go with Overall I'm leaning towards the |
OK sounds good! Then I'll change the approach to use shared memory and the API to be:
Then current calls will go through the usual code path of using the texture as a URI and loading it from a file, if the image data is set it will be used as a unique texture name and loaded from the image raw data. |
ok yeah that's sounds good to me |
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Ok done! The API is here. It not super ideal since I believe we can't change the current Texture getter since that would break downstream users (maybe could do a tick/tock cycle?):
As an alternative I added another getter to get the texture data
And changed the If this looks good I'll implement a similar update for PBR textures, as well as OGRE1 |
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
that looks good to me! I think the for OGRE1, you should be able to create a manual texture and load raw data to it. Here is an example: https://github.com/gazebosim/gz-rendering/blob/ign-rendering6/ogre/src/OgreDistortionPass.cc#L286-L405 |
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Thanks for the pointer! It made things a lot easier. Still, OGRE1 doesn't really work that well, specifically I had to add a workaround to swap red and blue here. It seems that regardless of whether I specify the pixel format as After the workaround the colors look better but some models (i.e. the nurse here) seem to have issues, probably due to the fact that it has an RGBA texture (so with an alpha channel) I guess I'll focus on getting the implementation as good / clean as possible with OGRE2 |
hmm that's weird. Yeah getting OGRE2 to work first sounds good. You can ticket an issue for the OGRE1 implementation afterwards |
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
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.
OK I think this is pretty much ready for review!
To test it you will need the dependency PRs in gz-cmake and gz-common, as well as a few assets in GLB, personally I tested with the attached ones:
AmbulanceStretcher
is a PBR GLTF asset, under Ubuntu 20.04 and the older version of assimp 5.0.x it will only have a diffuse and normal texture, under Ubuntu 22.04 andassimp
gltf PBR support it will also have metalness and roughness maps.StaffFemale_CheckClipboard
An animated human with PBR textures, same as above for PBR support but also include animations. Also provided as adae
to make sure animations in Collada and GLB look the same.
Other assets can be found quite easily, the Khronos repo has quite a variety of them.
All assets are provided as both gltf
and glb
.
gltf
is made of a readable json that includes the main fields that describe the mesh and points to a binary file for the binary data (i.e. vertices, normals, texture cooridnates) and image files for textures.
glb
includes all the data bundled in a single binary. gltf
doesn't use the API in this branch since textures are external images but glb
does, if all works well they should look exactly the same.
ogre/src/OgreMaterial.cc
Outdated
void OgreMaterial::SetNormalMap(const std::string &_name, | ||
const std::shared_ptr<common::Image>& /*_img*/) |
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 didn't add the NormalMapData getter / copy the member variable since it seems normal maps are not implemented in OGRE1 anyway
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.
To test it you will need the dependency PRs in gazebosim/gz-cmake#278 and gazebosim/gz-common#372, as well as a few assets in GLB, personally I tested with the attached ones:
Could you add an example to the examples
folder that loads that for easier testing? Bonus for an accompanying tutorial under tutorials
😄
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Done! Since this is all handled by the MeshManager I just added another mesh to |
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Signed-off-by: Luca Della Vedova <luca@openrobotics.org>
Changes look good as they are now. Just waiting for upstream PRs and green CI. One minor note that shouldn't block this PR from getting in is if we could keep the original |
Signed-off-by: Louise Poubel <louise@openrobotics.org>
Signed-off-by: Ian Chen <ichen@osrfoundation.org>
Codecov Report
@@ Coverage Diff @@
## main #642 +/- ##
==========================================
+ Coverage 73.95% 74.14% +0.18%
==========================================
Files 159 159
Lines 14243 14365 +122
==========================================
+ Hits 10534 10651 +117
- Misses 3709 3714 +5
Continue to review full report at Codecov.
|
61 Windows failures 😩 Merging 😬 |
Tested locally, LGTM. |
🎉 New feature
Edit: Ready for review!
Summary
This PR is an early request-for-feedback on having support for in-memory textures. It reached a "working" state with the gz-common luca/inmemory_textures branch where GLB assets with textures stored as binary blobs (array of bytes containing the file) are correctly parsed and rendered. I.e. below a world with a nurse looking at an ambulance stretcher, both defined as single file GLBs with embedded textures:
Before I refine too much the implementation I'd like to know whether the API makes sense or I should define a different one, specifically:
Right now, to set a texture we currently use the SetTexture method which takes as an input a filename, however we would need to support arbitrary binary blobs in memory for formats with embedded textures to work.
I have a few ideas and currently implemented one but happy to scrap it completely:
Parse images into a gz::common::Image and change SetTexture (or add an overloaded method) to accept a
gz::common::Image
as an input.This would have worked and sounded the cleanest but I was concerned about doing additional processing that might not be needed. For example, we could parse an image and change it into RGBA8 but it is unclear what format might be demanded by downstream users of gz-rendering. For example OGRE2 can parse PNGs straightaway hence if we preprocessed the image we would have unnecessarily inflated the data before copying it around. Also
gz::Image
doesn't expose raw data yet so we would have needed to add an API to set (from compressed) and get raw data, which is what we would have ended up using anyway.Change SetTexture to accept a vector of raw data parameter, set to default empty
I.e. going from:
To
In this case
_texture
would either be a URI or a unique name that can be used to identify the binary texture (to be generated to make sure that if we load multiple instances of the same model through binary blobs we don't duplicate the texture).This feels generally a lot simpler but the ambiguity of the
_texture
argument (URI to a file or unique name) for the two use cases felt a bit unclear.This approach would probably reduce the diff / complexity quite a bit since we can leverage all the existing code and just add a check to the
SetTexture
function and load the texture from memory instead of a file if the_buf
argument is not empty.Brand new overloaded function
This is the approach I went for when prototyping for simplicity but I'm happy to scrap, it currently looks like this:
The tricky part here is that we have to save the texture buffer and name to an internal member to make sure the data is retained when the class is copied around (which seems to happen quite a bit!)
Now it gets ambiguous, if a user calls the normal
SetTexture
and tells the rendering engine "load this file", then calls the overloaded method and tells the engine "load this texture from a binary file" what should the appropriate behavior be? I'm guessing clearing the previous texture, which is fine but again the API is slightly unclear, if you call aSetTexture(URI)
, then somewhere else aSetTexture(binary data)
, then next time you call the getterTexture()
to get the URI the information is gone, or it's not gone but it's not rendered, just a bit tricky.I found this especially tricky to figure out in the custom copy constructor since its result will now depend on the order of operations.
Other considerations
std::vector<>
for the data but noticed while debugging that there are quite a few copies / clones happening behind the scenes and the data gets copied around at least twice (once in the gz-common -> gz-rendering transition and once through a Clone() call). I feel this is a non trivial amount for data that is multiple megabytes per object so happy to move to ashared_ptr
approach if that would help with performance.SetTexture
overloads for all the PBR maps like metalness, roughness, normal, and probably lightmaps, hence it would be good to know the best API to make the diff as simple / manageable as possible@iche033 @chapulina for API feedback!
Test it
Stay tuned!
Checklist
codecheck
passed (See contributing)