Tango: Added Ortho mode (#193)

This commit is contained in:
matlabbe
2017-06-12 15:36:33 -04:00
parent bbaac8b2b1
commit c00119989e
12 changed files with 213 additions and 69 deletions

View File

@@ -1598,6 +1598,14 @@ void RTABMapApp::setPointSize(float value)
{
main_scene_.setPointSize(value);
}
void RTABMapApp::setFOV(float angle)
{
main_scene_.setFOV(angle);
}
void RTABMapApp::setOrthoCropFactor(float value)
{
main_scene_.setOrthoCropFactor(value);
}
void RTABMapApp::setLighting(bool enabled)
{
main_scene_.setLighting(enabled);

View File

@@ -119,6 +119,8 @@ class RTABMapApp : public UEventsHandler {
void setOdomCloudShown(bool shown);
void setMeshRendering(bool enabled, bool withTexture);
void setPointSize(float value);
void setFOV(float angle);
void setOrthoCropFactor(float value);
void setLighting(bool enabled);
void setBackfaceCulling(bool enabled);
void setLocalizationMode(bool enabled);

View File

@@ -157,6 +157,18 @@ Java_com_introlab_rtabmap_RTABMapLib_setPointSize(
return app.setPointSize(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setFOV(
JNIEnv*, jobject, float fov)
{
return app.setFOV(fov);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setOrthoCropFactor(
JNIEnv*, jobject, float value)
{
return app.setOrthoCropFactor(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setLighting(
JNIEnv*, jobject, bool enabled)
{

View File

@@ -201,7 +201,7 @@ void Scene::SetupViewPort(int w, int h) {
LOGE("Setup graphic height not valid");
}
UASSERT(gesture_camera_ != 0);
gesture_camera_->SetAspectRatio(static_cast<float>(w) / static_cast<float>(h));
gesture_camera_->SetWindowSize(static_cast<float>(w), static_cast<float>(h));
glViewport(0, 0, w, h);
if(screenWidth_ != w || fboId_ == 0)
{
@@ -426,7 +426,7 @@ int Scene::Render() {
UTimer timer;
bool onlineBlending = blending_ && mapRendering_ && meshRendering_ && cloudsToDraw.size()>1;
bool onlineBlending = blending_ && gesture_camera_->GetCameraType()!=tango_gl::GestureCamera::kTopOrtho && mapRendering_ && meshRendering_ && cloudsToDraw.size()>1;
if(onlineBlending && fboId_)
{
// set the rendering destination to FBO
@@ -556,6 +556,15 @@ void Scene::SetCameraPose(const rtabmap::Transform & pose)
*currentPose_ = pose;
}
void Scene::setFOV(float angle)
{
gesture_camera_->SetFieldOfView(angle);
}
void Scene::setOrthoCropFactor(float value)
{
gesture_camera_->SetOrthoCropFactor(value);
}
rtabmap::Transform Scene::GetOpenGLCameraPose(float * fov) const
{
if(fov)
@@ -563,7 +572,6 @@ rtabmap::Transform Scene::GetOpenGLCameraPose(float * fov) const
*fov = gesture_camera_->getFOV();
}
return glmToTransform(gesture_camera_->GetTransformationMatrix());
}
void Scene::OnTouchEvent(int touch_count,

View File

@@ -124,6 +124,8 @@ class Scene {
void setMapRendering(bool enabled) {mapRendering_ = enabled;}
void setMeshRendering(bool enabled, bool withTexture) {meshRendering_ = enabled; meshRenderingTexture_ = withTexture;}
void setPointSize(float size) {pointSize_ = size;}
void setFOV(float angle);
void setOrthoCropFactor(float value);
void setLighting(bool enabled) {lighting_ = enabled;}
void setBackfaceCulling(bool enabled) {backfaceCulling_ = enabled;}
void setBackgroundColor(float r, float g, float b) {r_=r; g_=g; b_=b;} // 0.0f <> 1.0f

View File

@@ -22,8 +22,13 @@ namespace tango_gl {
Camera::Camera() {
field_of_view_ = 45.0f * DEGREE_2_RADIANS;
aspect_ratio_ = 4.0f / 3.0f;
width_ = 800.0f;
height_ = 600.0f;
near_clip_plane_ = 0.2f;
far_clip_plane_ = 1000.0f;
ortho_ = false;
orthoScale_ = 2.0f;
orthoCropFactor_ = -1.0f;
}
glm::mat4 Camera::GetViewMatrix() {
@@ -31,12 +36,17 @@ glm::mat4 Camera::GetViewMatrix() {
}
glm::mat4 Camera::GetProjectionMatrix() {
return glm::perspective(field_of_view_, aspect_ratio_,
near_clip_plane_, far_clip_plane_);
if(ortho_)
{
return glm::ortho(-orthoScale_*aspect_ratio_, orthoScale_*aspect_ratio_, -orthoScale_, orthoScale_, orthoScale_ + orthoCropFactor_, far_clip_plane_);
}
return glm::perspective(field_of_view_, aspect_ratio_, near_clip_plane_, far_clip_plane_);
}
void Camera::SetAspectRatio(float aspect_ratio) {
aspect_ratio_ = aspect_ratio;
void Camera::SetWindowSize(float width, float height) {
width_ = width;
height_ = height;
aspect_ratio_ = width/height;
}
void Camera::SetFieldOfView(float fov) {

View File

@@ -62,68 +62,79 @@ GestureCamera::GestureCamera() :
GestureCamera::~GestureCamera() { delete cam_parent_transform_; }
void GestureCamera::OnTouchEvent(int touch_count, TouchEvent event, float x0,
float y0, float x1, float y1) {
if (camera_type_ == kFirstPerson) {
return;
}
float y0, float x1, float y1) {
if (camera_type_ == kFirstPerson) {
return;
}
if (touch_count == 1) {
switch (event) {
case kTouch0Down: {
cam_start_angle_ = cam_cur_angle_;
if (touch_count == 1) {
switch (event) {
case kTouch0Down: {
cam_start_angle_ = cam_cur_angle_;
touch0_start_position_.x = x0;
touch0_start_position_.y = y0;
break;
}
case kTouchMove: {
float rotation_x = (touch0_start_position_.y - y0) * kRotationSpeed;
float rotation_y = (touch0_start_position_.x - x0) * kRotationSpeed;
touch0_start_position_.x = x0;
touch0_start_position_.y = y0;
break;
}
case kTouchMove: {
glm::vec2 offset;
cam_cur_angle_.x = cam_start_angle_.x + rotation_x;
cam_cur_angle_.y = cam_start_angle_.y + rotation_y;
StartCameraToCurrentTransform();
break;
}
default: { break; }
}
}
if (touch_count == 2) {
switch (event) {
case kTouch1Down: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
start_touch_dist_ = std::sqrt(abs_x * abs_x + abs_y * abs_y);
cam_start_dist_ = GetPosition().z;
float rotation_x = (touch0_start_position_.y - y0) * kRotationSpeed;
float rotation_y = (touch0_start_position_.x - x0) * kRotationSpeed;
// center touch
touch0_start_position_.x = (x0+x1)/2.0f;
touch0_start_position_.y = (y0+y1)/2.0f;
break;
}
case kTouchMove: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
float dist = start_touch_dist_ - std::sqrt(abs_x * abs_x + abs_y * abs_y);
if(camera_type_!=kTopOrtho)
cam_cur_angle_.x = cam_start_angle_.x + rotation_x;
cam_cur_angle_.y = cam_start_angle_.y + rotation_y;
cam_cur_dist_ = tango_gl::util::Clamp(cam_start_dist_ + dist * kZoomSpeed,
kCamViewMinDist, kCamViewMaxDist);
StartCameraToCurrentTransform();
glm::vec2 touch_center_position((x0+x1)/2.0f, (y0+y1)/2.0f);
glm::vec2 offset;
offset.x = (touch_center_position.x - touch0_start_position_.x) * kMoveSpeed;
offset.y = (touch_center_position.y - touch0_start_position_.y) * kMoveSpeed;
touch0_start_position_ = touch_center_position;
break;
}
default: { break; }
}
}
if (touch_count == 2) {
switch (event) {
case kTouch1Down: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
start_touch_dist_ = std::sqrt(abs_x * abs_x + abs_y * abs_y);
cam_start_dist_ = GetPosition().z;
StartCameraToCurrentTransform();
// center touch
touch0_start_position_.x = (x0+x1)/2.0f;
touch0_start_position_.y = (y0+y1)/2.0f;
break;
}
case kTouchMove: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
float dist = start_touch_dist_ - std::sqrt(abs_x * abs_x + abs_y * abs_y);
anchor_offset_ += glm::rotate(cam_parent_transform_->GetRotation(), glm::vec3(-offset.x, offset.y, 0));
cam_cur_dist_ = tango_gl::util::Clamp(cam_start_dist_ + dist * kZoomSpeed,
kCamViewMinDist, kCamViewMaxDist);
break;
}
default: { break; }
}
}
this->SetOrthoMode(camera_type_ == kTopOrtho);
if(camera_type_ == kTopOrtho)
{
this->SetOrthoScale(cam_cur_dist_);
}
glm::vec2 touch_center_position((x0+x1)/2.0f, (y0+y1)/2.0f);
glm::vec2 offset;
offset.x = (touch_center_position.x - touch0_start_position_.x) * kMoveSpeed;
offset.y = (touch_center_position.y - touch0_start_position_.y) * kMoveSpeed;
touch0_start_position_ = touch_center_position;
StartCameraToCurrentTransform();
anchor_offset_ += glm::rotate(cam_parent_transform_->GetRotation(), glm::vec3(-offset.x, offset.y, 0));
break;
}
default: { break; }
}
}
}
Segment GestureCamera::GetSegmentFromTouch(float normalized_x,
@@ -164,6 +175,7 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
camera_type_ = camera_index;
switch (camera_index) {
case kFirstPerson:
SetOrthoMode(false);
SetFieldOfView(kLowFov);
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
@@ -177,7 +189,8 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
break;
case kThirdPerson:
case kThirdPersonFollow:
SetFieldOfView(kHighFov);
SetOrthoMode(false);
SetFieldOfView(kHighFov);
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
cam_cur_dist_ = kThirdPersonFollow?kThirdPersonFollowCameraDist:kThirdPersonCameraDist;
@@ -188,9 +201,10 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
StartCameraToCurrentTransform();
break;
case kTopDown:
SetFieldOfView(kHighFov);
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
SetOrthoMode(false);
SetFieldOfView(kHighFov);
cam_cur_dist_ = kTopDownCameraDist;
anchor_offset_ = glm::vec3(0.0f,0.0f,0.0f);
cam_cur_angle_.x = -M_PI / 2.0f;
@@ -198,6 +212,19 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
cam_cur_target_rot_ = glm::quat(1,0,0,0);
StartCameraToCurrentTransform();
break;
case kTopOrtho:
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
SetOrthoMode(true);
SetOrthoScale(kTopDownCameraDist);
SetOrthoCropFactor(-1.0f);
cam_cur_dist_ = kTopDownCameraDist;
anchor_offset_ = glm::vec3(0.0f,0.0f,0.0f);
cam_cur_angle_.x = -M_PI / 2.0f;
cam_cur_angle_.y = 0.0f;
cam_cur_target_rot_ = glm::quat(1,0,0,0);
StartCameraToCurrentTransform();
break;
default:
break;
}

View File

@@ -27,8 +27,11 @@ class Camera : public Transform {
Camera& operator=(const Camera&) = delete;
~Camera();
void SetAspectRatio(const float aspect_ratio);
void SetWindowSize(const float width, const float height);
void SetFieldOfView(const float fov);
void SetOrthoMode(bool enabled) {ortho_ = enabled;}
void SetOrthoScale(float scale) {orthoScale_ = scale;}
void SetOrthoCropFactor(float value) {orthoCropFactor_ = value;}
void SetNearFarClipPlanes(const float near, const float far);
glm::mat4 GetViewMatrix();
@@ -55,7 +58,12 @@ class Camera : public Transform {
protected:
float field_of_view_;
float aspect_ratio_;
float width_;
float height_;
float near_clip_plane_, far_clip_plane_;
bool ortho_;
float orthoScale_;
float orthoCropFactor_;
};
} // namespace tango_gl
#endif // TANGO_GL_CAMERA_H_

View File

@@ -29,7 +29,8 @@ class GestureCamera : public Camera {
kFirstPerson = 0,
kThirdPersonFollow = 1,
kTopDown = 2,
kThirdPerson = 3
kTopOrtho = 3,
kThirdPerson = 4
};
enum TouchEvent {

View File

@@ -122,5 +122,16 @@
android:layout_centerHorizontal="true"
android:paddingLeft="5dp"
android:text="@string/close_visualization" />
<SeekBar
android:id="@+id/seekBar_fov"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:rotation="270"
android:layout_alignParentLeft="true"
android:layout_alignBaseline="@+id/first_person_button"
android:layout_gravity="center"
android:layout_marginLeft="-50dp" />
</RelativeLayout>

View File

@@ -85,6 +85,8 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.NumberPicker;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
@@ -124,6 +126,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;
// UI states
private static enum State {
@@ -173,6 +176,7 @@ public class RTABMapActivity extends Activity implements OnClickListener {
private Button mButtonCloseVisualization;
private Button mButtonSaveOnDevice;
private Button mButtonShareOnSketchfab;
private SeekBar mSeekBarFov;
private String mOpenedDatabasePath = "";
private String mWorkingDirectory = "";
@@ -272,6 +276,32 @@ public class RTABMapActivity extends Activity implements OnClickListener {
{
mButtonBackfaceShown.setVisibility(mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked()?View.VISIBLE:View.INVISIBLE);
}
mSeekBarFov = (SeekBar)findViewById(R.id.seekBar_fov);
mSeekBarFov.setMax(45);
mSeekBarFov.setProgress(20);
mSeekBarFov.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progressValue, boolean fromUser) {
if(mButtonFirst.isChecked())
{
RTABMapLib.setFOV((float)progressValue+45.0f);
}
else if(mButtonTop.isChecked())
{
RTABMapLib.setOrthoCropFactor((float)progressValue/20.0f - 3.0f);
}
resetNoTouchTimer();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
mToast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);
@@ -590,16 +620,38 @@ public class RTABMapActivity extends Activity implements OnClickListener {
}
private void setCamera(int type)
{
{
if(!DISABLE_LOG) Log.i(TAG, String.format("called setCamera(type=%d);", type));
// for convenience, for a refresh of the memory used
mStatusTexts[1] = getString(R.string.memory)+String.valueOf(Debug.getNativeHeapAllocatedSize()/(1024*1024));
mStatusTexts[2] = getString(R.string.free_memory)+String.valueOf(getFreeMemory());
updateStatusTexts();
RTABMapLib.setCamera(type);
mButtonFirst.setChecked(type==0);
mButtonThird.setChecked(type==1);
mButtonTop.setChecked(type==2);
mButtonTop.setChecked(type==2 || type==3);
mButtonTop.setText(type==3?"Ortho":"Top");
mButtonTop.setTextOn(type==3?"Ortho":"Top");
mButtonTop.setTextOff(type==3?"Ortho":"Top");
mSeekBarFov.setVisibility(type!=0 && type!=3?View.INVISIBLE:View.VISIBLE);
if(type==0)
{
mSeekBarFov.setMax(45);
mSeekBarFov.setProgress(20);
}
if(type==3)
{
mSeekBarFov.setMax(120);
mSeekBarFov.setProgress(40);
}
if(type==2 && !mTipOrthoShown_)
{
mToast.makeText(this, "Tip: Click again on Top to set Ortho mode.", mToast.LENGTH_LONG).show();
mTipOrthoShown_ = true;
}
}
@Override
@@ -614,7 +666,7 @@ public class RTABMapActivity extends Activity implements OnClickListener {
setCamera(1);
break;
case R.id.top_down_button:
setCamera(2);
setCamera(mButtonFirst.isChecked() || mButtonThird.isChecked() || mButtonTop.getTextOn().equals("Ortho")?2:3);
break;
case R.id.pause_button:
pauseMapping();
@@ -1256,6 +1308,7 @@ public class RTABMapActivity extends Activity implements OnClickListener {
mButtonThird.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE);
mButtonTop.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE);
mButtonBackfaceShown.setVisibility(mHudVisible && (mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked())?View.VISIBLE:View.INVISIBLE);
mSeekBarFov.setVisibility(mHudVisible && (mButtonFirst.isChecked() || (mButtonTop.isChecked() && mButtonTop.getTextOn().equals("Ortho")))?View.VISIBLE:View.INVISIBLE);
}
private void pauseMapping() {
@@ -2091,7 +2144,7 @@ public class RTABMapActivity extends Activity implements OnClickListener {
}
else
{
mToast.makeText(getActivity(), String.format("Exporting mesh \"%s\" failed! No files found in tmp directory!?", pathHuman), mToast.LENGTH_LONG).show();
mToast.makeText(getActivity(), String.format("Exporting mesh \"%s\" failed! No files found in tmp directory!? Last export may have failed or have been canceled.", pathHuman), mToast.LENGTH_LONG).show();
success = false;
}
}

View File

@@ -77,6 +77,8 @@ public class RTABMapLib
public static native void setMaxCloudDepth(float value);
public static native void setMinCloudDepth(float value);
public static native void setPointSize(float value);
public static native void setFOV(float value);
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 setCloudDensityLevel(int value);