Skip to content

Commit

Permalink
SceneGraph modifies/access renderer in the context. (RobotLocomotion#…
Browse files Browse the repository at this point in the history
…20355)

Previously we only provide API to modify/query the renderer in the SceneGraph
 model. Now we provide API to modify/query the renderer in the context.
  • Loading branch information
hongkai-dai authored and WawasCode committed Oct 31, 2023
1 parent 91ebbd3 commit 0bd16b0
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 16 deletions.
49 changes: 42 additions & 7 deletions bindings/pydrake/geometry/geometry_py_scene_graph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,48 @@ void DoScalarDependentDefinitions(py::module m, T) {
overload_cast_explicit<CollisionFilterManager>(
&Class::collision_filter_manager),
cls_doc.collision_filter_manager.doc_0args)
.def("AddRenderer", &Class::AddRenderer, py::arg("name"),
py::arg("renderer"), cls_doc.AddRenderer.doc)
.def("RemoveRenderer", &Class::RemoveRenderer, py::arg("name"),
cls_doc.RemoveRenderer.doc)
.def("HasRenderer", &Class::HasRenderer, py::arg("name"),
cls_doc.HasRenderer.doc)
.def("RendererCount", &Class::RendererCount, cls_doc.RendererCount.doc)
.def("AddRenderer",
overload_cast_explicit<void, std::string,
std::unique_ptr<render::RenderEngine>>(&Class::AddRenderer),
py::arg("name"), py::arg("renderer"), cls_doc.AddRenderer.doc_2args)
.def("AddRenderer",
overload_cast_explicit<void, systems::Context<T>*, std::string,
std::unique_ptr<render::RenderEngine>>(&Class::AddRenderer),
py::arg("context"), py::arg("name"), py::arg("renderer"),
cls_doc.AddRenderer.doc_3args)
.def("RemoveRenderer",
overload_cast_explicit<void, const std::string&>(
&Class::RemoveRenderer),
py::arg("name"), cls_doc.RemoveRenderer.doc_1args)
.def("RemoveRenderer",
overload_cast_explicit<void, systems::Context<T>*,
const std::string&>(&Class::RemoveRenderer),
py::arg("context"), py::arg("name"),
cls_doc.RemoveRenderer.doc_2args)
.def("HasRenderer",
overload_cast_explicit<bool, const std::string&>(
&Class::HasRenderer),
py::arg("name"), cls_doc.HasRenderer.doc_1args)
.def("HasRenderer",
overload_cast_explicit<bool, const systems::Context<T>&,
const std::string&>(&Class::HasRenderer),
py::arg("context"), py::arg("name"), cls_doc.HasRenderer.doc_2args)
.def("RendererCount",
overload_cast_explicit<int>(&Class::RendererCount),
cls_doc.RendererCount.doc_0args)
.def("RendererCount",
overload_cast_explicit<int, const systems::Context<T>&>(
&Class::RendererCount),
py::arg("context"), cls_doc.RendererCount.doc_1args)
.def("GetRendererTypeName",
overload_cast_explicit<std::string, const std::string&>(
&Class::GetRendererTypeName),
py::arg("name"), cls_doc.GetRendererTypeName.doc_1args)
.def("GetRendererTypeName",
overload_cast_explicit<std::string, const systems::Context<T>&,
const std::string&>(&Class::GetRendererTypeName),
py::arg("context"), py::arg("name"),
cls_doc.GetRendererTypeName.doc_2args)
// - Begin: AssignRole Overloads.
// - - Proximity.
.def(
Expand Down
34 changes: 29 additions & 5 deletions bindings/pydrake/geometry/test/scene_graph_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,21 @@ def test_scene_graph_api(self, T):
scene_graph.get_query_output_port(), OutputPort)

# Test limited rendering API.
scene_graph.AddRenderer("test_renderer",
renderer_name = "test_renderer"
scene_graph.AddRenderer(renderer_name,
mut.MakeRenderEngineVtk(
mut.RenderEngineVtkParams()))
self.assertTrue(scene_graph.HasRenderer("test_renderer"))
self.assertTrue(scene_graph.HasRenderer(renderer_name))
self.assertEqual(scene_graph.RendererCount(), 1)
renderer_type_name = scene_graph.GetRendererTypeName(
name=renderer_name)

scene_graph.RemoveRenderer("test_renderer")
self.assertFalse(scene_graph.HasRenderer("test_renderer"))
scene_graph.RemoveRenderer(renderer_name)
self.assertFalse(scene_graph.HasRenderer(renderer_name))
self.assertEqual(scene_graph.RendererCount(), 0)

# Now add the renderer back.
scene_graph.AddRenderer("test_renderer",
scene_graph.AddRenderer(renderer_name,
mut.MakeRenderEngineVtk(
mut.RenderEngineVtkParams()))

Expand Down Expand Up @@ -327,6 +330,27 @@ def test_scene_graph_api(self, T):
frame_id=global_frame, role=role),
1 if i == 0 else 0)

