diff --git a/app/android/jni/RTABMapApp.cpp b/app/android/jni/RTABMapApp.cpp index 8a27447a..f6ff5ecc 100644 --- a/app/android/jni/RTABMapApp.cpp +++ b/app/android/jni/RTABMapApp.cpp @@ -954,7 +954,7 @@ int RTABMapApp::Render() mesh.texture = exportedTexture_; } - main_scene_.addMesh(g_exportedMeshId, mesh, opengl_world_T_rtabmap_world); + main_scene_.addMesh(g_exportedMeshId, mesh, opengl_world_T_rtabmap_world, true); } else { @@ -1614,6 +1614,10 @@ void RTABMapApp::setBackfaceCulling(bool enabled) { main_scene_.setBackfaceCulling(enabled); } +void RTABMapApp::setWireframe(bool enabled) +{ + main_scene_.setWireframe(enabled); +} void RTABMapApp::setLocalizationMode(bool enabled) { diff --git a/app/android/jni/RTABMapApp.h b/app/android/jni/RTABMapApp.h index 50cfe500..a441dfad 100644 --- a/app/android/jni/RTABMapApp.h +++ b/app/android/jni/RTABMapApp.h @@ -123,6 +123,7 @@ class RTABMapApp : public UEventsHandler { void setOrthoCropFactor(float value); void setLighting(bool enabled); void setBackfaceCulling(bool enabled); + void setWireframe(bool enabled); void setLocalizationMode(bool enabled); void setTrajectoryMode(bool enabled); void setGraphOptimization(bool enabled); diff --git a/app/android/jni/jni_interface.cpp b/app/android/jni/jni_interface.cpp index 9a56980e..ef2981c9 100644 --- a/app/android/jni/jni_interface.cpp +++ b/app/android/jni/jni_interface.cpp @@ -181,6 +181,12 @@ Java_com_introlab_rtabmap_RTABMapLib_setBackfaceCulling( return app.setBackfaceCulling(enabled); } JNIEXPORT void JNICALL +Java_com_introlab_rtabmap_RTABMapLib_setWireframe( + JNIEnv*, jobject, bool enabled) +{ + return app.setWireframe(enabled); +} +JNIEXPORT void JNICALL Java_com_introlab_rtabmap_RTABMapLib_setLocalizationMode( JNIEnv*, jobject, bool enabled) { diff --git a/app/android/jni/point_cloud_drawable.cpp b/app/android/jni/point_cloud_drawable.cpp index 73224d59..b9fe5102 100644 --- a/app/android/jni/point_cloud_drawable.cpp +++ b/app/android/jni/point_cloud_drawable.cpp @@ -318,7 +318,8 @@ PointCloudDrawable::PointCloudDrawable( } PointCloudDrawable::PointCloudDrawable( - const Mesh & mesh) : + const Mesh & mesh, + bool createWireframe) : vertex_buffers_(0), textures_(0), nPoints_(0), @@ -330,7 +331,7 @@ PointCloudDrawable::PointCloudDrawable( gainG_(1.0f), gainB_(1.0f) { - updateMesh(mesh); + updateMesh(mesh, createWireframe); } PointCloudDrawable::~PointCloudDrawable() @@ -351,22 +352,33 @@ PointCloudDrawable::~PointCloudDrawable() } } -void PointCloudDrawable::updatePolygons(const std::vector & polygons, const std::vector & polygonsLowRes) +void PointCloudDrawable::updatePolygons(const std::vector & polygons, const std::vector & polygonsLowRes, bool createWireframe) { LOGD("Update polygons"); polygons_.clear(); + polygonLines_.clear(); + polygonsLowRes_.clear(); + polygonLinesLowRes_.clear(); if(polygons.size() && organizedToDenseIndices_.size()) { unsigned int polygonSize = polygons[0].vertices.size(); UASSERT(polygonSize == 3); polygons_.resize(polygons.size() * polygonSize); + if(createWireframe) + polygonLines_.resize(polygons_.size()*2); int oi = 0; + int li = 0; for(unsigned int i=0; i & polyg unsigned int polygonSize = polygonsLowRes[0].vertices.size(); UASSERT(polygonSize == 3); polygonsLowRes_.resize(polygonsLowRes.size() * polygonSize); + if(createWireframe) + polygonLinesLowRes_.resize(polygonsLowRes_.size()*2); int oi = 0; + int li = 0; for(unsigned int i=0; i::Pt nPoints_ = totalPoints; } -void PointCloudDrawable::updateMesh(const Mesh & mesh) +void PointCloudDrawable::updateMesh(const Mesh & mesh, bool createWireframe) { UASSERT(mesh.cloud.get() && !mesh.cloud->empty()); nPoints_ = 0; @@ -797,7 +817,7 @@ void PointCloudDrawable::updateMesh(const Mesh & mesh) if(polygons_.size() != polygons.size()) { - updatePolygons(polygons, polygonsLowRes); + updatePolygons(polygons, polygonsLowRes, createWireframe); } if(!pose_.isNull()) @@ -857,7 +877,8 @@ void PointCloudDrawable::Render( int screenHeight, float nearClipPlane, float farClipPlane, - bool packDepthToColorChannel) const + bool packDepthToColorChannel, + bool wireFrame) const { if(vertex_buffers_ && nPoints_ && visible_ && !shaderPrograms_.empty()) { @@ -1021,22 +1042,38 @@ void PointCloudDrawable::Render( { if(distanceToCameraSqr<16.0f || polygonsLowRes_.empty()) { - glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data()); + wireFrame = wireFrame && polygonLines_.size(); + if(wireFrame) + glDrawElements(GL_LINES, polygonLines_.size(), GL_UNSIGNED_INT, polygonLines_.data()); + else + glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data()); } else { - glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data()); + wireFrame = wireFrame && polygonLinesLowRes_.size(); + if(wireFrame) + glDrawElements(GL_LINES, polygonLinesLowRes_.size(), GL_UNSIGNED_INT, polygonLinesLowRes_.data()); + else + glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data()); } } else if(meshRendering && polygons_.size()) { if(distanceToCameraSqr<50.0f || polygonsLowRes_.empty()) { - glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data()); + wireFrame = wireFrame && polygonLines_.size(); + if(wireFrame) + glDrawElements(GL_LINES, polygonLines_.size(), GL_UNSIGNED_INT, polygonLines_.data()); + else + glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data()); } else { - glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data()); + wireFrame = wireFrame && polygonLinesLowRes_.size(); + if(wireFrame) + glDrawElements(GL_LINES, polygonLinesLowRes_.size(), GL_UNSIGNED_INT, polygonLinesLowRes_.data()); + else + glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data()); } } else if(!verticesLowRes_.empty()) diff --git a/app/android/jni/point_cloud_drawable.h b/app/android/jni/point_cloud_drawable.h index 2c09f5f5..d62ec100 100644 --- a/app/android/jni/point_cloud_drawable.h +++ b/app/android/jni/point_cloud_drawable.h @@ -55,12 +55,13 @@ private: float gainG = 1.0f, float gainB = 1.0f); PointCloudDrawable( - const Mesh & mesh); + const Mesh & mesh, + bool createWireframe = false); virtual ~PointCloudDrawable(); - void updatePolygons(const std::vector & polygons, const std::vector & polygonsLowRes = std::vector()); + void updatePolygons(const std::vector & polygons, const std::vector & polygonsLowRes = std::vector(), bool createWireframe = false); void updateCloud(const pcl::PointCloud::Ptr & cloud, const pcl::IndicesPtr & indices); - void updateMesh(const Mesh & mesh); + void updateMesh(const Mesh & mesh, bool createWireframe = false); void setPose(const rtabmap::Transform & pose); void setVisible(bool visible) {visible_=visible;} void setGains(float gainR, float gainG, float gainB) {gainR_ = gainR; gainG_ = gainG; gainB_ = gainB;} @@ -93,7 +94,8 @@ private: int screenHeight = 0, // nonnull if depthTexture>0 float nearClipPlane = 0, // nonnull if depthTexture>0 float farClipPlane = 0, // nonnull if depthTexture>0 - bool packDepthToColorChannel = false) const; + bool packDepthToColorChannel = false, + bool wireFrame = false) const; private: template @@ -114,6 +116,8 @@ private: GLuint textures_; std::vector polygons_; std::vector polygonsLowRes_; + std::vector polygonLines_; + std::vector polygonLinesLowRes_; std::vector verticesLowRes_; std::vector verticesLowLowRes_; int nPoints_; diff --git a/app/android/jni/scene.cpp b/app/android/jni/scene.cpp index 945b201d..f4e9ff97 100644 --- a/app/android/jni/scene.cpp +++ b/app/android/jni/scene.cpp @@ -86,6 +86,7 @@ Scene::Scene() : boundingBoxRendering_(false), lighting_(false), backfaceCulling_(true), + wireFrame_(false), r_(0.0f), g_(0.0f), b_(0.0f), @@ -533,7 +534,7 @@ int Scene::Render() { 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()); + cloud->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, meshRenderingTexture_, lighting_, distanceToCameraSqr, onlineBlending?depthTexture_:0, screenWidth_, screenHeight_, gesture_camera_->getNearClipPlane(), gesture_camera_->getFarClipPlane(), false, wireFrame_); } if(onlineBlending) @@ -653,7 +654,8 @@ void Scene::addCloud( void Scene::addMesh( int id, const Mesh & mesh, - const rtabmap::Transform & pose) + const rtabmap::Transform & pose, + bool createWireframe) { LOGI("add mesh %d", id); std::map::iterator iter=pointClouds_.find(id); @@ -664,7 +666,7 @@ void Scene::addMesh( } //create - PointCloudDrawable * drawable = new PointCloudDrawable(mesh); + PointCloudDrawable * drawable = new PointCloudDrawable(mesh, createWireframe); drawable->setPose(pose); pointClouds_.insert(std::make_pair(id, drawable)); } diff --git a/app/android/jni/scene.h b/app/android/jni/scene.h index ed7fba5e..b4acbb20 100644 --- a/app/android/jni/scene.h +++ b/app/android/jni/scene.h @@ -108,7 +108,8 @@ class Scene { void addMesh( int id, const Mesh & mesh, - const rtabmap::Transform & pose); + const rtabmap::Transform & pose, + bool createWireframe = false); void setCloudPose(int id, const rtabmap::Transform & pose); void setCloudVisible(int id, bool visible); @@ -128,6 +129,7 @@ class Scene { void setOrthoCropFactor(float value); void setLighting(bool enabled) {lighting_ = enabled;} void setBackfaceCulling(bool enabled) {backfaceCulling_ = enabled;} + void setWireframe(bool enabled) {wireFrame_ = enabled;} void setBackgroundColor(float r, float g, float b) {r_=r; g_=g; b_=b;} // 0.0f <> 1.0f void setGridColor(float r, float g, float b); @@ -179,6 +181,7 @@ class Scene { bool boundingBoxRendering_; bool lighting_; bool backfaceCulling_; + bool wireFrame_; float r_; float g_; float b_; diff --git a/app/android/res/layout/activity_rtabmap.xml b/app/android/res/layout/activity_rtabmap.xml index a8b400ee..4f62555c 100644 --- a/app/android/res/layout/activity_rtabmap.xml +++ b/app/android/res/layout/activity_rtabmap.xml @@ -23,6 +23,19 @@ android:layout_height="fill_parent" android:layout_gravity="top" /> + + Backface Lighting Lighting + Wireframe Close Visualization Export to File… Share to Sketchfab… diff --git a/app/android/src/com/introlab/rtabmap/RTABMapActivity.java b/app/android/src/com/introlab/rtabmap/RTABMapActivity.java index 557e6f52..03481284 100644 --- a/app/android/src/com/introlab/rtabmap/RTABMapActivity.java +++ b/app/android/src/com/introlab/rtabmap/RTABMapActivity.java @@ -127,6 +127,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { public static final long NOTOUCH_TIMEOUT = 5000; // 5 sec private boolean mHudVisible = true; private boolean mTipOrthoShown_ = false; + private int mSavedRenderingType = 0; // UI states private static enum State { @@ -172,6 +173,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { private ToggleButton mButtonTop; private ToggleButton mButtonPause; private ToggleButton mButtonLighting; + private ToggleButton mButtonWireframe; private ToggleButton mButtonBackfaceShown; private Button mButtonCloseVisualization; private Button mButtonSaveOnDevice; @@ -253,6 +255,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { mButtonTop = (ToggleButton)findViewById(R.id.top_down_button); mButtonPause = (ToggleButton)findViewById(R.id.pause_button); mButtonLighting = (ToggleButton)findViewById(R.id.light_button); + mButtonWireframe = (ToggleButton)findViewById(R.id.wireframe_button); mButtonBackfaceShown = (ToggleButton)findViewById(R.id.backface_button); mButtonCloseVisualization = (Button)findViewById(R.id.close_visualization_button); mButtonSaveOnDevice = (Button)findViewById(R.id.button_saveOnDevice); @@ -262,6 +265,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { mButtonTop.setOnClickListener(this); mButtonPause.setOnClickListener(this); mButtonLighting.setOnClickListener(this); + mButtonWireframe.setOnClickListener(this); mButtonBackfaceShown.setOnClickListener(this); mButtonCloseVisualization.setOnClickListener(this); mButtonSaveOnDevice.setOnClickListener(this); @@ -269,6 +273,8 @@ public class RTABMapActivity extends Activity implements OnClickListener { mButtonFirst.setChecked(true); mButtonLighting.setChecked(false); mButtonLighting.setVisibility(View.INVISIBLE); + mButtonWireframe.setChecked(false); + mButtonWireframe.setVisibility(View.INVISIBLE); mButtonCloseVisualization.setVisibility(View.INVISIBLE); mButtonSaveOnDevice.setVisibility(View.INVISIBLE); mButtonShareOnSketchfab.setVisibility(View.INVISIBLE); @@ -289,7 +295,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { } else if(mButtonTop.isChecked()) { - RTABMapLib.setOrthoCropFactor((float)progressValue/20.0f - 3.0f); + RTABMapLib.setOrthoCropFactor((float)(120-progressValue)/20.0f - 3.0f); } resetNoTouchTimer(); } @@ -644,7 +650,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { if(type==3) { mSeekBarFov.setMax(120); - mSeekBarFov.setProgress(40); + mSeekBarFov.setProgress(80); } if(type==2 && !mTipOrthoShown_) @@ -677,7 +683,22 @@ public class RTABMapActivity extends Activity implements OnClickListener { case R.id.backface_button: RTABMapLib.setBackfaceCulling(!mButtonBackfaceShown.isChecked()); break; + case R.id.wireframe_button: + RTABMapLib.setWireframe(mButtonWireframe.isChecked()); + break; case R.id.close_visualization_button: + if(mSavedRenderingType==0) + { + mItemRenderingPointCloud.setChecked(true); + } + else if(mSavedRenderingType==1) + { + mItemRenderingMesh.setChecked(true); + } + else + { + mItemRenderingTextureMesh.setChecked(true); + } updateState(State.STATE_IDLE); RTABMapLib.postExportation(false); break; @@ -1261,6 +1282,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { { case STATE_PROCESSING: mButtonLighting.setVisibility(View.INVISIBLE); + mButtonWireframe.setVisibility(View.INVISIBLE); mButtonCloseVisualization.setVisibility(View.INVISIBLE); mButtonSaveOnDevice.setVisibility(View.INVISIBLE); mButtonShareOnSketchfab.setVisibility(View.INVISIBLE); @@ -1274,7 +1296,8 @@ public class RTABMapActivity extends Activity implements OnClickListener { mButtonPause.setVisibility(View.INVISIBLE); break; case STATE_VISUALIZING: - mButtonLighting.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE); + mButtonLighting.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE); + mButtonWireframe.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE); mButtonCloseVisualization.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE); mButtonSaveOnDevice.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE); mButtonShareOnSketchfab.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE); @@ -1290,6 +1313,7 @@ public class RTABMapActivity extends Activity implements OnClickListener { break; default: mButtonLighting.setVisibility(View.INVISIBLE); + mButtonWireframe.setVisibility(View.INVISIBLE); mButtonCloseVisualization.setVisibility(View.INVISIBLE); mButtonSaveOnDevice.setVisibility(View.INVISIBLE); mButtonShareOnSketchfab.setVisibility(View.INVISIBLE); @@ -1500,15 +1524,18 @@ public class RTABMapActivity extends Activity implements OnClickListener { mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(), mItemRenderingTextureMesh.isChecked()); - mButtonBackfaceShown.setVisibility(mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked()?View.VISIBLE:View.INVISIBLE); - - // save preference - int type = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2; - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putInt(getString(R.string.pref_key_rendering), type); - // Commit the edits! - editor.commit(); + resetNoTouchTimer(); + + if(mState != State.STATE_VISUALIZING) + { + // save preference + int type = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2; + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putInt(getString(R.string.pref_key_rendering), type); + // Commit the edits! + editor.commit(); + } } else if(itemId == R.id.map_shown) { @@ -1920,6 +1947,19 @@ public class RTABMapActivity extends Activity implements OnClickListener { public void onClick(DialogInterface dialog, int which) { mExportedOBJ = isOBJ; resetNoTouchTimer(); + mSavedRenderingType = !meshing?0:!isOBJ?1:2; + if(!meshing) + { + mItemRenderingPointCloud.setChecked(true); + } + else if(!isOBJ) + { + mItemRenderingMesh.setChecked(true); + } + else // isOBJ + { + mItemRenderingTextureMesh.setChecked(true); + } updateState(State.STATE_VISUALIZING); RTABMapLib.postExportation(true); if(mButtonFirst.isChecked()) diff --git a/app/android/src/com/introlab/rtabmap/RTABMapLib.java b/app/android/src/com/introlab/rtabmap/RTABMapLib.java index e774dccb..d7a2a859 100644 --- a/app/android/src/com/introlab/rtabmap/RTABMapLib.java +++ b/app/android/src/com/introlab/rtabmap/RTABMapLib.java @@ -81,6 +81,7 @@ public class RTABMapLib public static native void setOrthoCropFactor(float value); public static native void setLighting(boolean enabled); public static native void setBackfaceCulling(boolean enabled); + public static native void setWireframe(boolean enabled); public static native void setCloudDensityLevel(int value); public static native void setMeshAngleTolerance(float value); public static native void setMeshTriangleSize(int value);