Skip to content
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

Optionally disable "render back faces" for the shadow caster #3117

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions gazebo/physics/World.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,13 @@ void World::Load(sdf::ElementPtr _sdf)
this->dataPtr->sdf->GetElement("scene")->
Get<std::string>("ignition:shadow_caster_material_name");
}
else

if (this->dataPtr->sdf->GetElement("scene")->
HasElement("ignition:shadow_caster_render_back_faces"))
{
this->dataPtr->shadowCasterMaterialName = "Gazebo/shadow_caster";
this->dataPtr->shadowCasterRenderBackFaces =
this->dataPtr->sdf->GetElement("scene")->
Get<bool>("ignition:shadow_caster_render_back_faces");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks fine. I think if we plane to add more shadow params in the future, we can consider adding a <shadows> </shadows> section to group these parameters


// The period at which messages are processed
Expand Down Expand Up @@ -296,12 +300,21 @@ void World::Load(sdf::ElementPtr _sdf)
<< std::endl;
}

std::string shadowCasterService("/shadow_caster_material_name");
if (!this->dataPtr->ignNode.Advertise(shadowCasterService,
&World::ShadowCasterService, this))
std::string shadowCasterMaterialNameService("/shadow_caster_material_name");
if (!this->dataPtr->ignNode.Advertise(shadowCasterMaterialNameService,
&World::ShadowCasterMaterialNameService, this))
{
gzerr << "Error advertising service [" << shadowCasterService << "]"
<< std::endl;
gzerr << "Error advertising service [" <<
shadowCasterMaterialNameService << "]" << std::endl;
}

std::string shadowCasterRenderBackFacesService(
"/shadow_caster_render_back_faces");
if (!this->dataPtr->ignNode.Advertise(shadowCasterRenderBackFacesService,
&World::ShadowCasterRenderBackFacesService, this))
{
gzerr << "Error advertising service [" <<
shadowCasterRenderBackFacesService << "]" << std::endl;
}

// This should come before loading of entities
Expand Down Expand Up @@ -3368,8 +3381,15 @@ bool World::PluginInfoService(const ignition::msgs::StringMsg &_req,
}

//////////////////////////////////////////////////
bool World::ShadowCasterService(ignition::msgs::StringMsg &_res)
bool World::ShadowCasterMaterialNameService(ignition::msgs::StringMsg &_res)
{
_res.set_data(this->dataPtr->shadowCasterMaterialName.c_str());
return true;
}

//////////////////////////////////////////////////
bool World::ShadowCasterRenderBackFacesService(ignition::msgs::Boolean &_res)
{
_res.set_data(this->dataPtr->shadowCasterRenderBackFaces);
return true;
}
12 changes: 11 additions & 1 deletion gazebo/physics/World.hh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace ignition
{
class Plugin_V;
class StringMsg;
class Boolean;
}
}

Expand Down Expand Up @@ -654,7 +655,16 @@ namespace gazebo
/// \brief Callback for "<this_name>/shadow_caster_material_name" service.
/// \param[out] _response Message containing shadow caster material name
/// \return True if the info was successfully obtained.
private: bool ShadowCasterService(ignition::msgs::StringMsg &_response);
private: bool ShadowCasterMaterialNameService(
ignition::msgs::StringMsg &_response);

/// \brief Callback for "<this_name>/shadow_caster_render_back_faces"
/// service.
/// \param[out] _response Message containing shadow caster render back
/// faces
/// \return True if the info was successfully obtained.
private: bool ShadowCasterRenderBackFacesService(
ignition::msgs::Boolean &_response);

/// \internal
/// \brief Private data pointer.
Expand Down
5 changes: 4 additions & 1 deletion gazebo/physics/WorldPrivate.hh
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,10 @@ namespace gazebo
public: std::unique_ptr<sdf::World> worldSDFDom;

/// \brief Shadow caster material name from scene SDF
public: std::string shadowCasterMaterialName;
public: std::string shadowCasterMaterialName = "Gazebo/shadow_caster";

/// \brief Shadow caster render back faces from scene SDF
public: bool shadowCasterRenderBackFaces = true;
};
}
}
Expand Down
3 changes: 2 additions & 1 deletion gazebo/rendering/RTShaderSystem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,8 @@ void RTShaderSystem::UpdateShadows(ScenePtr _scene)
#endif

sceneMgr->setShadowTextureSelfShadow(false);
sceneMgr->setShadowCasterRenderBackFaces(true);
sceneMgr->setShadowCasterRenderBackFaces(
_scene->ShadowCasterRenderBackFaces());