@numpy_compare.check_all_types
def test_scene_graph_renderer_with_context(self, T):
SceneGraph = mut.SceneGraph_[T]
scene_graph = SceneGraph()
context = scene_graph.CreateDefaultContext()
self.assertEqual(scene_graph.RendererCount(context), 0)
render_params = mut.RenderEngineVtkParams()
renderer_name = "test_renderer"
self.assertFalse(
scene_graph.HasRenderer(context=context, name=renderer_name))
scene_graph.AddRenderer(
context=context, name=renderer_name,
renderer=mut.MakeRenderEngineVtk(params=render_params))
self.assertEqual(scene_graph.RendererCount(context=context), 1)
self.assertTrue(
scene_graph.HasRenderer(context=context, name=renderer_name))
scene_graph.RemoveRenderer(context=context, name=renderer_name)
self.assertEqual(scene_graph.RendererCount(context=context), 0)
renderer_type_name = scene_graph.GetRendererTypeName(
context=context, name=renderer_name)

@numpy_compare.check_all_types
def test_scene_graph_register_geometry(self, T):
SceneGraph = mut.SceneGraph_[T]
Expand Down
47 changes: 47 additions & 0 deletions geometry/scene_graph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -262,16 +262,38 @@ void SceneGraph<T>::AddRenderer(
return model_.AddRenderer(std::move(name), std::move(renderer));
}

template <typename T>
void SceneGraph<T>::AddRenderer(
Context<T>* context, std::string name,
std::unique_ptr<render::RenderEngine> renderer) const {
auto& g_state = mutable_geometry_state(context);
g_state.AddRenderer(std::move(name), std::move(renderer));
}

template <typename T>
void SceneGraph<T>::RemoveRenderer(const std::string& name) {
return model_.RemoveRenderer(name);
}

template <typename T>
void SceneGraph<T>::RemoveRenderer(Context<T>* context,
const std::string& name) const {
auto& g_state = mutable_geometry_state(context);
g_state.RemoveRenderer(name);
}

template <typename T>
bool SceneGraph<T>::HasRenderer(const std::string& name) const {
return model_.HasRenderer(name);
}

template <typename T>
bool SceneGraph<T>::HasRenderer(const Context<T>& context,
const std::string& name) const {
const auto& g_state = geometry_state(context);
return g_state.HasRenderer(name);
}

