mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-03 01:50:24 +08:00
* Using shadows on all texts and icons to see them better when background is white. Buffering database previews to show faster the Library. Updated how RAM usage is computed and now show max memory. Added warnings when RAM usage is low. * Added measuring tool * fixed map not shown when closing visualization * Added measure text size setting, changed look and feel of point to point * Fixed measuring point not showing * Added fix for #1401 * Addressing #1407 * Export: Added colored OBJ options * fixed index_t not existing on focal * Fixed Settings not applied after restoring to all default settings witohut restarting the app (Marker detection not working issue #1455 ) * Marker detection: Fixing wrong depth used when rgb and depth image sizes cannot be divided exactly one from the the other #1455 * Added Marker Max Range option (default 1m) * Added OBJ texture policy option (keep color on textureless polygons) * Added texture/color blending option directly in the app. Added LAZ export option. * Hiding measuring button if not mesh, dont zip if exporting to laz, updating Export XXX button based on the current context, fixed always blending texture/color on not visualization mode * updated default marker max range to 2m * bump ios app version * fixing pcl 1.8.1 build * fixed android build
1222 lines
33 KiB
C++
1222 lines
33 KiB
C++
/*
|
|
* Copyright 2014 Google Inc. All Rights Reserved.
|
|
*
|
|
* 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 <tango-gl/conversions.h>
|
|
#include <tango-gl/gesture_camera.h>
|
|
#include <tango-gl/util.h>
|
|
|
|
#include <rtabmap/utilite/ULogger.h>
|
|
#include <rtabmap/utilite/UStl.h>
|
|
#include <rtabmap/utilite/UTimer.h>
|
|
#include <rtabmap/core/util3d_filtering.h>
|
|
#include <rtabmap/core/util3d_transforms.h>
|
|
#include <rtabmap/core/util3d_surface.h>
|
|
#include <pcl/common/transforms.h>
|
|
#include <pcl/common/common.h>
|
|
|
|
#include <glm/gtx/transform.hpp>
|
|
|
|
#include "scene.h"
|
|
#include "util.h"
|
|
|
|
// We want to represent the device properly with respect to the ground so we'll
|
|
// add an offset in z to our origin. We'll set this offset to 1.3 meters based
|
|
// on the average height of a human standing with a Tango device. This allows us
|
|
// to place a grid roughly on the ground for most users.
|
|
const glm::vec3 Scene::kHeightOffset = glm::vec3(0.0f, -1.3f, 0.0f);
|
|
|
|
// Color of the motion tracking trajectory.
|
|
const tango_gl::Color kTraceColor(0.66f, 0.66f, 0.66f);
|
|
|
|
// Color of the ground grid.
|
|
const tango_gl::Color kGridColor(0.85f, 0.85f, 0.85f);
|
|
|
|
// Frustum scale.
|
|
const glm::vec3 kFrustumScale = glm::vec3(0.4f, 0.3f, 0.5f);
|
|
|
|
const std::string kGraphVertexShader =
|
|
"precision mediump float;\n"
|
|
"precision mediump int;\n"
|
|
"attribute vec3 vertex;\n"
|
|
"uniform vec3 color;\n"
|
|
"uniform mat4 mvp;\n"
|
|
"varying vec3 v_color;\n"
|
|
"void main() {\n"
|
|
" gl_Position = mvp*vec4(vertex.x, vertex.y, vertex.z, 1.0);\n"
|
|
" v_color = color;\n"
|
|
"}\n";
|
|
const std::string kGraphFragmentShader =
|
|
"precision mediump float;\n"
|
|
"precision mediump int;\n"
|
|
"varying vec3 v_color;\n"
|
|
"void main() {\n"
|
|
" gl_FragColor = vec4(v_color.z, v_color.y, v_color.x, 1.0);\n"
|
|
"}\n";
|
|
|
|
|
|
|
|
Scene::Scene() :
|
|
background_renderer_(0),
|
|
gesture_camera_(0),
|
|
axis_(0),
|
|
frustum_(0),
|
|
grid_(0),
|
|
box_(0),
|
|
trace_(0),
|
|
graph_(0),
|
|
graphVisible_(true),
|
|
gridVisible_(true),
|
|
traceVisible_(true),
|
|
frustumVisible_(true),
|
|
color_camera_to_display_rotation_(rtabmap::ROTATION_0),
|
|
currentPose_(0),
|
|
graph_shader_program_(0),
|
|
blending_(true),
|
|
mapRendering_(true),
|
|
meshRendering_(true),
|
|
meshRenderingTexture_(true),
|
|
pointSize_(10.0f),
|
|
boundingBoxRendering_(false),
|
|
lighting_(false),
|
|
backfaceCulling_(true),
|
|
wireFrame_(false),
|
|
textureColorSeamsHidden_(true),
|
|
r_(0.0f),
|
|
g_(0.0f),
|
|
b_(0.0f),
|
|
fboId_(0),
|
|
rboId_(0),
|
|
screenWidth_(0),
|
|
screenHeight_(0),
|
|
doubleTapOn_(false)
|
|
{
|
|
depthTexture_ = 0;
|
|
gesture_camera_ = new tango_gl::GestureCamera();
|
|
gesture_camera_->SetCameraType(
|
|
tango_gl::GestureCamera::kThirdPersonFollow);
|
|
}
|
|
|
|
Scene::~Scene() {
|
|
DeleteResources();
|
|
delete gesture_camera_;
|
|
delete currentPose_;
|
|
}
|
|
|
|
//Should only be called in OpenGL thread!
|
|
void Scene::InitGLContent()
|
|
{
|
|
if(axis_ != 0)
|
|
{
|
|
DeleteResources();
|
|
}
|
|
|
|
UASSERT(axis_ == 0);
|
|
|
|
TextDrawable::createShaderProgram();
|
|
|
|
axis_ = new tango_gl::Axis();
|
|
frustum_ = new tango_gl::Frustum();
|
|
trace_ = new tango_gl::Trace();
|
|
grid_ = new tango_gl::Grid();
|
|
box_ = new BoundingBoxDrawable();
|
|
|
|
|
|
axis_->SetScale(glm::vec3(0.5f,0.5f,0.5f));
|
|
frustum_->SetColor(kTraceColor);
|
|
trace_->ClearVertexArray();
|
|
trace_->SetColor(kTraceColor);
|
|
grid_->SetColor(kGridColor);
|
|
grid_->SetPosition(kHeightOffset);
|
|
box_->SetShader();
|
|
box_->SetColor(1,0,0);
|
|
|
|
PointCloudDrawable::createShaderPrograms();
|
|
|
|
if(graph_shader_program_ == 0)
|
|
{
|
|
graph_shader_program_ = tango_gl::util::CreateProgram(kGraphVertexShader.c_str(), kGraphFragmentShader.c_str());
|
|
UASSERT(graph_shader_program_ != 0);
|
|
}
|
|
}
|
|
|
|
//Should only be called in OpenGL thread!
|
|
void Scene::DeleteResources() {
|
|
|
|
LOGI("Scene::DeleteResources()");
|
|
if(axis_)
|
|
{
|
|
delete axis_;
|
|
axis_ = 0;
|
|
delete frustum_;
|
|
delete trace_;
|
|
delete grid_;
|
|
delete box_;
|
|
delete background_renderer_;
|
|
background_renderer_ = 0;
|
|
}
|
|
|
|
TextDrawable::releaseShaderProgram();
|
|
PointCloudDrawable::releaseShaderPrograms();
|
|
|
|
if (graph_shader_program_) {
|
|
glDeleteShader(graph_shader_program_);
|
|
graph_shader_program_ = 0;
|
|
}
|
|
|
|
if(fboId_>0)
|
|
{
|
|
glDeleteFramebuffers(1, &fboId_);
|
|
fboId_ = 0;
|
|
glDeleteRenderbuffers(1, &rboId_);
|
|
rboId_ = 0;
|
|
glDeleteTextures(1, &depthTexture_);
|
|
depthTexture_ = 0;
|
|
}
|
|
|
|
clear();
|
|
}
|
|
|
|
//Should only be called in OpenGL thread!
|
|
void Scene::clear()
|
|
{
|
|
LOGI("Scene::clear()");
|
|
for(std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.begin(); iter!=pointClouds_.end(); ++iter)
|
|
{
|
|
delete iter->second;
|
|
}
|
|
for(std::map<int, tango_gl::Axis*>::iterator iter=markers_.begin(); iter!=markers_.end(); ++iter)
|
|
{
|
|
delete iter->second;
|
|
}
|
|
clearLines();
|
|
clearQuads();
|
|
clearTexts();
|
|
clearCircles();
|
|
if(trace_)
|
|
{
|
|
trace_->ClearVertexArray();
|
|
}
|
|
if(graph_)
|
|
{
|
|
delete graph_;
|
|
graph_ = 0;
|
|
}
|
|
pointClouds_.clear();
|
|
markers_.clear();
|
|
if(grid_)
|
|
{
|
|
grid_->SetPosition(kHeightOffset);
|
|
}
|
|
}
|
|
|
|
void Scene::clearLines()
|
|
{
|
|
for(std::map<int, tango_gl::Line*>::iterator iter=lines_.begin(); iter!=lines_.end(); ++iter)
|
|
{
|
|
delete iter->second;
|
|
}
|
|
lines_.clear();
|
|
}
|
|
void Scene::clearTexts()
|
|
{
|
|
for(std::map<int, TextDrawable*>::iterator iter=texts_.begin(); iter!=texts_.end(); ++iter)
|
|
{
|
|
delete iter->second;
|
|
}
|
|
texts_.clear();
|
|
}
|
|
void Scene::clearQuads()
|
|
{
|
|
for(std::map<int, QuadColor*>::iterator iter=quads_.begin(); iter!=quads_.end(); ++iter)
|
|
{
|
|
delete iter->second;
|
|
}
|
|
quads_.clear();
|
|
}
|
|
void Scene::clearCircles()
|
|
{
|
|
for(std::map<int, tango_gl::Circle*>::iterator iter=circles_.begin(); iter!=circles_.end(); ++iter)
|
|
{
|
|
delete iter->second;
|
|
}
|
|
circles_.clear();
|
|
}
|
|
|
|
//Should only be called in OpenGL thread!
|
|
void Scene::SetupViewPort(int w, int h) {
|
|
if (h == 0) {
|
|
LOGE("Setup graphic height not valid");
|
|
}
|
|
|
|
UASSERT(gesture_camera_ != 0);
|
|
gesture_camera_->SetWindowSize(static_cast<float>(w), static_cast<float>(h));
|
|
glViewport(0, 0, w, h);
|
|
if(screenWidth_ != w || screenHeight_ != h || fboId_ == 0)
|
|
{
|
|
UINFO("Setup viewport OpenGL: %dx%d", w, h);
|
|
|
|
if(fboId_>0)
|
|
{
|
|
glDeleteFramebuffers(1, &fboId_);
|
|
fboId_ = 0;
|
|
glDeleteRenderbuffers(1, &rboId_);
|
|
rboId_ = 0;
|
|
glDeleteTextures(1, &depthTexture_);
|
|
depthTexture_ = 0;
|
|
}
|
|
|
|
GLint originid = 0;
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originid);
|
|
|
|
// regenerate fbo texture
|
|
// create a framebuffer object, you need to delete them when program exits.
|
|
glGenFramebuffers(1, &fboId_);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fboId_);
|
|
|
|
// Create depth texture
|
|
glGenTextures(1, &depthTexture_);
|
|
glBindTexture(GL_TEXTURE_2D, depthTexture_);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glGenRenderbuffers(1, &rboId_);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, rboId_);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, w, h);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
|
|
// Set the texture to be at the color attachment point of the FBO (we pack depth 32 bits in color)
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depthTexture_, 0);
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId_);
|
|
|
|
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
UASSERT ( status == GL_FRAMEBUFFER_COMPLETE);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, originid);
|
|
}
|
|
screenWidth_ = w;
|
|
screenHeight_ = h;
|
|
}
|
|
|
|
std::vector<glm::vec4> computeFrustumPlanes(const glm::mat4 & mat, bool normalize = true)
|
|
{
|
|
// http://www.txutxi.com/?p=444
|
|
std::vector<glm::vec4> planes(6);
|
|
|
|
// Left Plane
|
|
// col4 + col1
|
|
planes[0].x = mat[0][3] + mat[0][0];
|
|
planes[0].y = mat[1][3] + mat[1][0];
|
|
planes[0].z = mat[2][3] + mat[2][0];
|
|
planes[0].w = mat[3][3] + mat[3][0];
|
|
|
|
// Right Plane
|
|
// col4 - col1
|
|
planes[1].x = mat[0][3] - mat[0][0];
|
|
planes[1].y = mat[1][3] - mat[1][0];
|
|
planes[1].z = mat[2][3] - mat[2][0];
|
|
planes[1].w = mat[3][3] - mat[3][0];
|
|
|
|
// Bottom Plane
|
|
// col4 + col2
|
|
planes[2].x = mat[0][3] + mat[0][1];
|
|
planes[2].y = mat[1][3] + mat[1][1];
|
|
planes[2].z = mat[2][3] + mat[2][1];
|
|
planes[2].w = mat[3][3] + mat[3][1];
|
|
|
|
// Top Plane
|
|
// col4 - col2
|
|
planes[3].x = mat[0][3] - mat[0][1];
|
|
planes[3].y = mat[1][3] - mat[1][1];
|
|
planes[3].z = mat[2][3] - mat[2][1];
|
|
planes[3].w = mat[3][3] - mat[3][1];
|
|
|
|
// Near Plane
|
|
// col4 + col3
|
|
planes[4].x = mat[0][3] + mat[0][2];
|
|
planes[4].y = mat[1][3] + mat[1][2];
|
|
planes[4].z = mat[2][3] + mat[2][2];
|
|
planes[4].w = mat[3][3] + mat[3][2];
|
|
|
|
// Far Plane
|
|
// col4 - col3
|
|
planes[5].x = mat[0][3] - mat[0][2];
|
|
planes[5].y = mat[1][3] - mat[1][2];
|
|
planes[5].z = mat[2][3] - mat[2][2];
|
|
planes[5].w = mat[3][3] - mat[3][2];
|
|
|
|
//if(normalize)
|
|
{
|
|
for(unsigned int i=0;i<planes.size(); ++i)
|
|
{
|
|
if(normalize)
|
|
{
|
|
float d = std::sqrt(planes[i].x * planes[i].x + planes[i].y * planes[i].y + planes[i].z * planes[i].z); // for normalizing the coordinates
|
|
planes[i].x/=d;
|
|
planes[i].y/=d;
|
|
planes[i].z/=d;
|
|
planes[i].w/=d;
|
|
}
|
|
}
|
|
}
|
|
|
|
return planes;
|
|
}
|
|
|
|
/**
|
|
* Tells whether or not b is intersecting f.
|
|
* http://www.txutxi.com/?p=584
|
|
* @param planes Viewing frustum.
|
|
* @param boxMin The axis aligned bounding box min.
|
|
* @param boxMax The axis aligned bounding box max.
|
|
* @return True if b intersects f, false otherwise.
|
|
*/
|
|
bool intersectFrustumAABB(
|
|
const std::vector<glm::vec4> &planes,
|
|
const pcl::PointXYZ &boxMin,
|
|
const pcl::PointXYZ &boxMax)
|
|
{
|
|
// Indexed for the 'index trick' later
|
|
const pcl::PointXYZ * box[] = {&boxMin, &boxMax};
|
|
|
|
// We only need to do 6 point-plane tests
|
|
for (unsigned int i = 0; i < planes.size(); ++i)
|
|
{
|
|
// This is the current plane
|
|
const glm::vec4 &p = planes[i];
|
|
|
|
// p-vertex selection (with the index trick)
|
|
// According to the plane normal we can know the
|
|
// indices of the positive vertex
|
|
const int px = p.x > 0.0f?1:0;
|
|
const int py = p.y > 0.0f?1:0;
|
|
const int pz = p.z > 0.0f?1:0;
|
|
|
|
// Dot product
|
|
// project p-vertex on plane normal
|
|
// (How far is p-vertex from the origin)
|
|
const float dp =
|
|
(p.x*box[px]->x) +
|
|
(p.y*box[py]->y) +
|
|
(p.z*box[pz]->z) + p.w;
|
|
|
|
// Doesn't intersect if it is behind the plane
|
|
if (dp < 0) {return false; }
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//Should only be called in OpenGL thread!
|
|
int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat4 arProjectionMatrix, const rtabmap::Mesh & occlusionMesh, bool mapping)
|
|
{
|
|
UASSERT(gesture_camera_ != 0);
|
|
|
|
if(currentPose_ == 0)
|
|
{
|
|
currentPose_ = new rtabmap::Transform(0,0,0,0,0,-M_PI/2.0f);
|
|
}
|
|
glm::vec3 position(currentPose_->x(), currentPose_->y(), currentPose_->z());
|
|
Eigen::Quaternionf quat = currentPose_->getQuaternionf();
|
|
glm::quat rotation(quat.w(), quat.x(), quat.y(), quat.z());
|
|
glm::mat4 rotateM;
|
|
if(!currentPose_->isNull())
|
|
{
|
|
rotateM = glm::rotate<float>(float(color_camera_to_display_rotation_)*-1.57079632679489661923132169163975144, glm::vec3(0.0f, 0.0f, 1.0f));
|
|
|
|
if (gesture_camera_->GetCameraType() == tango_gl::GestureCamera::kFirstPerson)
|
|
{
|
|
// In first person mode, we directly control camera's motion.
|
|
gesture_camera_->SetPosition(position);
|
|
gesture_camera_->SetRotation(rotation*glm::quat(rotateM));
|
|
}
|
|
else
|
|
{
|
|
// In third person or top down mode, we follow the camera movement.
|
|
gesture_camera_->SetAnchorPosition(position, rotation*glm::quat(rotateM));
|
|
}
|
|
}
|
|
|
|
glm::mat4 projectionMatrix = gesture_camera_->GetProjectionMatrix();
|
|
glm::mat4 viewMatrix = gesture_camera_->GetViewMatrix();
|
|
|
|
bool renderBackgroundCamera =
|
|
background_renderer_ &&
|
|
gesture_camera_->GetCameraType() == tango_gl::GestureCamera::kFirstPerson &&
|
|
!rtabmap::glmToTransform(arProjectionMatrix).isNull() &&
|
|
uvsTransformed;
|
|
|
|
if(renderBackgroundCamera)
|
|
{
|
|
if(projectionMatrix[0][0] > arProjectionMatrix[0][0]-0.3)
|
|
{
|
|
projectionMatrix = arProjectionMatrix;
|
|
viewMatrix = arViewMatrix;
|
|
}
|
|
else
|
|
{
|
|
renderBackgroundCamera = false;
|
|
}
|
|
}
|
|
|
|
rtabmap::Transform openglCamera = GetOpenGLCameraPose();//*rtabmap::Transform(0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f);
|
|
// transform in same coordinate as frustum filtering
|
|
openglCamera *= rtabmap::Transform(
|
|
0.0f, 0.0f, 1.0f, 0.0f,
|
|
0.0f, 1.0f, 0.0f, 0.0f,
|
|
-1.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
//Culling
|
|
std::vector<glm::vec4> planes = computeFrustumPlanes(projectionMatrix*viewMatrix, true);
|
|
std::vector<PointCloudDrawable*> cloudsToDraw(pointClouds_.size());
|
|
int oi=0;
|
|
int positiveCloudIds = 0;
|
|
for(std::map<int, PointCloudDrawable*>::const_iterator iter=pointClouds_.begin(); iter!=pointClouds_.end(); ++iter)
|
|
{
|
|
if(iter->first > 0)
|
|
{
|
|
positiveCloudIds++;
|
|
}
|
|
|
|
if(!mapRendering_ && iter->first > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(iter->second->isVisible())
|
|
{
|
|
if(intersectFrustumAABB(planes,
|
|
iter->second->aabbMinWorld(),
|
|
iter->second->aabbMaxWorld()))
|
|
{
|
|
cloudsToDraw[oi++] = iter->second;
|
|
}
|
|
}
|
|
}
|
|
cloudsToDraw.resize(oi);
|
|
|
|
// First rendering to get depth texture
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LESS);
|
|
glDepthMask(GL_TRUE);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
glDisable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
if(backfaceCulling_)
|
|
{
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
else
|
|
{
|
|
glDisable(GL_CULL_FACE);
|
|
}
|
|
|
|
bool onlineBlending =
|
|
(!meshRendering_ &&
|
|
occlusionMesh.cloud.get() &&
|
|
occlusionMesh.cloud->size()) ||
|
|
(blending_ &&
|
|
gesture_camera_->GetCameraType()!=tango_gl::GestureCamera::kTopOrtho &&
|
|
mapRendering_ && meshRendering_ &&
|
|
(positiveCloudIds > 1 || (renderBackgroundCamera && wireFrame_)));
|
|
|
|
if(onlineBlending && fboId_)
|
|
{
|
|
GLint originid = 0;
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originid);
|
|
|
|
// set the rendering destination to FBO
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fboId_);
|
|
|
|
glClearColor(0, 0, 0, 0);
|
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
|
|
// Draw scene
|
|
for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter)
|
|
{
|
|
Eigen::Vector3f cloudToCamera(
|
|
(*iter)->getPose().x() - openglCamera.x(),
|
|
(*iter)->getPose().y() - openglCamera.y(),
|
|
(*iter)->getPose().z() - openglCamera.z());
|
|
float distanceToCameraSqr = cloudToCamera[0]*cloudToCamera[0] + cloudToCamera[1]*cloudToCamera[1] + cloudToCamera[2]*cloudToCamera[2];
|
|
(*iter)->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, false, false, distanceToCameraSqr, 0, 0, 0, 0, 0, true);
|
|
}
|
|
|
|
if(!meshRendering_ && occlusionMesh.cloud.get() && occlusionMesh.cloud->size())
|
|
{
|
|
PointCloudDrawable drawable(occlusionMesh);
|
|
drawable.Render(projectionMatrix, viewMatrix, true, pointSize_, false, false, 0, 0, 0, 0, 0, 0, true);
|
|
}
|
|
|
|
// back to normal window-system-provided framebuffer
|
|
glBindFramebuffer(GL_FRAMEBUFFER, originid); // unbind
|
|
}
|
|
|
|
if(doubleTapOn_ && gesture_camera_->GetCameraType() != tango_gl::GestureCamera::kFirstPerson)
|
|
{
|
|
glClearColor(0, 0, 0, 0);
|
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
|
|
// FIXME: we could use the depthTexture if already computed!
|
|
for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter)
|
|
{
|
|
Eigen::Vector3f cloudToCamera(
|
|
(*iter)->getPose().x() - openglCamera.x(),
|
|
(*iter)->getPose().y() - openglCamera.y(),
|
|
(*iter)->getPose().z() - openglCamera.z());
|
|
float distanceToCameraSqr = cloudToCamera[0]*cloudToCamera[0] + cloudToCamera[1]*cloudToCamera[1] + cloudToCamera[2]*cloudToCamera[2];
|
|
|
|
(*iter)->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_*10.0f, false, false, distanceToCameraSqr, 0, 0, 0, 0, 0, true);
|
|
}
|
|
|
|
GLubyte zValue[4];
|
|
glReadPixels(doubleTapPos_.x*screenWidth_, screenHeight_-doubleTapPos_.y*screenHeight_, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, zValue);
|
|
float zValueF = float(zValue[0]/255.0f) + float(zValue[1]/255.0f)/255.0f + float(zValue[2]/255.0f)/65025.0f + float(zValue[3]/255.0f)/160581375.0f;
|
|
|
|
if(zValueF != 0.0f)
|
|
{
|
|
zValueF = zValueF*2.0-1.0;//NDC
|
|
glm::vec4 point = glm::inverse(projectionMatrix*viewMatrix)*glm::vec4(doubleTapPos_.x*2.0f-1.0f, (1.0f-doubleTapPos_.y)*2.0f-1.0f, zValueF, 1.0f);
|
|
point /= point.w;
|
|
gesture_camera_->SetAnchorOffset(glm::vec3(point.x, point.y, point.z) - position);
|
|
}
|
|
}
|
|
doubleTapOn_ = false;
|
|
|
|
glClearColor(r_, g_, b_, 1.0f);
|
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
|
|
if(renderBackgroundCamera && (!onlineBlending || !meshRendering_))
|
|
{
|
|
background_renderer_->Draw(uvsTransformed, 0, screenWidth_, screenHeight_, false);
|
|
|
|
//To debug occlusion image:
|
|
//PointCloudDrawable drawable(occlusionMesh);
|
|
//drawable.Render(projectionMatrix, viewMatrix, true, pointSize_, false, false, 999.0f);
|
|
}
|
|
|
|
if(!currentPose_->isNull())
|
|
{
|
|
if (frustumVisible_ && gesture_camera_->GetCameraType() != tango_gl::GestureCamera::kFirstPerson)
|
|
{
|
|
frustum_->SetPosition(position);
|
|
frustum_->SetRotation(rotation);
|
|
// Set the frustum scale to 4:3, this doesn't necessarily match the physical
|
|
// camera's aspect ratio, this is just for visualization purposes.
|
|
frustum_->SetScale(kFrustumScale);
|
|
frustum_->Render(projectionMatrix, viewMatrix);
|
|
|
|
rtabmap::Transform cameraFrame = *currentPose_*rtabmap::optical_T_opengl*rtabmap::CameraMobile::opticalRotationInv;
|
|
glm::vec3 positionCamera(cameraFrame.x(), cameraFrame.y(), cameraFrame.z());
|
|
Eigen::Quaternionf quatCamera = cameraFrame.getQuaternionf();
|
|
glm::quat rotationCamera(quatCamera.w(), quatCamera.x(), quatCamera.y(), quatCamera.z());
|
|
|
|
axis_->SetPosition(positionCamera);
|
|
axis_->SetRotation(rotationCamera);
|
|
axis_->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
|
|
trace_->UpdateVertexArray(position);
|
|
if(traceVisible_)
|
|
{
|
|
trace_->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
else
|
|
{
|
|
trace_->ClearVertexArray();
|
|
}
|
|
}
|
|
|
|
if(gridVisible_ && !renderBackgroundCamera)
|
|
{
|
|
grid_->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
|
|
if(graphVisible_ && graph_)
|
|
{
|
|
graph_->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
|
|
|
|
if(onlineBlending)
|
|
{
|
|
glEnable (GL_BLEND);
|
|
glDepthMask(GL_FALSE);
|
|
}
|
|
|
|
for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter)
|
|
{
|
|
PointCloudDrawable * cloud = *iter;
|
|
|
|
if(boundingBoxRendering_)
|
|
{
|
|
box_->updateVertices(cloud->aabbMinWorld(), cloud->aabbMaxWorld());
|
|
box_->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
|
|
Eigen::Vector3f cloudToCamera(
|
|
cloud->getPose().x() - openglCamera.x(),
|
|
cloud->getPose().y() - openglCamera.y(),
|
|
cloud->getPose().z() - openglCamera.z());
|
|
float distanceToCameraSqr = cloudToCamera[0]*cloudToCamera[0] + cloudToCamera[1]*cloudToCamera[1] + cloudToCamera[2]*cloudToCamera[2];
|
|
|
|
cloud->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, meshRenderingTexture_, lighting_, distanceToCameraSqr, onlineBlending?depthTexture_:0, screenWidth_, screenHeight_, gesture_camera_->getNearClipPlane(), gesture_camera_->getFarClipPlane(), false, wireFrame_, textureColorSeamsHidden_);
|
|
}
|
|
|
|
if(quads_.find(55556)!=quads_.end())
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glDisable(GL_CULL_FACE);
|
|
const QuadColor * quad = quads_.at(55556);
|
|
quad->Render(projectionMatrix, viewMatrix);
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
if(onlineBlending)
|
|
{
|
|
if(renderBackgroundCamera && meshRendering_)
|
|
{
|
|
background_renderer_->Draw(uvsTransformed, depthTexture_, screenWidth_, screenHeight_, mapping);
|
|
}
|
|
|
|
glDisable (GL_BLEND);
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
|
|
///////
|
|
glDisable (GL_DEPTH_TEST);
|
|
if(lines_.size())
|
|
{
|
|
for(std::map<int, tango_gl::Line*>::const_iterator iter=lines_.begin(); iter!=lines_.end(); ++iter)
|
|
{
|
|
const tango_gl::Line * line = iter->second;
|
|
line->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
}
|
|
|
|
if(quads_.size())
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glDisable(GL_CULL_FACE);
|
|
for(std::map<int, QuadColor*>::const_iterator iter=quads_.begin(); iter!=quads_.end(); ++iter)
|
|
{
|
|
if(iter->first!=55556)
|
|
{
|
|
const QuadColor * quad = iter->second;
|
|
quad->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
}
|
|
}
|
|
if(circles_.size())
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glDisable(GL_CULL_FACE);
|
|
for(std::map<int, tango_gl::Circle*>::const_iterator iter=circles_.begin(); iter!=circles_.end(); ++iter)
|
|
{
|
|
const tango_gl::Circle * circle = iter->second;
|
|
circle->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
}
|
|
if(texts_.size())
|
|
{
|
|
glDisable(GL_CULL_FACE);
|
|
glEnable(GL_BLEND);
|
|
|
|
glm::mat4 viewMatrixRotInv = viewMatrix;
|
|
viewMatrixRotInv[3][0] = 0;
|
|
viewMatrixRotInv[3][1] = 0;
|
|
viewMatrixRotInv[3][2] = 0;
|
|
viewMatrixRotInv = glm::inverse(viewMatrixRotInv);
|
|
for(std::map<int, TextDrawable*>::const_iterator iter=texts_.begin(); iter!=texts_.end(); ++iter)
|
|
{
|
|
const TextDrawable * text = iter->second;
|
|
text->Render(projectionMatrix, viewMatrix, viewMatrixRotInv);
|
|
}
|
|
}
|
|
|
|
//draw markers on foreground
|
|
for(std::map<int, tango_gl::Axis*>::const_iterator iter=markers_.begin(); iter!=markers_.end(); ++iter)
|
|
{
|
|
iter->second->Render(projectionMatrix, viewMatrix);
|
|
}
|
|
|
|
return (int)cloudsToDraw.size();
|
|
}
|
|
|
|
void Scene::SetCameraType(tango_gl::GestureCamera::CameraType camera_type) {
|
|
gesture_camera_->SetCameraType(camera_type);
|
|
}
|
|
|
|
void Scene::SetCameraPose(const rtabmap::Transform & pose)
|
|
{
|
|
UASSERT(!pose.isNull());
|
|
if(currentPose_ ==0)
|
|
{
|
|
currentPose_ = new rtabmap::Transform(0,0,0,0,0,-M_PI/2.0f);
|
|
}
|
|
*currentPose_ = pose;
|
|
}
|
|
|
|
void Scene::setFOV(float angle)
|
|
{
|
|
gesture_camera_->SetFieldOfView(angle);
|
|
}
|
|
void Scene::setOrthoCropFactor(float value)
|
|
{
|
|
gesture_camera_->SetOrthoCropFactor(value);
|
|
}
|
|
void Scene::setGridRotation(float angleDeg)
|
|
{
|
|
float angleRad = angleDeg * DEGREE_2_RADIANS;
|
|
if(grid_)
|
|
{
|
|
glm::quat rot = glm::rotate(glm::quat(1,0,0,0), angleRad, glm::vec3(0, 1, 0));
|
|
grid_->SetRotation(rot);
|
|
}
|
|
}
|
|
|
|
rtabmap::Transform Scene::GetOpenGLCameraPose(float * fov) const
|
|
{
|
|
if(fov)
|
|
{
|
|
*fov = gesture_camera_->getFOV();
|
|
}
|
|
return rtabmap::glmToTransform(gesture_camera_->GetTransformationMatrix());
|
|
}
|
|
|
|
void Scene::OnTouchEvent(int touch_count,
|
|
tango_gl::GestureCamera::TouchEvent event, float x0,
|
|
float y0, float x1, float y1) {
|
|
UASSERT(gesture_camera_ != 0);
|
|
if(touch_count == 3)
|
|
{
|
|
//doubletap
|
|
if(!doubleTapOn_)
|
|
{
|
|
doubleTapPos_.x = x0;
|
|
doubleTapPos_.y = y0;
|
|
doubleTapOn_ = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// rotate/translate/zoom
|
|
gesture_camera_->OnTouchEvent(touch_count, event, x0, y0, x1, y1);
|
|
}
|
|
}
|
|
|
|
void Scene::updateGraph(
|
|
const std::map<int, rtabmap::Transform> & poses,
|
|
const std::multimap<int, rtabmap::Link> & links)
|
|
{
|
|
LOGI("updateGraph");
|
|
//create
|
|
UASSERT(graph_shader_program_ != 0);
|
|
delete graph_;
|
|
graph_ = new GraphDrawable(graph_shader_program_, poses, links);
|
|
}
|
|
|
|
void Scene::setGraphVisible(bool visible)
|
|
{
|
|
graphVisible_ = visible;
|
|
}
|
|
|
|
void Scene::setGridVisible(bool visible)
|
|
{
|
|
gridVisible_ = visible;
|
|
}
|
|
|
|
void Scene::setTraceVisible(bool visible)
|
|
{
|
|
traceVisible_ = visible;
|
|
}
|
|
|
|
void Scene::setFrustumVisible(bool visible)
|
|
{
|
|
frustumVisible_ = visible;
|
|
}
|
|
|
|
//Should only be called in OpenGL thread!
|
|
void Scene::addMarker(
|
|
int id,
|
|
const rtabmap::Transform & pose)
|
|
{
|
|
LOGI("add marker %d", id);
|
|
std::map<int, tango_gl::Axis*>::iterator iter=markers_.find(id);
|
|
if(iter == markers_.end())
|
|
{
|
|
//create
|
|
tango_gl::Axis * drawable = new tango_gl::Axis();
|
|
drawable->SetScale(glm::vec3(0.05f,0.05f,0.05f));
|
|
drawable->SetLineWidth(5);
|
|
markers_.insert(std::make_pair(id, drawable));
|
|
}
|
|
setMarkerPose(id, pose);
|
|
}
|
|
void Scene::setMarkerPose(int id, const rtabmap::Transform & pose)
|
|
{
|
|
UASSERT(!pose.isNull());
|
|
std::map<int, tango_gl::Axis*>::iterator iter=markers_.find(id);
|
|
if(iter != markers_.end())
|
|
{
|
|
glm::vec3 position(pose.x(), pose.y(), pose.z());
|
|
Eigen::Quaternionf quat = pose.getQuaternionf();
|
|
glm::quat rotation(quat.w(), quat.x(), quat.y(), quat.z());
|
|
iter->second->SetPosition(position);
|
|
iter->second->SetRotation(rotation);
|
|
}
|
|
}
|
|
bool Scene::hasMarker(int id) const
|
|
{
|
|
return markers_.find(id) != markers_.end();
|
|
}
|
|
void Scene::removeMarker(int id)
|
|
{
|
|
std::map<int, tango_gl::Axis*>::iterator iter=markers_.find(id);
|
|
if(iter != markers_.end())
|
|
{
|
|
delete iter->second;
|
|
markers_.erase(iter);
|
|
}
|
|
}
|
|
std::set<int> Scene::getAddedMarkers() const
|
|
{
|
|
return uKeysSet(markers_);
|
|
}
|
|
|
|
void Scene::addCloud(
|
|
int id,
|
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
|
const pcl::IndicesPtr & indices,
|
|
const rtabmap::Transform & pose)
|
|
{
|
|
LOGI("add cloud %d (%d points %d indices)", id, (int)cloud->size(), indices.get()?(int)indices->size():0);
|
|
removeCloudOrMesh(id);
|
|
|
|
//create
|
|
PointCloudDrawable * drawable = new PointCloudDrawable(cloud, indices);
|
|
drawable->setPose(pose);
|
|
pointClouds_.insert(std::make_pair(id, drawable));
|
|
}
|
|
|
|
void Scene::removeCloudOrMesh(int id)
|
|
{
|
|
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
|
|
if(iter != pointClouds_.end())
|
|
{
|
|
delete iter->second;
|
|
pointClouds_.erase(iter);
|
|
}
|
|
}
|
|
|
|
void Scene::addMesh(
|
|
int id,
|
|
const rtabmap::Mesh & mesh,
|
|
const rtabmap::Transform & pose,
|
|
bool createWireframe)
|
|
{
|
|
LOGI("add mesh %d", id);
|
|
removeCloudOrMesh(id);
|
|
|
|
//create
|
|
PointCloudDrawable * drawable = new PointCloudDrawable(mesh, createWireframe);
|
|
drawable->setPose(pose);
|
|
pointClouds_.insert(std::make_pair(id, drawable));
|
|
|
|
if(!mesh.pose.isNull() && mesh.cloud->size() && (!mesh.cloud->isOrganized() || mesh.indices->size()))
|
|
{
|
|
UTimer time;
|
|
float height = 0.0f;
|
|
Eigen::Affine3f affinePose = mesh.pose.toEigen3f();
|
|
if(mesh.polygons.size())
|
|
{
|
|
for(unsigned int i=0; i<mesh.polygons.size(); ++i)
|
|
{
|
|
for(unsigned int j=0; j<mesh.polygons[i].vertices.size(); ++j)
|
|
{
|
|
pcl::PointXYZRGB pt = pcl::transformPoint(mesh.cloud->at(mesh.polygons[i].vertices[j]), affinePose);
|
|
if(pt.z < height)
|
|
{
|
|
height = pt.z;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(mesh.cloud->isOrganized())
|
|
{
|
|
for(unsigned int i=0; i<mesh.indices->size(); ++i)
|
|
{
|
|
pcl::PointXYZRGB pt = pcl::transformPoint(mesh.cloud->at(mesh.indices->at(i)), affinePose);
|
|
if(pt.z < height)
|
|
{
|
|
height = pt.z;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(unsigned int i=0; i<mesh.cloud->size(); ++i)
|
|
{
|
|
pcl::PointXYZRGB pt = pcl::transformPoint(mesh.cloud->at(i), affinePose);
|
|
if(pt.z < height)
|
|
{
|
|
height = pt.z;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(grid_->GetPosition().y == kHeightOffset.y || grid_->GetPosition().y > height)
|
|
{
|
|
grid_->SetPosition(glm::vec3(0,height,0));
|
|
}
|
|
LOGD("compute min height %f s", time.ticks());
|
|
}
|
|
}
|
|
|
|
void Scene::addLine(
|
|
int id,
|
|
const cv::Point3f & pt1,
|
|
const cv::Point3f & pt2,
|
|
const tango_gl::Color & color)
|
|
{
|
|
LOGI("add line %d", id);
|
|
removeLine(id);
|
|
|
|
//create
|
|
tango_gl::Line * line = new tango_gl::Line(2.0f, GL_LINES);
|
|
line->SetShader();
|
|
std::vector<glm::vec3> vertices(2);
|
|
vertices[0].x = pt1.x;
|
|
vertices[0].y = pt1.y;
|
|
vertices[0].z = pt1.z;
|
|
vertices[1].x = pt2.x;
|
|
vertices[1].y = pt2.y;
|
|
vertices[1].z = pt2.z;
|
|
line->UpdateLineVertices(vertices);
|
|
line->SetColor(color);
|
|
lines_.insert(std::make_pair(id, line));
|
|
}
|
|
|
|
void Scene::removeLine(int id)
|
|
{
|
|
std::map<int, tango_gl::Line*>::iterator iter=lines_.find(id);
|
|
if(iter != lines_.end())
|
|
{
|
|
delete iter->second;
|
|
lines_.erase(iter);
|
|
}
|
|
}
|
|
|
|
void Scene::addText(
|
|
int id,
|
|
const std::string & text,
|
|
const rtabmap::Transform & pose,
|
|
float size,
|
|
const tango_gl::Color & color)
|
|
{
|
|
LOGI("add text %d", id);
|
|
removeText(id);
|
|
|
|
//create
|
|
TextDrawable * textD = new TextDrawable(text, pose, size, color);
|
|
texts_.insert(std::make_pair(id, textD));
|
|
}
|
|
void Scene::removeText(int id)
|
|
{
|
|
std::map<int, TextDrawable*>::iterator iter=texts_.find(id);
|
|
if(iter != texts_.end())
|
|
{
|
|
delete iter->second;
|
|
texts_.erase(iter);
|
|
}
|
|
}
|
|
|
|
void Scene::addQuad(
|
|
int id,
|
|
float size,
|
|
const rtabmap::Transform & pose,
|
|
const tango_gl::Color & color,
|
|
float alpha)
|
|
{
|
|
//LOGI("add quad %d", id);
|
|
std::map<int, QuadColor*>::iterator iter=quads_.find(id);
|
|
if(iter != quads_.end())
|
|
{
|
|
delete iter->second;
|
|
quads_.erase(iter);
|
|
}
|
|
|
|
//create
|
|
QuadColor * quad = new QuadColor(size);
|
|
quad->SetTransformationMatrix(glmFromTransform(pose));
|
|
quad->SetColor(color);
|
|
quad->SetAlpha(alpha);
|
|
quads_.insert(std::make_pair(id, quad));
|
|
}
|
|
|
|
void Scene::addQuad(
|
|
int id,
|
|
float widthLeft,
|
|
float widthRight,
|
|
float heightBottom,
|
|
float heightTop,
|
|
const rtabmap::Transform & pose,
|
|
const tango_gl::Color & color,
|
|
float alpha)
|
|
{
|
|
//LOGI("add quad %d", id);
|
|
removeQuad(id);
|
|
|
|
//create
|
|
QuadColor * quad = new QuadColor(widthLeft, widthRight, heightBottom, heightTop);
|
|
quad->SetTransformationMatrix(glmFromTransform(pose));
|
|
quad->SetColor(color);
|
|
quad->SetAlpha(alpha);
|
|
quads_.insert(std::make_pair(id, quad));
|
|
}
|
|
|
|
void Scene::removeQuad(int id)
|
|
{
|
|
std::map<int, QuadColor*>::iterator iter=quads_.find(id);
|
|
if(iter != quads_.end())
|
|
{
|
|
delete iter->second;
|
|
quads_.erase(iter);
|
|
}
|
|
}
|
|
|
|
bool Scene::hasQuad(int id) const
|
|
{
|
|
return quads_.find(id) != quads_.end();
|
|
}
|
|
|
|
void Scene::addCircle(
|
|
int id,
|
|
float radius,
|
|
const rtabmap::Transform & pose,
|
|
const tango_gl::Color & color,
|
|
float alpha)
|
|
{
|
|
//LOGI("add quad %d", id);
|
|
std::map<int, tango_gl::Circle*>::iterator iter=circles_.find(id);
|
|
if(iter != circles_.end())
|
|
{
|
|
delete iter->second;
|
|
circles_.erase(iter);
|
|
}
|
|
|
|
//create
|
|
tango_gl::Circle * circle = new tango_gl::Circle(radius, 12);
|
|
circle->SetTransformationMatrix(glmFromTransform(pose));
|
|
circle->SetColor(color);
|
|
circle->SetAlpha(alpha);
|
|
circles_.insert(std::make_pair(id, circle));
|
|
}
|
|
|
|
void Scene::removeCircle(int id)
|
|
{
|
|
std::map<int, tango_gl::Circle*>::iterator iter=circles_.find(id);
|
|
if(iter != circles_.end())
|
|
{
|
|
delete iter->second;
|
|
circles_.erase(iter);
|
|
}
|
|
}
|
|
|
|
bool Scene::hasCircle(int id) const
|
|
{
|
|
return circles_.find(id) != circles_.end();
|
|
}
|
|
|
|
void Scene::setCloudPose(int id, const rtabmap::Transform & pose)
|
|
{
|
|
UASSERT(!pose.isNull());
|
|
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
|
|
if(iter != pointClouds_.end())
|
|
{
|
|
iter->second->setPose(pose);
|
|
}
|
|
}
|
|
|
|
void Scene::setCloudVisible(int id, bool visible)
|
|
{
|
|
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
|
|
if(iter != pointClouds_.end())
|
|
{
|
|
iter->second->setVisible(visible);
|
|
}
|
|
}
|
|
|
|
bool Scene::hasCloud(int id) const
|
|
{
|
|
return pointClouds_.find(id) != pointClouds_.end();
|
|
}
|
|
|
|
bool Scene::hasMesh(int id) const
|
|
{
|
|
return pointClouds_.find(id) != pointClouds_.end() && pointClouds_.at(id)->hasMesh();
|
|
}
|
|
|
|
bool Scene::hasTexture(int id) const
|
|
{
|
|
return pointClouds_.find(id) != pointClouds_.end() && pointClouds_.at(id)->hasTexture();
|
|
}
|
|
|
|
std::set<int> Scene::getAddedClouds() const
|
|
{
|
|
return uKeysSet(pointClouds_);
|
|
}
|
|
|
|
void Scene::updateCloudPolygons(int id, const std::vector<pcl::Vertices> & polygons)
|
|
{
|
|
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
|
|
if(iter != pointClouds_.end())
|
|
{
|
|
iter->second->updatePolygons(polygons);
|
|
}
|
|
}
|
|
|
|
void Scene::updateMesh(int id, const rtabmap::Mesh & mesh)
|
|
{
|
|
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
|
|
if(iter != pointClouds_.end())
|
|
{
|
|
iter->second->updateMesh(mesh);
|
|
}
|
|
}
|
|
|
|
void Scene::updateGains(int id, float gainR, float gainG, float gainB)
|
|
{
|
|
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
|
|
if(iter != pointClouds_.end())
|
|
{
|
|
iter->second->setGains(gainR, gainG, gainB);
|
|
}
|
|
}
|
|
|
|
void Scene::setGridColor(float r, float g, float b)
|
|
{
|
|
if(grid_)
|
|
{
|
|
grid_->SetColor(r, g, b);
|
|
}
|
|
}
|