281 lines
8.4 KiB
C++
281 lines
8.4 KiB
C++
|
/*
|
||
|
* Copyright (C) 2012 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.
|
||
|
*
|
||
|
*/
|
||
|
#ifdef _WIN32
|
||
|
// Ensure that Winsock2.h is included before Windows.h, which can get
|
||
|
// pulled in by anybody (e.g., Boost).
|
||
|
#include <Winsock2.h>
|
||
|
#endif
|
||
|
|
||
|
#include <boost/program_options.hpp>
|
||
|
|
||
|
#include "gazebo/msgs/msgs.hh"
|
||
|
#include "gazebo/transport/transport.hh"
|
||
|
#include "gazebo/sensors/SensorsIface.hh"
|
||
|
#include "ModelPropShop.hh"
|
||
|
|
||
|
using namespace gazebo;
|
||
|
namespace po = boost::program_options;
|
||
|
|
||
|
// Register this plugin with the simulator
|
||
|
GZ_REGISTER_SYSTEM_PLUGIN(ModelPropShop)
|
||
|
|
||
|
/////////////////////////////////////////////
|
||
|
ModelPropShop::~ModelPropShop()
|
||
|
{
|
||
|
rendering::fini();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////
|
||
|
void ModelPropShop::Load(int _argc, char **_argv)
|
||
|
{
|
||
|
// Turn off sensors.
|
||
|
gazebo::sensors::disable();
|
||
|
|
||
|
po::options_description v_desc("Options");
|
||
|
v_desc.add_options()
|
||
|
("propshop-save", po::value<std::string>(),
|
||
|
"Path to save image files into.")
|
||
|
("propshop-model", po::value<std::string>(), "Model to spawn.");
|
||
|
|
||
|
po::options_description desc("Options");
|
||
|
desc.add(v_desc);
|
||
|
|
||
|
po::variables_map vm;
|
||
|
try
|
||
|
{
|
||
|
po::store(po::command_line_parser(_argc, _argv).options(
|
||
|
desc).allow_unregistered().run(), vm);
|
||
|
po::notify(vm);
|
||
|
} catch(boost::exception &_e)
|
||
|
{
|
||
|
std::cerr << "Error. Invalid arguments\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get the directory in which to save the images.
|
||
|
if (vm.count("propshop-save"))
|
||
|
{
|
||
|
this->savePath = boost::filesystem::path(
|
||
|
vm["propshop-save"].as<std::string>());
|
||
|
if (!boost::filesystem::exists(this->savePath))
|
||
|
boost::filesystem::create_directories(this->savePath);
|
||
|
}
|
||
|
else
|
||
|
this->savePath = boost::filesystem::temp_directory_path();
|
||
|
|
||
|
std::string modelFile;
|
||
|
|
||
|
if (vm.count("propshop-model"))
|
||
|
modelFile = vm["propshop-model"].as<std::string>();
|
||
|
else
|
||
|
return;
|
||
|
|
||
|
std::ifstream ifs(modelFile.c_str());
|
||
|
if (!ifs)
|
||
|
{
|
||
|
std::cerr << "Error: Unable to open file[" << modelFile << "]\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this->sdf.reset(new sdf::SDF());
|
||
|
if (!sdf::init(this->sdf))
|
||
|
{
|
||
|
std::cerr << "ERROR: SDF parsing the xml failed" << std::endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!sdf::readFile(modelFile, this->sdf))
|
||
|
{
|
||
|
std::cerr << "Error: SDF parsing the xml failed\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdf::ElementPtr modelElem = this->sdf->Root()->GetElement("model");
|
||
|
this->modelName = modelElem->Get<std::string>("name");
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////
|
||
|
void ModelPropShop::Init()
|
||
|
{
|
||
|
this->worldCreatedConn = event::Events::ConnectWorldCreated(
|
||
|
boost::bind(&ModelPropShop::OnWorldCreated, this));
|
||
|
|
||
|
this->updateConn = event::Events::ConnectWorldUpdateBegin(
|
||
|
boost::bind(&ModelPropShop::Update, this));
|
||
|
|
||
|
this->node = transport::NodePtr(new transport::Node());
|
||
|
this->node->Init();
|
||
|
this->pub = this->node->Advertise<msgs::ServerControl>(
|
||
|
"/gazebo/server/control");
|
||
|
|
||
|
this->factoryPub = this->node->Advertise<msgs::Factory>("~/factory");
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////
|
||
|
void ModelPropShop::OnWorldCreated()
|
||
|
{
|
||
|
this->factoryPub->WaitForConnection();
|
||
|
|
||
|
if (this->sdf)
|
||
|
{
|
||
|
msgs::Factory msg;
|
||
|
msg.set_sdf(this->sdf->ToString());
|
||
|
this->factoryPub->Publish(msg, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////
|
||
|
void ModelPropShop::Update()
|
||
|
{
|
||
|
// Make sure to initialize the rendering engine in the same thread that will
|
||
|
// capture images.
|
||
|
if (!this->scene)
|
||
|
{
|
||
|
rendering::load();
|
||
|
rendering::init();
|
||
|
|
||
|
sdf::ElementPtr cameraSDF(new sdf::Element);
|
||
|
sdf::initFile("camera.sdf", cameraSDF);
|
||
|
|
||
|
this->scene = rendering::create_scene("default", false, true);
|
||
|
this->camera = this->scene->CreateCamera("propshopcamera", false);
|
||
|
this->camera->SetCaptureData(true);
|
||
|
this->camera->Load(cameraSDF);
|
||
|
this->camera->Init();
|
||
|
this->camera->SetHFOV(static_cast<ignition::math::Angle>(IGN_DTOR(60)));
|
||
|
this->camera->SetImageWidth(960);
|
||
|
this->camera->SetImageHeight(540);
|
||
|
this->camera->CreateRenderTexture("ModelPropShop_RttTex");
|
||
|
|
||
|
// Create a light
|
||
|
gazebo::msgs::Light lightMsg;
|
||
|
lightMsg.set_name("propshop_light");
|
||
|
lightMsg.set_type(gazebo::msgs::Light::DIRECTIONAL);
|
||
|
gazebo::msgs::Set(lightMsg.mutable_diffuse(),
|
||
|
gazebo::common::Color(1, 1, 1, 1));
|
||
|
gazebo::msgs::Set(lightMsg.mutable_specular(),
|
||
|
gazebo::common::Color(.2, .2, .2, 1));
|
||
|
gazebo::msgs::Set(lightMsg.mutable_direction(),
|
||
|
ignition::math::Vector3d(-0.5, 0.1, -0.9));
|
||
|
lightMsg.set_cast_shadows(false);
|
||
|
lightMsg.set_range(1000);
|
||
|
lightMsg.set_attenuation_constant(1);
|
||
|
lightMsg.set_attenuation_linear(0);
|
||
|
lightMsg.set_attenuation_quadratic(0);
|
||
|
|
||
|
this->light.reset(new gazebo::rendering::Light(this->scene));
|
||
|
light->LoadFromMsg(lightMsg);
|
||
|
gazebo::rendering::RTShaderSystem::Instance()->UpdateShaders();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (this->camera && this->scene)
|
||
|
event::Events::preRender();
|
||
|
|
||
|
if (this->camera && this->scene->Initialized() &&
|
||
|
this->camera->Initialized())
|
||
|
{
|
||
|
rendering::VisualPtr vis = this->scene->GetVisual(this->modelName);
|
||
|
if (vis)
|
||
|
{
|
||
|
math::Box bbox = vis->GetBoundingBox();
|
||
|
|
||
|
// Compute model scaling.
|
||
|
double scaling = 1.0 / bbox.GetSize().GetMax();
|
||
|
|
||
|
// Compute the model translation.
|
||
|
math::Vector3 trans = bbox.GetCenter();
|
||
|
trans *= -scaling;
|
||
|
|
||
|
// Normalize the size of the visual
|
||
|
vis->SetScale(math::Vector3(scaling, scaling, scaling));
|
||
|
vis->SetWorldPose(math::Pose(trans.x, trans.y, trans.z, 0, 0, 0));
|
||
|
|
||
|
// Place the visual at the origin
|
||
|
bbox = vis->GetBoundingBox();
|
||
|
|
||
|
ignition::math::Pose3d pose;
|
||
|
|
||
|
// Perspective view
|
||
|
pose.Pos().Set(1.6, -1.6, 1.2);
|
||
|
pose.Rot().Euler(0, IGN_DTOR(30), IGN_DTOR(-225));
|
||
|
this->light->SetDirection(ignition::math::Vector3d(-0.4, 0.4, -0.4));
|
||
|
this->camera->SetWorldPose(pose);
|
||
|
this->camera->Update();
|
||
|
this->camera->Render(true);
|
||
|
this->camera->PostRender();
|
||
|
this->camera->SaveFrame((this->savePath / "1.png").string());
|
||
|
|
||
|
// Top view
|
||
|
pose.Pos().Set(0, 0, 2.2);
|
||
|
pose.Rot().Euler(0, IGN_DTOR(90), 0);
|
||
|
this->light->SetDirection(ignition::math::Vector3d(0, 0, -1.0));
|
||
|
this->camera->SetWorldPose(pose);
|
||
|
this->camera->Update();
|
||
|
this->camera->Render(true);
|
||
|
this->camera->PostRender();
|
||
|
this->camera->SaveFrame((this->savePath / "2.png").string());
|
||
|
|
||
|
// Front view
|
||
|
pose.Pos().Set(2.2, 0, 0);
|
||
|
pose.Rot().Euler(0, 0, IGN_DTOR(-180));
|
||
|
this->light->SetDirection(ignition::math::Vector3d(-0.6, 0.0, -0.4));
|
||
|
this->camera->SetWorldPose(pose);
|
||
|
this->camera->Update();
|
||
|
this->camera->Render(true);
|
||
|
this->camera->PostRender();
|
||
|
this->camera->SaveFrame((this->savePath / "3.png").string());
|
||
|
|
||
|
// Side view
|
||
|
pose.Pos().Set(0, 2.2, 0);
|
||
|
pose.Rot().Euler(0, 0, IGN_DTOR(-90));
|
||
|
this->light->SetDirection(ignition::math::Vector3d(0, -0.6, -0.4));
|
||
|
this->camera->SetWorldPose(pose);
|
||
|
this->camera->Update();
|
||
|
this->camera->Render(true);
|
||
|
this->camera->PostRender();
|
||
|
this->camera->SaveFrame((this->savePath / "4.png").string());
|
||
|
|
||
|
// Back view
|
||
|
pose.Pos().Set(-2.2, 0, 0);
|
||
|
pose.Rot().Euler(0, 0, 0);
|
||
|
this->light->SetDirection(ignition::math::Vector3d(0.6, 0, -0.4));
|
||
|
this->camera->SetWorldPose(pose);
|
||
|
this->camera->Update();
|
||
|
this->camera->Render(true);
|
||
|
this->camera->PostRender();
|
||
|
this->camera->SaveFrame((this->savePath / "5.png").string());
|
||
|
|
||
|
event::Events::DisconnectWorldCreated(this->worldCreatedConn);
|
||
|
this->worldCreatedConn.reset();
|
||
|
|
||
|
event::Events::DisconnectWorldUpdateBegin(this->updateConn);
|
||
|
this->updateConn.reset();
|
||
|
|
||
|
// Clean up the camera.
|
||
|
this->camera.reset();
|
||
|
this->light.reset();
|
||
|
this->scene->RemoveCamera("propshopcamera");
|
||
|
|
||
|
// Tell the server to stop.
|
||
|
msgs::ServerControl msg;
|
||
|
msg.set_stop(true);
|
||
|
this->pub->Publish(msg);
|
||
|
}
|
||
|
}
|
||
|
}
|