template <typename T>
std::string SceneGraph<T>::GetRendererTypeName(const std::string& name) const {
const render::RenderEngine* engine = model_.GetRenderEngineByName(name);
Expand All @@ -282,16 +304,41 @@ std::string SceneGraph<T>::GetRendererTypeName(const std::string& name) const {
return NiceTypeName::Get(*engine);
}

template <typename T>
std::string SceneGraph<T>::GetRendererTypeName(const Context<T>& context,
const std::string& name) const {
const auto& g_state = geometry_state(context);
const render::RenderEngine* engine = g_state.GetRenderEngineByName(name);
if (engine == nullptr) {
return {};
}

return NiceTypeName::Get(*engine);
}

template <typename T>
int SceneGraph<T>::RendererCount() const {
return model_.RendererCount();
}

template <typename T>
int SceneGraph<T>::RendererCount(const Context<T>& context) const {
const auto& g_state = geometry_state(context);
return g_state.RendererCount();
}

template <typename T>
vector<std::string> SceneGraph<T>::RegisteredRendererNames() const {
return model_.RegisteredRendererNames();
}

template <typename T>
vector<std::string> SceneGraph<T>::RegisteredRendererNames(
const Context<T>& context) const {
const auto& g_state = geometry_state(context);
return g_state.RegisteredRendererNames();
}

template <typename T>
void SceneGraph<T>::AssignRole(SourceId source_id, GeometryId geometry_id,
ProximityProperties properties,
Expand Down
35 changes: 35 additions & 0 deletions geometry/scene_graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -705,16 +705,34 @@ class SceneGraph final : public systems::LeafSystem<T> {
void AddRenderer(std::string name,
std::unique_ptr<render::RenderEngine> renderer);

/** systems::Context-modifying variant of AddRenderer(). Rather than
modifying %SceneGraph's model, it modifies the copy of the model stored in
the provided context. */
void AddRenderer(systems::Context<T>* context, std::string name,
std::unique_ptr<render::RenderEngine> renderer) const;

/** Removes an existing renderer from this %SceneGraph
@param name The unique name of the renderer to be removed.
@throws std::exception if this %SceneGraph doesn't have a renderer with the
specified name. */
void RemoveRenderer(const std::string& name);

/** systems::Context-modifying variant of RemoveRenderer(). Rather than
modifying %SceneGraph's model, it modifies the copy of the model stored in
the provided context. */
void RemoveRenderer(systems::Context<T>* context,
const std::string& name) const;

/** Reports true if this %SceneGraph has a renderer registered with the given
name. */
bool HasRenderer(const std::string& name) const;

/** systems::Context-query variant of HasRenderer(). Rather than querying
%SceneGraph's model, it queries the copy of the model stored in the
provided context. */
bool HasRenderer(const systems::Context<T>& context,
const std::string& name) const;

/** Reports the type name for the RenderEngine registered with the given
`name`.
Expand All @@ -723,12 +741,29 @@ class SceneGraph final : public systems::LeafSystem<T> {
registered with the given `name`. */
std::string GetRendererTypeName(const std::string& name) const;

/** systems::Context-query variant of GetRendererTypeName(). Rather than
querying %SceneGraph's model, it queries the copy of the model stored in the
provided context. */
std::string GetRendererTypeName(const systems::Context<T>& context,
const std::string& name) const;

/** Reports the number of renderers registered to this %SceneGraph. */
int RendererCount() const;

/** systems::Context-query variant of RendererCount(). Rather than querying
%SceneGraph's model, it queries the copy of the model stored in the
provided context. */
int RendererCount(const systems::Context<T>& context) const;

/** Reports the names of all registered renderers. */
std::vector<std::string> RegisteredRendererNames() const;

/** systems::Context-query variant of RegisteredRendererNames(). Rather than
querying %SceneGraph's model, it queries the copy of the model stored in the
provided context. */
std::vector<std::string> RegisteredRendererNames(
const systems::Context<T>& context) const;

//@}

/** @name Managing geometry roles
Expand Down
44 changes: 40 additions & 4 deletions geometry/test/scene_graph_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,8 @@ TEST_F(SceneGraphTest, ModelInspector) {
// configuration/introspection code. These tests are just smoke tests that the
// functions work. It relies on GeometryState to properly unit test the
// full behavior.
TEST_F(SceneGraphTest, RendererSmokeTest) {
TEST_F(SceneGraphTest, RendererInSceneGraphSmokeTest) {
// Test the renderer added to the SceneGraph.
const std::string kRendererName = "bob";

EXPECT_EQ(scene_graph_.RendererCount(), 0);
Expand All @@ -516,21 +517,56 @@ TEST_F(SceneGraphTest, RendererSmokeTest) {
EXPECT_EQ(scene_graph_.RendererCount(), 1);
EXPECT_EQ(scene_graph_.RegisteredRendererNames()[0], kRendererName);
EXPECT_TRUE(scene_graph_.HasRenderer(kRendererName));

DRAKE_EXPECT_NO_THROW(scene_graph_.RemoveRenderer(kRendererName));
EXPECT_EQ(scene_graph_.RendererCount(), 0);
EXPECT_FALSE(scene_graph_.HasRenderer(kRendererName));
}

TEST_F(SceneGraphTest, RendererInContextSmokeTest) {
// Test the renderer added to the context
CreateDefaultContext();
const std::string kRendererName = "bob";

EXPECT_EQ(scene_graph_.RendererCount(*context_), 0);
EXPECT_EQ(scene_graph_.RegisteredRendererNames(*context_).size(), 0u);
EXPECT_FALSE(scene_graph_.HasRenderer(*context_, kRendererName));

DRAKE_EXPECT_NO_THROW(scene_graph_.AddRenderer(
context_.get(), kRendererName, make_unique<DummyRenderEngine>()));

EXPECT_EQ(scene_graph_.RendererCount(*context_), 1);
// No renderer inside SceneGraph since the renderer is added to the context.
EXPECT_EQ(scene_graph_.RendererCount(), 0);
EXPECT_EQ(scene_graph_.RegisteredRendererNames(*context_)[0], kRendererName);
EXPECT_TRUE(scene_graph_.HasRenderer(*context_, kRendererName));

DRAKE_EXPECT_NO_THROW(
scene_graph_.RemoveRenderer(context_.get(), kRendererName));
EXPECT_EQ(scene_graph_.RendererCount(*context_), 0);
EXPECT_FALSE(scene_graph_.HasRenderer(*context_, kRendererName));
}

// Query the type name of a render engine. This logic is unique to SceneGraph
// so we test it here.
TEST_F(SceneGraphTest, GetRendererTypeName) {
const std::string kRendererName = "bob";
const std::string kRendererName1 = "bob";
const std::string kRendererName2 = "alice";

CreateDefaultContext();
DRAKE_EXPECT_NO_THROW(scene_graph_.AddRenderer(
kRendererName, make_unique<DummyRenderEngine>()));
kRendererName1, make_unique<DummyRenderEngine>()));
DRAKE_EXPECT_NO_THROW(scene_graph_.AddRenderer(
context_.get(), kRendererName2, make_unique<DummyRenderEngine>()));

// If no renderer has the name, the type doesn't matter.
EXPECT_EQ(scene_graph_.GetRendererTypeName("non-existent"), "");
EXPECT_EQ(scene_graph_.GetRendererTypeName(*context_, "non-existent"), "");

// Get the expected name.
EXPECT_EQ(scene_graph_.GetRendererTypeName(kRendererName),
EXPECT_EQ(scene_graph_.GetRendererTypeName(kRendererName1),
NiceTypeName::Get<DummyRenderEngine>());
EXPECT_EQ(scene_graph_.GetRendererTypeName(*context_, kRendererName2),
NiceTypeName::Get<DummyRenderEngine>());
}

Expand Down

0 comments on commit 0bd16b0

Please sign in to comment.