// TODO: We have two different shadow caster materials, both taken from
// OGRE samples. They should be compared and tested.
Expand Down
60 changes: 45 additions & 15 deletions gazebo/rendering/Scene.cc
Original file line number Diff line number Diff line change
Expand Up @@ -207,24 +207,48 @@ Scene::Scene(const std::string &_name, const bool _enableVisualizations,
this->dataPtr->sceneSimTimePosesApplied = common::Time();
this->dataPtr->sceneSimTimePosesReceived = common::Time();

// Get shadow caster material name from physics::World
ignition::transport::Node node;
ignition::msgs::StringMsg rep;
const std::string serviceName = "/shadow_caster_material_name";
bool result;
unsigned int timeout = 5000;
bool executed = node.Request(serviceName,
timeout, rep, result);
if (executed)
{
if (result)
this->dataPtr->shadowCasterMaterialName = rep.data();
{
// Get shadow caster material name from physics::World
ignition::transport::Node node;
ignition::msgs::StringMsg rep;
const std::string serviceName = "/shadow_caster_material_name";
bool result;
unsigned int timeout = 5000;
bool executed = node.Request(serviceName,
timeout, rep, result);
if (executed)
{
if (result)
this->dataPtr->shadowCasterMaterialName = rep.data();
else
gzerr << "Service call[" << serviceName << "] failed" << std::endl;
}
else
gzerr << "Service call[" << serviceName << "] failed" << std::endl;
{
gzerr << "Service call[" << serviceName << "] timed out" << std::endl;
}
}
else

{
gzerr << "Service call[" << serviceName << "] timed out" << std::endl;
// Get shadow caster render back faces from physics::World
ignition::transport::Node node;
ignition::msgs::Boolean rep;
const std::string serviceName = "/shadow_caster_render_back_faces";
bool result;
unsigned int timeout = 5000;
bool executed = node.Request(serviceName,
timeout, rep, result);
if (executed)
{
if (result)
this->dataPtr->shadowCasterRenderBackFaces = rep.data();
else
gzerr << "Service call[" << serviceName << "] failed" << std::endl;
}
else
{
gzerr << "Service call[" << serviceName << "] timed out" << std::endl;
}
}
}

Expand Down Expand Up @@ -3311,6 +3335,12 @@ std::string Scene::ShadowCasterMaterialName() const
return this->dataPtr->shadowCasterMaterialName;
}

/////////////////////////////////////////////////
bool Scene::ShadowCasterRenderBackFaces() const
{
return this->dataPtr->shadowCasterRenderBackFaces;
}

