From 5d9977c1d4a3724ebccfe85580f405517023d8d6 Mon Sep 17 00:00:00 2001 From: Michele Sottile sottile Date: Wed, 5 May 2010 15:27:08 +0000 Subject: [PATCH] Shot2Trackball trasformation with gluLookAt compensation. Fixed bug in getShotFromTrack2 (negative sign) --- src/meshlab_20/glarea.cpp | 123 ++++++++++++++++++++- src/meshlab_20/glarea.h | 147 +++++++++++++++++++++++++- src/meshlab_20/images/camera.png | Bin 0 -> 22474 bytes src/meshlab_20/mainwindow.h | 3 + src/meshlab_20/mainwindow_Init.cpp | 15 ++- src/meshlab_20/mainwindow_RunTime.cpp | 2 + src/meshlab_20/meshlab.qrc | 1 + 7 files changed, 284 insertions(+), 7 deletions(-) create mode 100644 src/meshlab_20/images/camera.png diff --git a/src/meshlab_20/glarea.cpp b/src/meshlab_20/glarea.cpp index 14e17e071..6333e8397 100644 --- a/src/meshlab_20/glarea.cpp +++ b/src/meshlab_20/glarea.cpp @@ -258,18 +258,18 @@ void GLArea::paintGL() setView(); // Set Modelview and Projection matrix drawGradient(); // draws the background - drawLight(); + drawLight(); glPushMatrix(); // Finally apply the Trackball for the model trackball.GetView(); - trackball.Apply(false); + trackball.Apply(false); glPushMatrix(); //glScale(d); - // glTranslate(-FullBBox.Center()); - setLightModel(); + //glTranslate(-FullBBox.Center()); + setLightModel(); // Set proper colorMode if(rm.colorMode != GLW::CMNone) @@ -680,6 +680,16 @@ void GLArea::mouseReleaseEvent(QMouseEvent*e) update(); if(isCurrent()) mvc->updateReleaseViewers(e); + + //TestShot + Shot shot1; initializeShot(shot1); + Shot shot2; initializeShot(shot2); + shot1.Extrinsics.SetTra(Point3(0,0,10)); + shot2.Extrinsics.SetTra(Point3(0,0,10)); + + shot1 = getShotFromTrack(shot1,&trackball); + shot2 = getShotFromTrack2(shot2, &trackball); + } //Processing of tablet events, interesting only for painting plugins @@ -1022,3 +1032,108 @@ void GLArea::initGlobalParameterSet( RichParameterSet * defaultGlobalParamSet) GLAreaSetting::initGlobalParameterSet(defaultGlobalParamSet); } + +void GLArea::initializeShot(Shot &shot) +{ + + //Da vedere + shot.Intrinsics.PixelSizeMm[0]=0.036916077; + shot.Intrinsics.PixelSizeMm[1]=0.036916077; + + shot.Intrinsics.FocalMm= 27.846098; //per avere circa 60 gradi + shot.Intrinsics.DistorCenterPx[0]=width()/2; + shot.Intrinsics.DistorCenterPx[1]=height()/2; + shot.Intrinsics.CenterPx[0]=width()/2; + shot.Intrinsics.CenterPx[1]=height()/2; + shot.Intrinsics.ViewportPx[0]=width(); + shot.Intrinsics.ViewportPx[1]=height(); + + shot.Extrinsics.SetIdentity(); + + //Shot newshot; + //vcg::Box3 box; + //box.Import(meshDoc->bbox()); + //newshot.Extrinsics.SetIdentity(); + //vcg::Point3d c = box.Center(); + //vcg::Point3d v = c - vcg::Point3d(0, 0, 3*box.Diag()); + //newshot.SetViewPoint(v); + //newshot.LookAt(c, vcg::Point3d(0, 1, 0)); + + + //vcg::Camera &cam = shot.Intrinsics; + //double dx = cam.ViewportPx[0]*cam.PixelSizeMm[0]; + + ////if we have the focal we compute the angle (and viceversa) + //cout << "Focal: " << cam.FocalMm << endl; + //cout << "dx: " << dx << endl; + //double angle = 60.0; + //if(dx != 0 && cam.FocalMm != 0) { //we have the focal + // angle = atan(dx/cam.FocalMm)*180.0f/M_PI; + //} else if(dx != 0) { + // cam.FocalMm = dx/tan(angle*M_PI/180.0f); + //} else { + // cam.FocalMm = 60; + //} + + //cout << "Angle: " << angle << endl; + //cout << "Focal: " << cam.FocalMm << endl; + //cout << endl; + + //newshot.Intrinsics.SetPerspective(angle/2, width()/(double)height(), cam.FocalMm, vcg::Point2(width(), height())); + //vcg::Camera &cam1 = newshot.Intrinsics; + //double dx1 = cam.ViewportPx[0]*cam1.PixelSizeMm[0]; + //cout << "Dx now: " << dx1 << " fcal: " << newshot.Intrinsics.FocalMm << endl; + //return newshot; +} + +void GLArea::loadShot(){ + //Shot test + Shot shot; + initializeShot(shot); + //oppure lo leggi da file + + double viewportYMm=shot.Intrinsics.PixelSizeMm[1]*shot.Intrinsics.ViewportPx[1]; + fov = 2*(vcg::math::ToDeg(atanf(viewportYMm/(2*shot.Intrinsics.FocalMm)))); + /*fov=60; + float focal = viewportYMm/(2*tanf(vcg::math::ToRad(fov/2)));*/ + + // This parameter is the one that controls: + // HOW LARGE IS THE TRACKBALL ICON ON THE SCREEN. + float viewRatio = 1.75f; + float cameraDist = viewRatio / tanf(vcg::math::ToRad(fov*.5f)); + + //Esempi di shot di ingresso + //shot.Extrinsics.SetTra(Point3d(0, 0, cameraDist)); + vcg::Matrix44d rot; + rot.Identity(); + rot.SetRotateDeg(90,Point3(0,1,0)); + shot.Extrinsics.SetRot(rot); + shot.Extrinsics.SetTra(Inverse(rot)*Point3d(0, 0, cameraDist)); + + //correct the traslation introduced by gluLookAt() (0,0,cameraDist)--------------------------------------- + //T(gl) S R T(t) => S R T(S^(-1) R^(-1)(gl) + t) + //Shot doesn't introduce scaling + //To compensate S^(-1) R^(-1)(gl)we add to t S^(-1) R^(-1)(-gl) + shot.Extrinsics.SetTra(shot.Extrinsics.Tra() + (Inverse(shot.Extrinsics.Rot())*Point3d(0, 0, -cameraDist))); + + //reset trackball. The point of view must be set only by the shot + trackball.Reset(); + float newScale= 3.0f/meshDoc->bbox().Diag(); + trackball.track.sca = newScale; + trackball.track.tra = -meshDoc->bbox().Center(); + + Shot2Track(shot, cameraDist,trackball); + + //Test on trackball + /*Matrix44f s_inv = Matrix44f().SetScale(1/trackball.track.sca, 1/trackball.track.sca, 1/trackball.track.sca); + vcg::Matrix44f rot_inv; + Inverse(trackball.track.rot).ToMatrix(rot_inv); + + Shot2Track(shot, cameraDist,trackball); + + trackball.track.tra += s_inv*rot_inv*Point3f(0, 0, cameraDist);*/ + + //Shot2Track(shot, cameraDist,trackball); + + updateGL(); +} diff --git a/src/meshlab_20/glarea.h b/src/meshlab_20/glarea.h index b7a4bd24b..94918b705 100644 --- a/src/meshlab_20/glarea.h +++ b/src/meshlab_20/glarea.h @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "../common/interfaces.h" #include "../common/filterscript.h" @@ -42,6 +44,9 @@ #include "viewer.h" #include "multiViewer_Container.h" +//mathematics +#include + #define SSHOT_BYTES_PER_PIXEL 4 enum LightingModel{LDOUBLE,LFANCY}; @@ -69,6 +74,8 @@ class GLArea : public QGLWidget, public Viewer { Q_OBJECT + typedef vcg::Shot Shot; + public: GLArea(QWidget *parent, MultiViewer_Container *mvcont, RichParameterSet *current, int id, MeshDocument *meshDoc); ~GLArea(); @@ -127,6 +134,7 @@ public: void setLightModel(); void setView(); void resetTrackBall(); + void loadShot(); std::list iDecoratorsList; void setRenderer(MeshRenderInterface *rend, QAction *shader){ iRenderer = rend; currentShader = shader;} @@ -309,7 +317,144 @@ private: int tileCol, tileRow, totalCols, totalRows; void setCursorTrack(vcg::TrackMode *tm); - + void initializeShot(Shot &shot); + + /* + Given a shot "refCamera" and a trackball "track", computes a new shot which is equivalent + to apply "refCamera" o "track". + */ + template + vcg::Shot getShotFromTrack(vcg::Shot &refCamera, vcg::Trackball *track){ + vcg::Shot view; + + double _near, _far; + _near = 0.1; + _far = 100; + + //get OpenGL modelview matrix after applying the trackball + GlShot >::SetView(refCamera, _near, _far); + glPushMatrix(); + track->GetView(); + track->Apply(); + vcg::Matrix44d model; + glGetv(GL_MODELVIEW_MATRIX, model); + glPopMatrix(); + GlShot >::UnsetView(); + + //get translation out of modelview + vcg::Point3d tra; + tra[0] = model[0][3]; tra[1] = model[1][3]; tra[2] = model[2][3]; + model[0][3] = model[1][3] = model[2][3] = 0; + + //get pure rotation out of modelview + double det = model.Determinant(); + double idet = 1/pow(det, 1/3.0); //inverse of the determinant + model *= idet; + model[3][3] = 1; + view.Extrinsics.SetRot(model); + + //get pure translation out of modelview + vcg::Matrix44d imodel = model; + vcg::Transpose(imodel); + tra = -(imodel*tra); + tra *= idet; + view.Extrinsics.SetTra(vcg::Point3::Construct(tra)); + + //use same current intrinsics + view.Intrinsics = refCamera.Intrinsics; + + return view; + } + + /* + Given a shot "refCamera" and a trackball "track", computes a new shot which is equivalent + to apply "refCamera" o "track". + */ + template + vcg::Shot getShotFromTrack2(vcg::Shot &refCamera, vcg::Trackball *track){ + vcg::Shot view; + + double _near, _far; + _near = 0.1; + _far = 100; + + //---------------------- ALTERED-------------------- + + // //get OpenGL modelview matrix after applying the trackball + // GlShot >::SetView(refCamera, _near, _far); + // glPushMatrix(); + // track->GetView(); + // track->Apply(); + // vcg::Matrix44d model; + // glGetv(GL_MODELVIEW_MATRIX, model); + // glPopMatrix(); + // GlShot >::UnsetView(); + + //GlShot >::SetView(refCamera, _near, _far); //mi serve per la proj di refcamera... altrimenti come la ottengo? + vcg::Matrix44f shotExtr; + refCamera.GetWorldToExtrinsicsMatrix().ToMatrix(shotExtr); + + ////legge la matrice di proj settata prima + //vcg::Matrix44f proj; + //glGetv(GL_PROJECTION_MATRIX,proj); + //GlShot >::UnsetView(); + + ////aggiorna la matrice di rototraslazione di track + //int viewport[] = {0,0,width(),height()}; + //track->camera.SetView(proj.V(),shotExtr.V(), viewport); + + vcg::Matrix44f model2; + model2 = (shotExtr)* track->Matrix(); + vcg::Matrix44d model; + model2.ToMatrix(model); + + //---------------------- ORIGINAL-------------------- + + //get translation out of modelview + vcg::Point3d tra; + tra[0] = model[0][3]; tra[1] = model[1][3]; tra[2] = model[2][3]; + model[0][3] = model[1][3] = model[2][3] = 0; + + //get pure rotation out of modelview + double det = model.Determinant(); + double idet = 1/pow(det, 1/3.0); //inverse of the determinant + model *= idet; + model[3][3] = 1; + view.Extrinsics.SetRot(model); + + //get pure translation out of modelview + vcg::Matrix44d imodel = model; + vcg::Transpose(imodel); + tra = -(imodel*tra); + tra *= idet; + view.Extrinsics.SetTra(vcg::Point3::Construct(tra)); + + //use same current intrinsics + view.Intrinsics = refCamera.Intrinsics; + + return view; + } + + /* + Given a Shot "from", and a trackball "tb" replaces "tb" with a trackball "tb'" such that: + "from" o "tb" = "tb'" + */ + template + void Shot2Track(const vcg::Shot &from, const float cameraDist, vcg::Trackball &tb){ + + Shot id; + + vcg::Quaterniond qto; qto.FromMatrix(id.Extrinsics.Rot()); + vcg::Quaterniond qfrom; qfrom.FromMatrix(from.Extrinsics.Rot()); + + /*float sca=tb.track.sca; + tb.track.sca=1;*/ + tb.track.tra += ( tb.track.rot.Inverse().Rotate( vcg::Point3f::Construct(-from.Extrinsics.Tra()) + tb.center ) ) / tb.track.sca; + tb.track.rot = vcg::Quaternionf::Construct(qto.Inverse() * qfrom) * tb.track.rot; + tb.track.tra -= ( tb.track.rot.Inverse().Rotate( vcg::Point3f::Construct(- id.Extrinsics.Tra()) + tb.center ) ) / tb.track.sca; + + //aggiustare sca e tra per mettere il centro della trackbal al punto giusto + } }; diff --git a/src/meshlab_20/images/camera.png b/src/meshlab_20/images/camera.png new file mode 100644 index 0000000000000000000000000000000000000000..1568c7938c7c5c791346cd529af40d476639cd5d GIT binary patch literal 22474 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 literal 0 HcmV?d00001 diff --git a/src/meshlab_20/mainwindow.h b/src/meshlab_20/mainwindow.h index 47ef96b87..ed5f01063 100644 --- a/src/meshlab_20/mainwindow.h +++ b/src/meshlab_20/mainwindow.h @@ -110,6 +110,7 @@ private slots: void toggleBackFaceCulling(); void toggleSelectFaceRendering(); void toggleSelectVertRendering(); + void loadShot(); //void applyDecorateMode(); ///////////Slot Menu View //////////////////////// void fullScreen(); @@ -296,6 +297,8 @@ private: QAction *colorModePerMeshAct; QAction *colorModePerVertexAct; QAction *colorModePerFaceAct; + + QAction *loadShotAct; ///////////Actions Menu View //////////////////////// QAction *fullScreenAct; QAction *showToolbarStandardAct; diff --git a/src/meshlab_20/mainwindow_Init.cpp b/src/meshlab_20/mainwindow_Init.cpp index 57685be2a..fcbcf21fc 100644 --- a/src/meshlab_20/mainwindow_Init.cpp +++ b/src/meshlab_20/mainwindow_Init.cpp @@ -205,6 +205,12 @@ void MainWindow::createActions() setSelectVertRenderingAct->setShortcutContext(Qt::ApplicationShortcut); connect(setSelectVertRenderingAct, SIGNAL(triggered()), this, SLOT(toggleSelectVertRendering())); + loadShotAct = new QAction(QIcon(":/images/camera.png"),tr("Load Shot"),this); + loadShotAct->setCheckable(false); + loadShotAct->setShortcutContext(Qt::ApplicationShortcut); + loadShotAct->setShortcut(Qt::CTRL+Qt::Key_W); + connect(loadShotAct, SIGNAL(triggered()), this, SLOT(loadShot())); + //////////////Action Menu View //////////////////////////////////////////////////////////////////////////// fullScreenAct = new QAction (tr("&FullScreen"), this); fullScreenAct->setCheckable(true); @@ -324,8 +330,10 @@ void MainWindow::createToolBars() renderToolBar->addActions(renderModeGroupAct->actions()); renderToolBar->addAction(renderModeTextureAct); renderToolBar->addAction(setLightAct); - renderToolBar->addAction(setSelectFaceRenderingAct); - renderToolBar->addAction(setSelectVertRenderingAct); + renderToolBar->addAction(setSelectFaceRenderingAct); + renderToolBar->addAction(setSelectVertRenderingAct); + + renderToolBar->addAction(loadShotAct); /*editToolBar = addToolBar(tr("Edit")); editToolBar->addAction(suspendEditModeAct); @@ -439,6 +447,9 @@ void MainWindow::createMenus() renderMenu->addSeparator(); + //Shot SUBmenu + renderMenu ->addAction(loadShotAct); + //////////////////// Menu View //////////////////////////////////////////////////////////////////////////// viewMenu = menuBar()->addMenu(tr("&View")); viewMenu->addAction(fullScreenAct); diff --git a/src/meshlab_20/mainwindow_RunTime.cpp b/src/meshlab_20/mainwindow_RunTime.cpp index bfe1f1ff4..4a9216d54 100644 --- a/src/meshlab_20/mainwindow_RunTime.cpp +++ b/src/meshlab_20/mainwindow_RunTime.cpp @@ -1172,6 +1172,8 @@ void MainWindow::setUnsplit() updateMenus(); } +void MainWindow::loadShot() { GLA()->loadShot(); } + void MainWindow::renderBbox() { GLA()->setDrawMode(GLW::DMBox ); } void MainWindow::renderPoint() { GLA()->setDrawMode(GLW::DMPoints ); } void MainWindow::renderWire() { GLA()->setDrawMode(GLW::DMWire ); } diff --git a/src/meshlab_20/meshlab.qrc b/src/meshlab_20/meshlab.qrc index 42d21341e..9db1fd6f8 100644 --- a/src/meshlab_20/meshlab.qrc +++ b/src/meshlab_20/meshlab.qrc @@ -2,6 +2,7 @@ images/backlines.png images/bbox.png + images/camera.png images/cursors/plain.png images/cursors/plain_pan.png images/cursors/plain_trackball.png