Ogre Version: 1.9.1
Operating System: Ubuntu 20.04
Render System: GLX
Hi, I'm still developing something for ROS Noetic, which runs on 20.04 and OGRE 1.9.1, so these things can't be changed (for now, later I'll also make it compatible with newer releases).
Basically, I develop nodelets (ROS terminology), which are plugin-based tasks which can be loaded into a master process (nodelet manager). The nodelet manager has a pool of threads and each registered nodelet runs its incoming data callbacks on these threads. The nodelet manager is a super simple and super general thing that can't be changed and it knows nothing about OGRE, OpenGL or whatever. It just registers the nodelets and runs their callbacks, whatever they do.
The nodelets I develop utilize OGRE to do some rendering to RTTs, which I then read out into CPU memory and send them further as a ROS Image message. So no rendering to screen, at any time.
The problem is that as long as there is only one instance of the nodelet loaded, it works perfectly, but loading any other instance results in weird behavior of the renderers.
I know that using OGRE from multiple threads is difficult, yet I have no other choice (the nodelets cannot choose on which thread their callback will be called). So my general strategy is that the first loaded nodelet sets up all the static infrastructure needed for OGRE, and the other nodelets just reuse it. When it comes to rendering, there is a static mutex locked by each nodelet, so that there are no concurrency problems during the rendering phase itself. I.e., only one rendering call at a time.
Each nodelet creates its own SceneManager, its own RTT texture, its own scene, its own compositors etc. The only things I could not separate are the singletons like Root, RenderSystem etc.
Code: Select all
// The setup() and render() calls for each nodelet both run in a single thread, and the thread is different for each nodelet
void setup()
{
// Here the code checks if Ogre::Root::getSingletonPtr() is null. If it is, it
// does the required OGRE setup. If it is non-null, no setup is done, just
// root->getRenderSystem()->registerThread();
// A separate scene_manager_ for each nodelet / thread
scene_manager_ = root->createSceneManager(Ogre::ST_GENERIC);
default_light_ = scene_manager_->createLight("MainLight");
// some point light setup
scene_manager_->setAmbientLight(Ogre::ColourValue(.5, .5, .5));
scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
// setup the scene
camera_ = scene_manager_->createCamera("RobotModelCamera");
// setup camera
// Create the RTT
tex_ = root->getTextureManager()->createManual(
"MainRenderTarget", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D,
res.width, res.height, 32, 0, this->config.pixelFormat, Ogre::TU_RENDERTARGET);
rt_ = tex_->getBuffer()->getRenderTarget();
viewPort_ = rt_->addViewport(camera_);
viewPort_->setClearEveryFrame(true);
// I add some compositors here to viewPort_, but the problems are even with no compositors
}
void render()
{
static std::mutex renderingMutex;
std::lock_guard<std::mutex> lock(renderingMutex);
rt_->update();
cv::Mat rectImg(rectRows, rectCols, this->cvImageType);
const Ogre::PixelBox pb(rt_->getWidth(), rt_->getHeight(), 1, this->config.pixelFormat, rectImg.data);
rt_->copyContentsToMemory(pb);
}
I face several problems:
Even with no compositor, only the first RTT is rendered correctly. The other RTTs seem like they have somehow weirdly set up lighting (as if the only point light I have was looking at the scene from a wrong point, and the ambient light did nothing).
When I add compositors, they also behave weird. I created the simplest possible compositor just to test this:
Code: Select all
Test.compositor:
compositor Test
{
technique
{
target_output
{
input previous
pass render_quad
{
material TestMat
}
}
}
}
TestMat.material:
fragment_program TestFS glsl
{
source test_fs.glsl
}
material TestMat
{
technique
{
pass
{
fragment_program_ref TestFS { }
}
}
}
test_fs.glsl:
void main()
{
gl_FragColor.r = 1.0;
gl_FragColor.g = 0.0;
gl_FragColor.b = 1.0;
gl_FragColor.a = 1.0;
}
This compositor added to the first RTT works correctly and results in a full pink image. On the second instance of RTT, I get only the wrongly lit model as described in issue 1. If I change "input previous" to "input none", I get a 0,0,0,0 image.
However, if I change "render_quad" to "render_scene", the second RTT again contains the same wrongly lit model (or, with a clear pass, I get a correctly cleared output). So the compositor itself works, it is just the render_quad that works wrong (and the rendering of the scene, as described in issue 1).
Here are a few images. These are the RTT contents of the very same scene, with identical scene setup, lighting, materials etc:
First RTT:
Any other RTT:
I also created a simplified material to just render everything in red color:
Code: Select all
color_material_ = Ogre::MaterialPtr(new Ogre::Material(
nullptr, material_name, 0, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME));
color_material_->setReceiveShadows(false);
color_material_->getTechnique(0)->setLightingEnabled(true);
Ogre::ColourValue color = color_material_->getTechnique(0)->getPass(0)->getDiffuse();
color.r = 1;
color.g = 0;
color.b = 0;
color_material_->getTechnique(0)->setAmbient(0.5 * color);
color_material_->getTechnique(0)->setDiffuse(color);
And these are the results:
First RTT:
Any other RTT:
So it seems that in the other RTTs, it somehow ignores this custom material and it always uses the mesh-embedded one (plus the incorrect lighting). If you inspect the last image closely, you'll see the lower left part of the image has a blue-y shade, which corresponds to the blue color in the proper image with embedded materials (the very first one).
Do you have any idea what other kind of setup is needed per thread to get all RTTs rendering correctly?