/////////////////////////////////////////////////
void Scene::AddVisual(VisualPtr _vis)
{
Expand Down
4 changes: 4 additions & 0 deletions gazebo/rendering/Scene.hh
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ namespace gazebo
/// \return Name of the shadow caster material
public: std::string ShadowCasterMaterialName() const;

/// \brief Get the shadow caster render back faces
/// \return Shadow caster render back faces
public: bool ShadowCasterRenderBackFaces() const;

/// \brief Add a visual to the scene
/// \param[in] _vis Visual to add.
public: void AddVisual(VisualPtr _vis);
Expand Down
3 changes: 3 additions & 0 deletions gazebo/rendering/ScenePrivate.hh
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,9 @@ namespace gazebo

/// \brief Shadow caster material name
public: std::string shadowCasterMaterialName = "Gazebo/shadow_caster";

/// \brief Shadow caster render back faces
public: bool shadowCasterRenderBackFaces = true;
};
}
}
Expand Down
1 change: 1 addition & 0 deletions test/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ set(tests
sensor.cc
sdf_frame_semantics.cc
server_fixture.cc
shadow_caster_render_back_faces.cc
sim_events.cc
speed.cc
speed_thread_islands.cc
Expand Down
175 changes: 175 additions & 0 deletions test/integration/shadow_caster_render_back_faces.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* Copyright (C) 2021 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

#include "gazebo/test/ServerFixture.hh"
#include "gazebo/sensors/sensors.hh"

using namespace gazebo;
class ShadowCasterRenderBackFacesTest : public ServerFixture
{
/// \brief Test rendering back faces
public: void ShadowCasterBackFaces();

/// \brief Test rendering without back face
public: void ShadowCasterNoBackFaces();

/// \brief Counter for the numbder of image messages received.
public: unsigned int imageCount = 0u;

/// \brief Depth data buffer.
public: unsigned char* imageBuffer = nullptr;

/// \brief Camera image callback
/// \param[in] _msg Message with image data containing raw image values.
public: void OnImage(ConstImageStampedPtr &_msg);
};

/////////////////////////////////////////////////
void ShadowCasterRenderBackFacesTest::OnImage(ConstImageStampedPtr &_msg)
{
unsigned int imageSamples = _msg->image().width() *_msg->image().height() * 3;
memcpy(this->imageBuffer, _msg->image().data().c_str(), imageSamples);
this->imageCount++;
}

/////////////////////////////////////////////////
// \brief The shadow caster will render back faces; The plane in the world will
/// cast a shadow
void ShadowCasterRenderBackFacesTest::ShadowCasterBackFaces()
{
this->Load("worlds/shadow_caster_back_faces.world");

// Make sure the render engine is available.
if (rendering::RenderEngine::Instance()->GetRenderPathType() ==
rendering::RenderEngine::NONE)
{
gzerr << "No rendering engine, unable to run camera test\n";
return;
}

sensors::CameraSensorPtr sensor =
std::dynamic_pointer_cast<sensors::CameraSensor>(
sensors::get_sensor("camera_normal"));
EXPECT_TRUE(sensor != nullptr);
EXPECT_TRUE(sensor->IsActive());

unsigned int width = 320;
unsigned int height = 240;

this->imageCount = 0;
this->imageBuffer = new unsigned char[width * height*3];

transport::NodePtr node(new transport::Node());
node->Init();

std::string topic = sensor->Topic();
EXPECT_TRUE(!topic.empty());

transport::SubscriberPtr sub = node->Subscribe(topic,
&ShadowCasterRenderBackFacesTest::OnImage, this);

// wait for a few images
int i = 0;
while (this->imageCount < 10 && i < 300)
{
common::Time::MSleep(10);
i++;
}
EXPECT_LT(i, 300);

for (unsigned int x = 0; x < 320 * 240; x += 600) {
EXPECT_GT(50, this->imageBuffer[3 * x]);
EXPECT_GT(50, this->imageBuffer[3 * x + 1]);
EXPECT_GT(50, this->imageBuffer[3 * x + 2]);
}

delete this->imageBuffer;
}

/////////////////////////////////////////////////
TEST_F(ShadowCasterRenderBackFacesTest, ShadowCasterBackFaces)
{
ShadowCasterBackFaces();
}

/////////////////////////////////////////////////
// \brief The shadow caster will not render back faces; The plane in the world
/// will not cast a shadow
void ShadowCasterRenderBackFacesTest::ShadowCasterNoBackFaces()
{
this->Load("worlds/shadow_caster_no_back_faces.world");

// Make sure the render engine is available.
if (rendering::RenderEngine::Instance()->GetRenderPathType() ==
rendering::RenderEngine::NONE)
{
gzerr << "No rendering engine, unable to run camera test\n";
return;
}

sensors::CameraSensorPtr sensor =
std::dynamic_pointer_cast<sensors::CameraSensor>(
sensors::get_sensor("camera_normal"));
EXPECT_TRUE(sensor != nullptr);
EXPECT_TRUE(sensor->IsActive());

unsigned int width = 320;
unsigned int height = 240;

this->imageCount = 0;
this->imageBuffer = new unsigned char[width * height*3];

transport::NodePtr node(new transport::Node());
node->Init();

std::string topic = sensor->Topic();
EXPECT_TRUE(!topic.empty());

transport::SubscriberPtr sub = node->Subscribe(topic,
&ShadowCasterRenderBackFacesTest::OnImage, this);

// wait for a few images
int i = 0;
while (this->imageCount < 10 && i < 300)
{
common::Time::MSleep(10);
i++;
}
EXPECT_LT(i, 300);

for (unsigned int x = 0; x < 320 * 240; x += 600) {
EXPECT_LT(50, this->imageBuffer[3 * x]);
EXPECT_LT(50, this->imageBuffer[3 * x + 1]);
EXPECT_LT(50, this->imageBuffer[3 * x + 2]);
}

delete this->imageBuffer;
}

/////////////////////////////////////////////////
TEST_F(ShadowCasterRenderBackFacesTest, ShadowCasterNoBackFaces)
{
ShadowCasterNoBackFaces();
}

/////////////////////////////////////////////////
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

2 changes: 1 addition & 1 deletion test/worlds/custom_shadow_caster.world
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<image>
<width>320</width>
<height>240</height>
<format>R8G8B8</format>\
<format>R8G8B8</format>
</image>
<clip>
<near>0.1</near>
Expand Down
Loading