00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <sstream>
00029
00030 #include "point_cloud_drawable.h"
00031 #include "rtabmap/utilite/ULogger.h"
00032 #include "rtabmap/utilite/UTimer.h"
00033 #include "rtabmap/utilite/UConversion.h"
00034 #include <opencv2/imgproc/imgproc.hpp>
00035 #include "util.h"
00036 #include "pcl/common/transforms.h"
00037
00038 #include <GLES2/gl2.h>
00039
00040 #define LOW_DEC 2
00041 #define LOWLOW_DEC 4
00042
00043 enum PointCloudShaders
00044 {
00045 kPointCloud = 0,
00046 kPointCloudBlending = 1,
00047 kPointCloudLighting = 2,
00048 kPointCloudLightingBlending = 3,
00049
00050 kTexture = 4,
00051 kTextureBlending = 5,
00052 kTextureLighting = 6,
00053 kTextureLightingBlending = 7,
00054
00055 kDepthPacking = 8
00056 };
00057
00058
00059 const std::string kPointCloudVertexShader =
00060 "precision mediump float;\n"
00061 "precision mediump int;\n"
00062 "attribute vec3 aVertex;\n"
00063 "attribute vec3 aColor;\n"
00064
00065 "uniform mat4 uMVP;\n"
00066 "uniform float uPointSize;\n"
00067
00068 "varying vec3 vColor;\n"
00069 "varying float vLightWeighting;\n"
00070
00071 "void main() {\n"
00072 " gl_Position = uMVP*vec4(aVertex.x, aVertex.y, aVertex.z, 1.0);\n"
00073 " gl_PointSize = uPointSize;\n"
00074 " vLightWeighting = 1.0;\n"
00075 " vColor = aColor;\n"
00076 "}\n";
00077 const std::string kPointCloudLightingVertexShader =
00078 "precision mediump float;\n"
00079 "precision mediump int;\n"
00080 "attribute vec3 aVertex;\n"
00081 "attribute vec3 aNormal;\n"
00082 "attribute vec3 aColor;\n"
00083
00084 "uniform mat4 uMVP;\n"
00085 "uniform mat3 uN;\n"
00086 "uniform vec3 uLightingDirection;\n"
00087 "uniform float uPointSize;\n"
00088
00089 "varying vec3 vColor;\n"
00090 "varying float vLightWeighting;\n"
00091
00092 "void main() {\n"
00093 " gl_Position = uMVP*vec4(aVertex.x, aVertex.y, aVertex.z, 1.0);\n"
00094 " gl_PointSize = uPointSize;\n"
00095 " vec3 transformedNormal = uN * aNormal;\n"
00096 " vLightWeighting = max(dot(transformedNormal, uLightingDirection)*0.5+0.5, 0.0);\n"
00097 " if(vLightWeighting<0.5)"
00098 " vLightWeighting=0.5;\n"
00099 " vColor = aColor;\n"
00100 "}\n";
00101
00102 const std::string kPointCloudFragmentShader =
00103 "precision mediump float;\n"
00104 "precision mediump int;\n"
00105 "uniform float uGainR;\n"
00106 "uniform float uGainG;\n"
00107 "uniform float uGainB;\n"
00108 "varying vec3 vColor;\n"
00109 "varying float vLightWeighting;\n"
00110 "void main() {\n"
00111 " vec4 textureColor = vec4(vColor.z, vColor.y, vColor.x, 1.0);\n"
00112 " gl_FragColor = vec4(textureColor.r * uGainR * vLightWeighting, textureColor.g * uGainG * vLightWeighting, textureColor.b * uGainB * vLightWeighting, textureColor.a);\n"
00113 "}\n";
00114 const std::string kPointCloudBlendingFragmentShader =
00115 "precision highp float;\n"
00116 "precision mediump int;\n"
00117 "uniform float uGainR;\n"
00118 "uniform float uGainG;\n"
00119 "uniform float uGainB;\n"
00120 "uniform float uNearZ;\n"
00121 "uniform float uFarZ;\n"
00122 "uniform sampler2D uDepthTexture;\n"
00123 "uniform vec2 uScreenScale;\n"
00124 "varying vec3 vColor;\n"
00125 "varying float vLightWeighting;\n"
00126 "void main() {\n"
00127 " vec4 textureColor = vec4(vColor.z, vColor.y, vColor.x, 1.0);\n"
00128 " float alpha = 1.0;\n"
00129 " vec2 coord = uScreenScale * gl_FragCoord.xy;\n;"
00130 " float depth = texture2D(uDepthTexture, coord).r;\n"
00131 " float num = (2.0 * uNearZ * uFarZ);\n"
00132 " float diff = (uFarZ - uNearZ);\n"
00133 " float add = (uFarZ + uNearZ);\n"
00134 " float ndcDepth = depth * 2.0 - 1.0;\n"
00135 " float linearDepth = num / (add - ndcDepth * diff);\n"
00136 " float ndcFragz = gl_FragCoord.z * 2.0 - 1.0;\n"
00137 " float linearFragz = num / (add - ndcFragz * diff);\n"
00138 " if(linearFragz > linearDepth + 0.05)\n"
00139 " alpha=0.0;\n"
00140 " gl_FragColor = vec4(textureColor.r * uGainR * vLightWeighting, textureColor.g * uGainG * vLightWeighting, textureColor.b * uGainB * vLightWeighting, alpha);\n"
00141 "}\n";
00142
00143 const std::string kPointCloudDepthPackingVertexShader =
00144 "precision mediump float;\n"
00145 "precision mediump int;\n"
00146 "attribute vec3 aVertex;\n"
00147 "uniform mat4 uMVP;\n"
00148 "uniform float uPointSize;\n"
00149 "void main() {\n"
00150 " gl_Position = uMVP*vec4(aVertex.x, aVertex.y, aVertex.z, 1.0);\n"
00151 " gl_PointSize = uPointSize;\n"
00152 "}\n";
00153 const std::string kPointCloudDepthPackingFragmentShader =
00154 "precision highp float;\n"
00155 "precision mediump int;\n"
00156 "void main() {\n"
00157 " float toFixed = 255.0/256.0;\n"
00158 " vec4 enc = vec4(1.0, 255.0, 65025.0, 160581375.0) * toFixed * gl_FragCoord.z;\n"
00159 " enc = fract(enc);\n"
00160 " gl_FragColor = enc;\n"
00161 "}\n";
00162
00163
00164 const std::string kTextureMeshVertexShader =
00165 "precision mediump float;\n"
00166 "precision mediump int;\n"
00167 "attribute vec3 aVertex;\n"
00168 "attribute vec2 aTexCoord;\n"
00169
00170 "uniform mat4 uMVP;\n"
00171
00172 "varying vec2 vTexCoord;\n"
00173 "varying float vLightWeighting;\n"
00174
00175 "void main() {\n"
00176 " gl_Position = uMVP*vec4(aVertex.x, aVertex.y, aVertex.z, 1.0);\n"
00177
00178 " if(aTexCoord.x < 0.0) {\n"
00179 " vTexCoord.x = 1.0;\n"
00180 " vTexCoord.y = 1.0;\n"
00181 " } else {\n"
00182 " vTexCoord = aTexCoord;\n"
00183 " }\n"
00184
00185 " vLightWeighting = 1.0;\n"
00186 "}\n";
00187 const std::string kTextureMeshLightingVertexShader =
00188 "precision mediump float;\n"
00189 "precision mediump int;\n"
00190 "attribute vec3 aVertex;\n"
00191 "attribute vec3 aNormal;\n"
00192 "attribute vec2 aTexCoord;\n"
00193
00194 "uniform mat4 uMVP;\n"
00195 "uniform mat3 uN;\n"
00196 "uniform vec3 uLightingDirection;\n"
00197
00198 "varying vec2 vTexCoord;\n"
00199 "varying float vLightWeighting;\n"
00200
00201 "void main() {\n"
00202 " gl_Position = uMVP*vec4(aVertex.x, aVertex.y, aVertex.z, 1.0);\n"
00203
00204 " if(aTexCoord.x < 0.0) {\n"
00205 " vTexCoord.x = 1.0;\n"
00206 " vTexCoord.y = 1.0;\n"
00207 " } else {\n"
00208 " vTexCoord = aTexCoord;\n"
00209 " }\n"
00210
00211 " vec3 transformedNormal = uN * aNormal;\n"
00212 " vLightWeighting = max(dot(transformedNormal, uLightingDirection)*0.5+0.5, 0.0);\n"
00213 " if(vLightWeighting<0.5) \n"
00214 " vLightWeighting=0.5;\n"
00215 "}\n";
00216 const std::string kTextureMeshFragmentShader =
00217 "precision mediump float;\n"
00218 "precision mediump int;\n"
00219 "uniform sampler2D uTexture;\n"
00220 "uniform float uGainR;\n"
00221 "uniform float uGainG;\n"
00222 "uniform float uGainB;\n"
00223 "varying vec2 vTexCoord;\n"
00224 "varying float vLightWeighting;\n"
00225 ""
00226 "void main() {\n"
00227 " vec4 textureColor = texture2D(uTexture, vTexCoord);\n"
00228 " gl_FragColor = vec4(textureColor.r * uGainR * vLightWeighting, textureColor.g * uGainG * vLightWeighting, textureColor.b * uGainB * vLightWeighting, textureColor.a);\n"
00229 "}\n";
00230 const std::string kTextureMeshBlendingFragmentShader =
00231 "precision highp float;\n"
00232 "precision mediump int;\n"
00233 "uniform sampler2D uTexture;\n"
00234 "uniform sampler2D uDepthTexture;\n"
00235 "uniform float uGainR;\n"
00236 "uniform float uGainG;\n"
00237 "uniform float uGainB;\n"
00238 "uniform vec2 uScreenScale;\n"
00239 "uniform float uNearZ;\n"
00240 "uniform float uFarZ;\n"
00241 "varying vec2 vTexCoord;\n"
00242 "varying float vLightWeighting;\n"
00243 ""
00244 "void main() {\n"
00245 " vec4 textureColor = texture2D(uTexture, vTexCoord);\n"
00246 " float alpha = 1.0;\n"
00247 " vec2 coord = uScreenScale * gl_FragCoord.xy;\n;"
00248 " float depth = texture2D(uDepthTexture, coord).r;\n"
00249 " float num = (2.0 * uNearZ * uFarZ);\n"
00250 " float diff = (uFarZ - uNearZ);\n"
00251 " float add = (uFarZ + uNearZ);\n"
00252 " float ndcDepth = depth * 2.0 - 1.0;\n"
00253 " float linearDepth = num / (add - ndcDepth * diff);\n"
00254 " float ndcFragz = gl_FragCoord.z * 2.0 - 1.0;\n"
00255 " float linearFragz = num / (add - ndcFragz * diff);\n"
00256 " if(linearFragz > linearDepth + 0.05)\n"
00257 " alpha=0.0;\n"
00258 " gl_FragColor = vec4(textureColor.r * uGainR * vLightWeighting, textureColor.g * uGainG * vLightWeighting, textureColor.b * uGainB * vLightWeighting, alpha);\n"
00259 "}\n";
00260
00261 std::vector<GLuint> PointCloudDrawable::shaderPrograms_;
00262
00263 void PointCloudDrawable::createShaderPrograms()
00264 {
00265 if(shaderPrograms_.empty())
00266 {
00267 shaderPrograms_.resize(9);
00268
00269 shaderPrograms_[kPointCloud] = tango_gl::util::CreateProgram(kPointCloudVertexShader.c_str(), kPointCloudFragmentShader.c_str());
00270 UASSERT(shaderPrograms_[kPointCloud] != 0);
00271 shaderPrograms_[kPointCloudBlending] = tango_gl::util::CreateProgram(kPointCloudVertexShader.c_str(), kPointCloudBlendingFragmentShader.c_str());
00272 UASSERT(shaderPrograms_[kPointCloudBlending] != 0);
00273 shaderPrograms_[kPointCloudLighting] = tango_gl::util::CreateProgram(kPointCloudLightingVertexShader.c_str(), kPointCloudFragmentShader.c_str());
00274 UASSERT(shaderPrograms_[kPointCloudLighting] != 0);
00275 shaderPrograms_[kPointCloudLightingBlending] = tango_gl::util::CreateProgram(kPointCloudLightingVertexShader.c_str(), kPointCloudBlendingFragmentShader.c_str());
00276 UASSERT(shaderPrograms_[kPointCloudLightingBlending] != 0);
00277
00278 shaderPrograms_[kTexture] = tango_gl::util::CreateProgram(kTextureMeshVertexShader.c_str(), kTextureMeshFragmentShader.c_str());
00279 UASSERT(shaderPrograms_[kTexture] != 0);
00280 shaderPrograms_[kTextureBlending] = tango_gl::util::CreateProgram(kTextureMeshVertexShader.c_str(), kTextureMeshBlendingFragmentShader.c_str());
00281 UASSERT(shaderPrograms_[kTextureBlending] != 0);
00282 shaderPrograms_[kTextureLighting] = tango_gl::util::CreateProgram(kTextureMeshLightingVertexShader.c_str(), kTextureMeshFragmentShader.c_str());
00283 UASSERT(shaderPrograms_[kTextureLighting] != 0);
00284 shaderPrograms_[kTextureLightingBlending] = tango_gl::util::CreateProgram(kTextureMeshLightingVertexShader.c_str(), kTextureMeshBlendingFragmentShader.c_str());
00285 UASSERT(shaderPrograms_[kTextureLightingBlending] != 0);
00286
00287 shaderPrograms_[kDepthPacking] = tango_gl::util::CreateProgram(kPointCloudDepthPackingVertexShader.c_str(), kPointCloudDepthPackingFragmentShader.c_str());
00288 UASSERT(shaderPrograms_[kDepthPacking] != 0);
00289 }
00290 }
00291 void PointCloudDrawable::releaseShaderPrograms()
00292 {
00293 for(unsigned int i=0; i<shaderPrograms_.size(); ++i)
00294 {
00295 glDeleteShader(shaderPrograms_[i]);
00296 }
00297 shaderPrograms_.clear();
00298 }
00299
00300 PointCloudDrawable::PointCloudDrawable(
00301 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
00302 const pcl::IndicesPtr & indices,
00303 float gainR,
00304 float gainG,
00305 float gainB) :
00306 vertex_buffers_(0),
00307 textures_(0),
00308 nPoints_(0),
00309 pose_(rtabmap::Transform::getIdentity()),
00310 poseGl_(1.0f),
00311 visible_(true),
00312 hasNormals_(false),
00313 gainR_(gainR),
00314 gainG_(gainG),
00315 gainB_(gainB)
00316 {
00317 updateCloud(cloud, indices);
00318 }
00319
00320 PointCloudDrawable::PointCloudDrawable(
00321 const Mesh & mesh,
00322 bool createWireframe) :
00323 vertex_buffers_(0),
00324 textures_(0),
00325 nPoints_(0),
00326 pose_(rtabmap::Transform::getIdentity()),
00327 poseGl_(1.0f),
00328 visible_(true),
00329 hasNormals_(false),
00330 gainR_(1.0f),
00331 gainG_(1.0f),
00332 gainB_(1.0f)
00333 {
00334 updateMesh(mesh, createWireframe);
00335 }
00336
00337 PointCloudDrawable::~PointCloudDrawable()
00338 {
00339 LOGI("Freeing cloud buffer %d", vertex_buffers_);
00340 if (vertex_buffers_)
00341 {
00342 glDeleteBuffers(1, &vertex_buffers_);
00343 tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
00344 vertex_buffers_ = 0;
00345 }
00346
00347 if (textures_)
00348 {
00349 glDeleteTextures(1, &textures_);
00350 tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
00351 textures_ = 0;
00352 }
00353 }
00354
00355 void PointCloudDrawable::updatePolygons(const std::vector<pcl::Vertices> & polygons, const std::vector<pcl::Vertices> & polygonsLowRes, bool createWireframe)
00356 {
00357 LOGD("Update polygons");
00358 polygons_.clear();
00359 polygonLines_.clear();
00360 polygonsLowRes_.clear();
00361 polygonLinesLowRes_.clear();
00362 if(polygons.size() && organizedToDenseIndices_.size())
00363 {
00364 unsigned int polygonSize = polygons[0].vertices.size();
00365 UASSERT(polygonSize == 3);
00366 polygons_.resize(polygons.size() * polygonSize);
00367 if(createWireframe)
00368 polygonLines_.resize(polygons_.size()*2);
00369 int oi = 0;
00370 int li = 0;
00371 for(unsigned int i=0; i<polygons.size(); ++i)
00372 {
00373 UASSERT(polygons[i].vertices.size() == polygonSize);
00374 for(unsigned int j=0; j<polygonSize; ++j)
00375 {
00376 polygons_[oi++] = organizedToDenseIndices_.at(polygons[i].vertices[j]);
00377 if(createWireframe)
00378 {
00379 polygonLines_[li++] = organizedToDenseIndices_.at(polygons[i].vertices[j]);
00380 polygonLines_[li++] = organizedToDenseIndices_.at(polygons[i].vertices[(j+1) % polygonSize]);
00381 }
00382 }
00383 }
00384
00385 if(polygonsLowRes.size())
00386 {
00387 unsigned int polygonSize = polygonsLowRes[0].vertices.size();
00388 UASSERT(polygonSize == 3);
00389 polygonsLowRes_.resize(polygonsLowRes.size() * polygonSize);
00390 if(createWireframe)
00391 polygonLinesLowRes_.resize(polygonsLowRes_.size()*2);
00392 int oi = 0;
00393 int li = 0;
00394 for(unsigned int i=0; i<polygonsLowRes.size(); ++i)
00395 {
00396 UASSERT(polygonsLowRes[i].vertices.size() == polygonSize);
00397 for(unsigned int j=0; j<polygonSize; ++j)
00398 {
00399 polygonsLowRes_[oi++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[j]);
00400 if(createWireframe)
00401 {
00402 polygonLinesLowRes_[li++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[j]);
00403 polygonLinesLowRes_[li++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[(j+1)%polygonSize]);
00404 }
00405 }
00406 }
00407 }
00408 }
00409 }
00410
00411 void PointCloudDrawable::updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::IndicesPtr & indices)
00412 {
00413 UASSERT(cloud.get() && !cloud->empty());
00414 nPoints_ = 0;
00415 polygons_.clear();
00416 polygonsLowRes_.clear();
00417 verticesLowRes_.clear();
00418 verticesLowLowRes_.clear();
00419 aabbMinModel_ = aabbMinWorld_ = pcl::PointXYZ(1000,1000,1000);
00420 aabbMaxModel_ = aabbMaxWorld_ = pcl::PointXYZ(-1000,-1000,-1000);
00421
00422 if (vertex_buffers_)
00423 {
00424 glDeleteBuffers(1, &vertex_buffers_);
00425 tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
00426 vertex_buffers_ = 0;
00427 }
00428
00429 if (textures_)
00430 {
00431 glDeleteTextures(1, &textures_);
00432 tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
00433 textures_ = 0;
00434 }
00435
00436 glGenBuffers(1, &vertex_buffers_);
00437 if(!vertex_buffers_)
00438 {
00439 LOGE("OpenGL: could not generate vertex buffers\n");
00440 return;
00441 }
00442
00443 LOGI("Creating cloud buffer %d", vertex_buffers_);
00444 std::vector<float> vertices;
00445 int totalPoints = 0;
00446 if(indices.get() && indices->size())
00447 {
00448 totalPoints = indices->size();
00449 vertices.resize(indices->size()*4);
00450 verticesLowRes_.resize(cloud->isOrganized()?totalPoints:0);
00451 verticesLowLowRes_.resize(cloud->isOrganized()?totalPoints:0);
00452 int oi_low = 0;
00453 int oi_lowlow = 0;
00454 for(unsigned int i=0; i<indices->size(); ++i)
00455 {
00456 const pcl::PointXYZRGB & pt = cloud->at(indices->at(i));
00457 vertices[i*4] = pt.x;
00458 vertices[i*4+1] = pt.y;
00459 vertices[i*4+2] = pt.z;
00460 vertices[i*4+3] = pt.rgb;
00461
00462 updateAABBMinMax(pt, aabbMinModel_, aabbMaxModel_);
00463
00464 if(cloud->isOrganized())
00465 {
00466 if(indices->at(i)%LOW_DEC == 0 && (indices->at(i)/cloud->width) % LOW_DEC == 0)
00467 {
00468 verticesLowRes_[oi_low++] = i;
00469 }
00470 if(indices->at(i)%LOWLOW_DEC == 0 && (indices->at(i)/cloud->width) % LOWLOW_DEC == 0)
00471 {
00472 verticesLowLowRes_[oi_lowlow++] = i;
00473 }
00474 }
00475 }
00476 verticesLowRes_.resize(oi_low);
00477 verticesLowLowRes_.resize(oi_lowlow);
00478 }
00479 else
00480 {
00481 totalPoints = cloud->size();
00482 vertices.resize(cloud->size()*4);
00483 verticesLowRes_.resize(cloud->isOrganized()?totalPoints:0);
00484 verticesLowLowRes_.resize(cloud->isOrganized()?totalPoints:0);
00485 int oi_low = 0;
00486 int oi_lowlow = 0;
00487 for(unsigned int i=0; i<cloud->size(); ++i)
00488 {
00489 const pcl::PointXYZRGB & pt = cloud->at(i);
00490 vertices[i*4] = pt.x;
00491 vertices[i*4+1] = pt.y;
00492 vertices[i*4+2] = pt.z;
00493 vertices[i*4+3] = pt.rgb;
00494
00495 updateAABBMinMax(pt, aabbMinModel_, aabbMaxModel_);
00496
00497 if(cloud->isOrganized())
00498 {
00499 if(i%LOW_DEC == 0 && (i/cloud->width) % LOW_DEC == 0)
00500 {
00501 verticesLowRes_[oi_low++] = i;
00502 }
00503 if(i%LOWLOW_DEC == 0 && (i/cloud->width) % LOWLOW_DEC == 0)
00504 {
00505 verticesLowLowRes_[oi_lowlow++] = i;
00506 }
00507 }
00508 }
00509 verticesLowRes_.resize(oi_low);
00510 verticesLowLowRes_.resize(oi_lowlow);
00511 }
00512
00513 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffers_);
00514 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (int)vertices.size(), (const void *)vertices.data(), GL_STATIC_DRAW);
00515 glBindBuffer(GL_ARRAY_BUFFER, 0);
00516
00517 GLint error = glGetError();
00518 if(error != GL_NO_ERROR)
00519 {
00520 LOGE("OpenGL: Could not allocate point cloud (0x%x)\n", error);
00521 vertex_buffers_ = 0;
00522 return;
00523 }
00524
00525 nPoints_ = totalPoints;
00526 }
00527
00528 void PointCloudDrawable::updateMesh(const Mesh & mesh, bool createWireframe)
00529 {
00530 UASSERT(mesh.cloud.get() && !mesh.cloud->empty());
00531 nPoints_ = 0;
00532 aabbMinModel_ = aabbMinWorld_ = pcl::PointXYZ(1000,1000,1000);
00533 aabbMaxModel_ = aabbMaxWorld_ = pcl::PointXYZ(-1000,-1000,-1000);
00534
00535 if (vertex_buffers_)
00536 {
00537 glDeleteBuffers(1, &vertex_buffers_);
00538 tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
00539 vertex_buffers_ = 0;
00540 }
00541
00542 gainR_ = mesh.gains[0];
00543 gainG_ = mesh.gains[1];
00544 gainB_ = mesh.gains[2];
00545
00546 bool textureUpdate = false;
00547 if(!mesh.texture.empty() && mesh.texture.type() == CV_8UC3)
00548 {
00549 if (textures_)
00550 {
00551 glDeleteTextures(1, &textures_);
00552 tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
00553 textures_ = 0;
00554 }
00555 textureUpdate = true;
00556 }
00557
00558 glGenBuffers(1, &vertex_buffers_);
00559 if(!vertex_buffers_)
00560 {
00561 LOGE("OpenGL: could not generate vertex buffers\n");
00562 return;
00563 }
00564
00565 if(textureUpdate)
00566 {
00567 glGenTextures(1, &textures_);
00568 if(!textures_)
00569 {
00570 vertex_buffers_ = 0;
00571 LOGE("OpenGL: could not generate texture buffers\n");
00572 return;
00573 }
00574 }
00575
00576
00577 std::vector<float> vertices;
00578 int totalPoints = 0;
00579 std::vector<pcl::Vertices> polygons = mesh.polygons;
00580 std::vector<pcl::Vertices> polygonsLowRes;
00581 hasNormals_ = mesh.normals.get() && mesh.normals->size() == mesh.cloud->size();
00582 UASSERT(!hasNormals_ || mesh.cloud->size() == mesh.normals->size());
00583 if(mesh.cloud->isOrganized())
00584 {
00585 polygonsLowRes = mesh.polygonsLowRes;
00586 organizedToDenseIndices_ = std::vector<unsigned int>(mesh.cloud->width*mesh.cloud->height, -1);
00587 totalPoints = mesh.indices->size();
00588 verticesLowRes_.resize(totalPoints);
00589 verticesLowLowRes_.resize(totalPoints);
00590 int oi_low = 0;
00591 int oi_lowlow = 0;
00592 if(textures_ && polygons.size())
00593 {
00594 int items = hasNormals_?9:6;
00595 vertices = std::vector<float>(mesh.indices->size()*items);
00596 for(unsigned int i=0; i<mesh.indices->size(); ++i)
00597 {
00598 const pcl::PointXYZRGB & pt = mesh.cloud->at(mesh.indices->at(i));
00599 vertices[i*items] = pt.x;
00600 vertices[i*items+1] = pt.y;
00601 vertices[i*items+2] = pt.z;
00602
00603
00604 vertices[i*items+3] = pt.rgb;
00605
00606 updateAABBMinMax(pt, aabbMinModel_, aabbMaxModel_);
00607
00608
00609 int index = mesh.indices->at(i);
00610 vertices[i*items+4] = float(index % mesh.cloud->width)/float(mesh.cloud->width);
00611 vertices[i*items+5] = float(index / mesh.cloud->width)/float(mesh.cloud->height);
00612
00613 if(hasNormals_)
00614 {
00615
00616 vertices[i*items+6] = mesh.normals->at(mesh.indices->at(i)).normal_x;
00617 vertices[i*items+7] = mesh.normals->at(mesh.indices->at(i)).normal_y;
00618 vertices[i*items+8] = mesh.normals->at(mesh.indices->at(i)).normal_z;
00619 }
00620
00621 organizedToDenseIndices_[mesh.indices->at(i)] = i;
00622
00623 if(mesh.indices->at(i)%LOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOW_DEC == 0)
00624 {
00625 verticesLowRes_[oi_low++] = i;
00626 }
00627 if(mesh.indices->at(i)%LOWLOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOWLOW_DEC == 0)
00628 {
00629 verticesLowLowRes_[oi_lowlow++] = i;
00630 }
00631 }
00632 }
00633 else
00634 {
00635
00636 int items = hasNormals_?7:4;
00637 vertices = std::vector<float>(mesh.indices->size()*items);
00638 for(unsigned int i=0; i<mesh.indices->size(); ++i)
00639 {
00640 const pcl::PointXYZRGB & pt = mesh.cloud->at(mesh.indices->at(i));
00641 vertices[i*items] = pt.x;
00642 vertices[i*items+1] = pt.y;
00643 vertices[i*items+2] = pt.z;
00644 vertices[i*items+3] = pt.rgb;
00645
00646 updateAABBMinMax(pt, aabbMinModel_, aabbMaxModel_);
00647
00648 if(hasNormals_)
00649 {
00650
00651 vertices[i*items+4] = mesh.normals->at(mesh.indices->at(i)).normal_x;
00652 vertices[i*items+5] = mesh.normals->at(mesh.indices->at(i)).normal_y;
00653 vertices[i*items+6] = mesh.normals->at(mesh.indices->at(i)).normal_z;
00654 }
00655
00656 organizedToDenseIndices_[mesh.indices->at(i)] = i;
00657
00658 if(mesh.indices->at(i)%LOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOW_DEC == 0)
00659 {
00660 verticesLowRes_[oi_low++] = i;
00661 }
00662 if(mesh.indices->at(i)%LOWLOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOWLOW_DEC == 0)
00663 {
00664 verticesLowLowRes_[oi_lowlow++] = i;
00665 }
00666 }
00667 }
00668 verticesLowRes_.resize(oi_low);
00669 verticesLowLowRes_.resize(oi_lowlow);
00670 }
00671 else
00672 {
00673 if(textures_ && polygons.size() && mesh.normals->size())
00674 {
00675
00676
00677
00678
00679
00680
00681
00682 totalPoints = mesh.texCoords.size();
00683 vertices = std::vector<float>(mesh.texCoords.size()*9);
00684 organizedToDenseIndices_ = std::vector<unsigned int>(totalPoints, -1);
00685
00686 UASSERT_MSG(mesh.texCoords.size() == polygons[0].vertices.size()*polygons.size(),
00687 uFormat("%d vs %d x %d", (int)mesh.texCoords.size(), (int)polygons[0].vertices.size(), (int)polygons.size()).c_str());
00688
00689 int items = hasNormals_?9:6;
00690 unsigned int oi=0;
00691 for(unsigned int i=0; i<polygons.size(); ++i)
00692 {
00693 pcl::Vertices & v = polygons[i];
00694 for(unsigned int j=0; j<v.vertices.size(); ++j)
00695 {
00696 UASSERT(oi < mesh.texCoords.size());
00697 UASSERT(v.vertices[j] < mesh.cloud->size());
00698
00699 const pcl::PointXYZRGB & pt = mesh.cloud->at(v.vertices[j]);
00700
00701 vertices[oi*items] = pt.x;
00702 vertices[oi*items+1] = pt.y;
00703 vertices[oi*items+2] = pt.z;
00704
00705
00706 vertices[oi*items+3] = pt.rgb;
00707
00708 updateAABBMinMax(pt, aabbMinModel_, aabbMaxModel_);
00709
00710
00711 if(mesh.texCoords[oi][0]>=0.0f)
00712 {
00713 vertices[oi*items+4] = mesh.texCoords[oi][0];
00714 vertices[oi*items+5] = 1.0f-mesh.texCoords[oi][1];
00715 }
00716 else
00717 {
00718 vertices[oi*items+4] = vertices[oi*items+5] = -1.0f;
00719 }
00720
00721 if(hasNormals_)
00722 {
00723
00724 vertices[oi*items+6] = mesh.normals->at(v.vertices[j]).normal_x;
00725 vertices[oi*items+7] = mesh.normals->at(v.vertices[j]).normal_y;
00726 vertices[oi*items+8] = mesh.normals->at(v.vertices[j]).normal_z;
00727 }
00728
00729 v.vertices[j] = (int)oi;
00730
00731 UASSERT(oi < organizedToDenseIndices_.size());
00732 organizedToDenseIndices_[oi] = oi;
00733
00734 ++oi;
00735 }
00736 }
00737 }
00738 else
00739 {
00740 totalPoints = mesh.cloud->size();
00741
00742 int items = hasNormals_?7:4;
00743 organizedToDenseIndices_ = std::vector<unsigned int>(totalPoints, -1);
00744 vertices = std::vector<float>(mesh.cloud->size()*items);
00745 for(unsigned int i=0; i<mesh.cloud->size(); ++i)
00746 {
00747 const pcl::PointXYZRGB & pt = mesh.cloud->at(i);
00748
00749 vertices[i*items] =pt.x;
00750 vertices[i*items+1] = pt.y;
00751 vertices[i*items+2] = pt.z;
00752 vertices[i*items+3] = pt.rgb;
00753
00754 updateAABBMinMax(pt, aabbMinModel_, aabbMaxModel_);
00755
00756 if(hasNormals_)
00757 {
00758 vertices[i*items+4] = mesh.normals->at(i).normal_x;
00759 vertices[i*items+5] = mesh.normals->at(i).normal_y;
00760 vertices[i*items+6] = mesh.normals->at(i).normal_z;
00761 }
00762
00763 organizedToDenseIndices_[i] = i;
00764 }
00765 }
00766 }
00767
00768 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffers_);
00769 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (int)vertices.size(), (const void *)vertices.data(), GL_STATIC_DRAW);
00770 glBindBuffer(GL_ARRAY_BUFFER, 0);
00771
00772 GLint error = glGetError();
00773 if(error != GL_NO_ERROR)
00774 {
00775 LOGE("OpenGL: Could not allocate point cloud (0x%x)\n", error);
00776 vertex_buffers_ = 0;
00777 return;
00778 }
00779
00780 if(textures_ && textureUpdate)
00781 {
00782
00783
00784
00785
00786
00787
00788
00789
00790 glBindTexture(GL_TEXTURE_2D, textures_);
00791 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00792 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00793 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00794 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00795 cv::Mat rgbImage;
00796 cv::cvtColor(mesh.texture, rgbImage, CV_BGR2RGBA);
00797
00798 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
00799
00800
00801
00802 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rgbImage.cols, rgbImage.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbImage.data);
00803
00804 GLint error = glGetError();
00805 if(error != GL_NO_ERROR)
00806 {
00807 LOGE("OpenGL: Could not allocate texture (0x%x)\n", error);
00808 textures_ = 0;
00809
00810 glDeleteBuffers(1, &vertex_buffers_);
00811 vertex_buffers_ = 0;
00812 return;
00813 }
00814 }
00815
00816 nPoints_ = totalPoints;
00817
00818 if(polygons_.size() != polygons.size())
00819 {
00820 updatePolygons(polygons, polygonsLowRes, createWireframe);
00821 }
00822
00823 if(!pose_.isNull())
00824 {
00825 updateAABBWorld(pose_);
00826 }
00827 }
00828
00829 void PointCloudDrawable::setPose(const rtabmap::Transform & pose)
00830 {
00831 UASSERT(!pose.isNull());
00832
00833 if(pose_ != pose)
00834 {
00835 updateAABBWorld(pose);
00836 }
00837
00838 pose_ = pose;
00839 poseGl_ = glmFromTransform(pose);
00840 }
00841
00842 void PointCloudDrawable::updateAABBWorld(const rtabmap::Transform & pose)
00843 {
00844 pcl::PointCloud<pcl::PointXYZ> corners;
00845 corners.resize(8);
00846 corners.at(0) = pcl::PointXYZ(aabbMinModel_.x, aabbMinModel_.y, aabbMinModel_.z);
00847 corners.at(1) = pcl::PointXYZ(aabbMinModel_.x, aabbMinModel_.y, aabbMaxModel_.z);
00848 corners.at(2) = pcl::PointXYZ(aabbMinModel_.x, aabbMaxModel_.y, aabbMinModel_.z);
00849 corners.at(3) = pcl::PointXYZ(aabbMaxModel_.x, aabbMinModel_.y, aabbMinModel_.z);
00850 corners.at(4) = pcl::PointXYZ(aabbMaxModel_.x, aabbMaxModel_.y, aabbMaxModel_.z);
00851 corners.at(5) = pcl::PointXYZ(aabbMaxModel_.x, aabbMaxModel_.y, aabbMinModel_.z);
00852 corners.at(6) = pcl::PointXYZ(aabbMaxModel_.x, aabbMinModel_.y, aabbMaxModel_.z);
00853 corners.at(7) = pcl::PointXYZ(aabbMinModel_.x, aabbMaxModel_.y, aabbMaxModel_.z);
00854
00855 pcl::PointCloud<pcl::PointXYZ> cornersTransformed;
00856 pcl::transformPointCloud(corners, cornersTransformed, pose.toEigen3f());
00857
00858 aabbMinWorld_ = pcl::PointXYZ(1000,1000,1000);
00859 aabbMaxWorld_ = pcl::PointXYZ(-1000,-1000,-1000);
00860 for(unsigned int i=0; i<cornersTransformed.size(); ++i)
00861 {
00862 updateAABBMinMax(cornersTransformed.at(i), aabbMinWorld_, aabbMaxWorld_);
00863 }
00864 }
00865
00866
00867 void PointCloudDrawable::Render(
00868 const glm::mat4 & projectionMatrix,
00869 const glm::mat4 & viewMatrix,
00870 bool meshRendering,
00871 float pointSize,
00872 bool textureRendering,
00873 bool lighting,
00874 float distanceToCameraSqr,
00875 const GLuint & depthTexture,
00876 int screenWidth,
00877 int screenHeight,
00878 float nearClipPlane,
00879 float farClipPlane,
00880 bool packDepthToColorChannel,
00881 bool wireFrame) const
00882 {
00883 if(vertex_buffers_ && nPoints_ && visible_ && !shaderPrograms_.empty())
00884 {
00885 if(packDepthToColorChannel || !hasNormals_)
00886 {
00887 lighting = false;
00888 }
00889
00890 if(packDepthToColorChannel || !(meshRendering && textureRendering && textures_))
00891 {
00892 textureRendering = false;
00893 }
00894
00895 GLuint program;
00896 if(packDepthToColorChannel)
00897 {
00898 program = shaderPrograms_[kDepthPacking];
00899 }
00900 else if(textureRendering)
00901 {
00902 if(lighting)
00903 {
00904 program = shaderPrograms_[depthTexture>0?kTextureLightingBlending:kTextureLighting];
00905 }
00906 else
00907 {
00908 program = shaderPrograms_[depthTexture>0?kTextureBlending:kTexture];
00909 }
00910 }
00911 else
00912 {
00913 if(lighting)
00914 {
00915 program = shaderPrograms_[depthTexture>0?kPointCloudLightingBlending:kPointCloudLighting];
00916 }
00917 else
00918 {
00919 program = shaderPrograms_[depthTexture>0?kPointCloudBlending:kPointCloud];
00920 }
00921 }
00922
00923 glUseProgram(program);
00924 tango_gl::util::CheckGlError("Pointcloud::Render() set program");
00925
00926 GLuint mvp_handle = glGetUniformLocation(program, "uMVP");
00927 glm::mat4 mv_mat = viewMatrix * poseGl_;
00928 glm::mat4 mvp_mat = projectionMatrix * mv_mat;
00929 glUniformMatrix4fv(mvp_handle, 1, GL_FALSE, glm::value_ptr(mvp_mat));
00930
00931 GLint attribute_vertex = glGetAttribLocation(program, "aVertex");
00932 glEnableVertexAttribArray(attribute_vertex);
00933 GLint attribute_color = 0;
00934 GLint attribute_texture = 0;
00935 GLint attribute_normal = 0;
00936
00937 if(packDepthToColorChannel || !textureRendering)
00938 {
00939 GLuint point_size_handle_ = glGetUniformLocation(program, "uPointSize");
00940 glUniform1f(point_size_handle_, pointSize);
00941 }
00942 tango_gl::util::CheckGlError("Pointcloud::Render() vertex");
00943
00944 if(!packDepthToColorChannel)
00945 {
00946 GLuint gainR_handle = glGetUniformLocation(program, "uGainR");
00947 GLuint gainG_handle = glGetUniformLocation(program, "uGainG");
00948 GLuint gainB_handle = glGetUniformLocation(program, "uGainB");
00949 glUniform1f(gainR_handle, gainR_);
00950 glUniform1f(gainG_handle, gainG_);
00951 glUniform1f(gainB_handle, gainB_);
00952
00953
00954 if(depthTexture > 0)
00955 {
00956
00957 glActiveTexture(GL_TEXTURE1);
00958
00959 glBindTexture(GL_TEXTURE_2D, depthTexture);
00960
00961 GLuint depth_texture_handle = glGetUniformLocation(program, "uDepthTexture");
00962 glUniform1i(depth_texture_handle, 1);
00963
00964 GLuint zNear_handle = glGetUniformLocation(program, "uNearZ");
00965 GLuint zFar_handle = glGetUniformLocation(program, "uFarZ");
00966 glUniform1f(zNear_handle, nearClipPlane);
00967 glUniform1f(zFar_handle, farClipPlane);
00968
00969 GLuint screenScale_handle = glGetUniformLocation(program, "uScreenScale");
00970 glUniform2f(screenScale_handle, 1.0f/(float)screenWidth, 1.0f/(float)screenHeight);
00971 }
00972
00973 if(lighting)
00974 {
00975 GLuint n_handle = glGetUniformLocation(program, "uN");
00976 glm::mat3 normalMatrix(mv_mat);
00977 normalMatrix = glm::inverse(normalMatrix);
00978 normalMatrix = glm::transpose(normalMatrix);
00979 glUniformMatrix3fv(n_handle, 1, GL_FALSE, glm::value_ptr(normalMatrix));
00980
00981 GLuint lightingDirection_handle = glGetUniformLocation(program, "uLightingDirection");
00982 glUniform3f(lightingDirection_handle, 0.0, 0.0, 1.0);
00983
00984 attribute_normal = glGetAttribLocation(program, "aNormal");
00985 glEnableVertexAttribArray(attribute_normal);
00986 }
00987
00988 if(textureRendering)
00989 {
00990
00991 glActiveTexture(GL_TEXTURE0);
00992
00993 glBindTexture(GL_TEXTURE_2D, textures_);
00994
00995 GLuint texture_handle = glGetUniformLocation(program, "uTexture");
00996 glUniform1i(texture_handle, 0);
00997
00998 attribute_texture = glGetAttribLocation(program, "aTexCoord");
00999 glEnableVertexAttribArray(attribute_texture);
01000 }
01001 else
01002 {
01003 attribute_color = glGetAttribLocation(program, "aColor");
01004 glEnableVertexAttribArray(attribute_color);
01005 }
01006 }
01007 tango_gl::util::CheckGlError("Pointcloud::Render() common");
01008
01009 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffers_);
01010 if(textures_)
01011 {
01012 glVertexAttribPointer(attribute_vertex, 3, GL_FLOAT, GL_FALSE, (hasNormals_?9:6)*sizeof(GLfloat), 0);
01013 if(textureRendering)
01014 {
01015 glVertexAttribPointer(attribute_texture, 2, GL_FLOAT, GL_FALSE, (hasNormals_?9:6)*sizeof(GLfloat), (GLvoid*) (4 * sizeof(GLfloat)));
01016 }
01017 else if(!packDepthToColorChannel)
01018 {
01019 glVertexAttribPointer(attribute_color, 3, GL_UNSIGNED_BYTE, GL_TRUE, (hasNormals_?9:6)*sizeof(GLfloat), (GLvoid*) (3 * sizeof(GLfloat)));
01020 }
01021 if(lighting && hasNormals_)
01022 {
01023 glVertexAttribPointer(attribute_normal, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (GLvoid*) (6 * sizeof(GLfloat)));
01024 }
01025 }
01026 else
01027 {
01028 glVertexAttribPointer(attribute_vertex, 3, GL_FLOAT, GL_FALSE, (hasNormals_?7:4)*sizeof(GLfloat), 0);
01029 if(!packDepthToColorChannel)
01030 {
01031 glVertexAttribPointer(attribute_color, 3, GL_UNSIGNED_BYTE, GL_TRUE, (hasNormals_?7:4)*sizeof(GLfloat), (GLvoid*) (3 * sizeof(GLfloat)));
01032 }
01033 if(lighting && hasNormals_)
01034 {
01035 glVertexAttribPointer(attribute_normal, 3, GL_FLOAT, GL_FALSE, 7*sizeof(GLfloat), (GLvoid*) (4 * sizeof(GLfloat)));
01036 }
01037 }
01038 tango_gl::util::CheckGlError("Pointcloud::Render() set attribute pointer");
01039
01040 UTimer drawTime;
01041 if(textureRendering)
01042 {
01043 if(distanceToCameraSqr<16.0f || polygonsLowRes_.empty())
01044 {
01045 wireFrame = wireFrame && polygonLines_.size();
01046 if(wireFrame)
01047 glDrawElements(GL_LINES, polygonLines_.size(), GL_UNSIGNED_INT, polygonLines_.data());
01048 else
01049 glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data());
01050 }
01051 else
01052 {
01053 wireFrame = wireFrame && polygonLinesLowRes_.size();
01054 if(wireFrame)
01055 glDrawElements(GL_LINES, polygonLinesLowRes_.size(), GL_UNSIGNED_INT, polygonLinesLowRes_.data());
01056 else
01057 glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data());
01058 }
01059 }
01060 else if(meshRendering && polygons_.size())
01061 {
01062 if(distanceToCameraSqr<50.0f || polygonsLowRes_.empty())
01063 {
01064 wireFrame = wireFrame && polygonLines_.size();
01065 if(wireFrame)
01066 glDrawElements(GL_LINES, polygonLines_.size(), GL_UNSIGNED_INT, polygonLines_.data());
01067 else
01068 glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data());
01069 }
01070 else
01071 {
01072 wireFrame = wireFrame && polygonLinesLowRes_.size();
01073 if(wireFrame)
01074 glDrawElements(GL_LINES, polygonLinesLowRes_.size(), GL_UNSIGNED_INT, polygonLinesLowRes_.data());
01075 else
01076 glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data());
01077 }
01078 }
01079 else if(!verticesLowRes_.empty())
01080 {
01081 if(distanceToCameraSqr>600.0f)
01082 {
01083 glDrawElements(GL_POINTS, verticesLowLowRes_.size(), GL_UNSIGNED_INT, verticesLowLowRes_.data());
01084 }
01085 else if(distanceToCameraSqr>150.0f)
01086 {
01087 glDrawElements(GL_POINTS, verticesLowRes_.size(), GL_UNSIGNED_INT, verticesLowRes_.data());
01088 }
01089 else
01090 {
01091 glDrawArrays(GL_POINTS, 0, nPoints_);
01092 }
01093 }
01094 else
01095 {
01096 glDrawArrays(GL_POINTS, 0, nPoints_);
01097 }
01098
01099 tango_gl::util::CheckGlError("Pointcloud::Render() draw");
01100
01101 glDisableVertexAttribArray(0);
01102 glBindBuffer(GL_ARRAY_BUFFER, 0);
01103
01104 glUseProgram(0);
01105 tango_gl::util::CheckGlError("Pointcloud::Render() cleaning");
01106 }
01107 }
01108