Commit 71959b68 authored by Frédéric Larue's avatar Frédéric Larue
Browse files

Picking function has been improved and is now used to show the label of an...

Picking function has been improved and is now used to show the label of an object in the 3D view when the mouse is over it and SHIFT is pressed.
parent 4db0a184
......@@ -125,6 +125,9 @@ GLViewer::~GLViewer()
void GLViewer::init( DisplayDoF dof )
{
m_BelowCursor = NULL;
m_MustUpdateFocal = false;
m_MustUpdateProjectionMatrix = false;
m_MustUpdateViewMatrix = false;
......@@ -927,6 +930,8 @@ void GLViewer::paintGL()
m_ViewMatrixInverse = m_ViewMatrix.inverted();
m_ViewRotationMatrixInverse = viewRotationMatrix().inverted();
m_MustUpdateViewMatrix = false;
mustUpdateViewProjectionMatrix = true;
}
......@@ -935,6 +940,8 @@ void GLViewer::paintGL()
{
m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
m_ViewProjectionMatrixInverse = m_ViewMatrixInverse * m_ProjectionMatrixInverse;
m_PixelToRayMatrix = viewRotationMatrixInverse() * projectionMatrixInverse();
}
// Setup the OpenGL transforms and viewport.
......@@ -966,11 +973,9 @@ void GLViewer::paintGL()
glPopMatrix();
}
// Finalize the rendering.
releaseScene();
// Display the metric grid.
if( m_IsGridDisplayed )
{
......@@ -981,6 +986,13 @@ void GLViewer::paintGL()
glDepthMask( GL_TRUE );
}
// Display the label of the object under the mouse cursor.
if( dof() == DISPLAY_DOF_3D && m_BelowCursor )
{
QVector3D c = m_BelowCursor->GetTransform().map( m_BelowCursor->boundingBox.Center() );
glColor3ub( 64, 64, 64 );
renderText( c.x(), c.y(), c.z(), m_BelowCursor->displayable->label() );
}
// Display the selection tool, if selection mode is enabled.
if( isSelectionEnabled() )
......@@ -1085,7 +1097,7 @@ void GLViewer::displayLabel( DisplayableInterface *d )
if( fm.height() < bottomLeft.y()-topRight.y()-4 )
{
imgName = d->label();// getSource()->BaseName() + " [" + QString().setNum(m_ImgTexture->width()) + "x" + QString().setNum(m_ImgTexture->height()) + "]";
imgName = d->label();
imgNameWidth = fm.width( imgName );
if( imgNameWidth > topRight.x()-bottomLeft.x()-8 )
......@@ -1482,7 +1494,7 @@ void GLViewer::mousePressEvent( QMouseEvent *evt )
{
PickedPoint p;
if( !isSelectionEnabled() && evt->button() == Qt::RightButton && getPickedPoint( evt->pos().x(), evt->pos().y(), p, true ) )
if( !isSelectionEnabled() && evt->button() == Qt::RightButton && getPickedPoint( evt->pos().x(), height()-evt->pos().y(), p, true ) )
{
QMenu ctxMenu;
ctxMenu.addAction( "Save current render" );
......@@ -1544,9 +1556,45 @@ void GLViewer::mouseReleaseEvent( QMouseEvent *evt )
}
void GLViewer::findObjectUnderCursor( const QPoint& cursor )
{
PickedPoint pp;
if( getPickedPoint( cursor.x(), height()-cursor.y(), pp, true ) )
{
auto disp = &m_Displayables[ pp.srcObject ];
if( disp != m_BelowCursor )
{
m_BelowCursor = disp;
update();
}
}
else if( m_BelowCursor )
{
m_BelowCursor = NULL;
update();
}
}
void GLViewer::clearObjectUnderCursor()
{
if( m_BelowCursor )
{
m_BelowCursor = NULL;
update();
}
}
void GLViewer::mouseMoveEvent( QMouseEvent *evt )
{
if( !isSelectionEnabled() )
if( isSelectionEnabled() )
{
makeCurrent();
m_SelectionCurrentTool->mouseMoveEvent( evt );
update();
}
else if( evt->buttons() != Qt::NoButton )
{
double dx = (evt->pos().x() - m_PrevMousePos.x());
double dy = (evt->pos().y() - m_PrevMousePos.y());
......@@ -1570,13 +1618,8 @@ void GLViewer::mouseMoveEvent( QMouseEvent *evt )
mouseMotionNavigationEvent( dx, dy, evt );
}
else
{
makeCurrent();
m_SelectionCurrentTool->mouseMoveEvent( evt );
}
update();
else if( !isSelectionEnabled() )
findObjectUnderCursor( evt->pos() );
}
......@@ -1678,6 +1721,24 @@ bool GLViewer::event( QEvent *evt )
update();
return true;
}
else if( kevt->key() == Qt::Key_Shift && !isSelectionEnabled() )
{
setMouseTracking( true );
findObjectUnderCursor( mapFromGlobal( cursor().pos() ) );
return true;
}
}
else if( evt->type() == QEvent::KeyRelease )
{
QKeyEvent *kevt = static_cast<QKeyEvent*>( evt );
if( kevt->key() == Qt::Key_Shift && !isSelectionEnabled() )
{
setMouseTracking( false );
clearObjectUnderCursor();
return true;
}
}
return QOpenGLWidget::event( evt );
......@@ -2061,7 +2122,23 @@ bool GLViewer::getPickedPoint( const float x,
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
QVector3D rayOrig = viewpointLocation();
QVector3D rayDir = pixelRay( x, y ).normalized();
DisplayableInfo *closestBoxObject = NULL;
float closestBoxDist = std::numeric_limits<float>::max();
for( DisplayableMap::iterator d=m_Displayables.begin(); d!=m_Displayables.end(); ++d )
{
QMatrix4x4 cameraToBox = d->second.GetTransform().inverted();
QVector3D localRayOrig = cameraToBox.map( rayOrig );
QVector3D localRayDir = cameraToBox.mapVector( rayDir );
QVector3D boxHitPointCoords;
float boxHitPointDist;
if( !d->second.boundingBox.Intersects(localRayOrig,localRayDir,boxHitPointCoords,boxHitPointDist) )
continue;
if( d->second.displayable->isPickable( *d->first->GetDisplayOptions() ) )
{
m_PickingShader.SetUniform( "viewMatrix", (viewMatrix() * d->second.GetTransform()).data() );
......@@ -2073,72 +2150,90 @@ bool GLViewer::getPickedPoint( const float x,
d->second.displayable->onPicking( *d->first->GetDisplayOptions(), m_PickingShader, "vertexPosition" );
}
else if( boxHitPointDist < closestBoxDist )
{
closestBoxObject = &d->second;
closestBoxDist = boxHitPointDist;
}
}
pickingBuffer.Unbind();
// Reads back the content of the buffers.
struct PickingBufferElement
{
QVector3D position;
float depth;
};
PickingBufferElement pickedPointBuffer[ pickingWinArea ];
qint32 pickedObjIdBuffer[ pickingWinArea ];
pickingBuffer.DumpTo( GL_COLOR_ATTACHMENT0, pickedObjIdBuffer, GL_RGBA, GL_UNSIGNED_BYTE, 4 );
pickingBuffer.DumpTo( GL_COLOR_ATTACHMENT1, pickedPointBuffer, GL_RGBA, GL_FLOAT, 8 );
bool pickingFound = false;
// Looks for the buffer pixel that corresponds to the valid point that has the smallest distance to the viewpoint.
int nearestId = -1;
if( closestBoxObject )
{
picked.srcObject = closestBoxObject->displayable->getSource();
picked.position = closestBoxObject->boundingBox.Center();
picked.global = closestBoxObject->GetTransform().map( picked.position );
pickingFound = true;
}
if( accurate )
if( !orderedManageables.empty() )
{
// In order to improve the picking accuracy, the buffer is analysed by looking first at the pixel located at
// the center of the window, and by increasing progressively the search radius .
for( int radius=0, diam=1; radius<=PICKING_WIN_RADIUS; ++radius, diam+=2 )
// Reads back the content of the buffers.
struct PickingBufferElement
{
float nearestDepth = std::numeric_limits<float>::max();
QVector3D position;
float depth;
};
for( int a=0, n=(PICKING_WIN_RADIUS-radius)*(pickingWinDiam+1); a<diam; ++a, n+=pickingWinDiam-diam )
for( int b=0; b<diam; ++b, ++n )
if( pickedObjIdBuffer[n] && pickedPointBuffer[n].depth < nearestDepth )
{
nearestDepth = pickedPointBuffer[n].depth;
nearestId = n;
}
PickingBufferElement pickedPointBuffer[ pickingWinArea ];
qint32 pickedObjIdBuffer[ pickingWinArea ];
if( nearestId >= 0 )
break;
}
}
else
{
float nearestDepth = std::numeric_limits<float>::max();
pickingBuffer.DumpTo( GL_COLOR_ATTACHMENT0, pickedObjIdBuffer, GL_RGBA, GL_UNSIGNED_BYTE, 4 );
pickingBuffer.DumpTo( GL_COLOR_ATTACHMENT1, pickedPointBuffer, GL_RGBA, GL_FLOAT, 8 );
// Looks for the buffer pixel that corresponds to the valid point that has the smallest distance to the viewpoint.
float nearestDepth;
int nearestId = -1;
for( int i=0; i<pickingWinArea; ++i )
if( pickedObjIdBuffer[i] && pickedPointBuffer[i].depth < nearestDepth )
if( accurate )
{
// In order to improve the picking accuracy, the buffer is analysed by looking first at the pixel located at
// the center of the window, and by increasing progressively the search radius .
for( int radius=0, diam=1; radius<=PICKING_WIN_RADIUS; ++radius, diam+=2 )
{
nearestDepth = pickedPointBuffer[i].depth;
nearestId = i;
nearestDepth = std::numeric_limits<float>::max();
for( int a=0, n=(PICKING_WIN_RADIUS-radius)*(pickingWinDiam+1); a<diam; ++a, n+=pickingWinDiam-diam )
for( int b=0; b<diam; ++b, ++n )
if( pickedObjIdBuffer[n] && pickedPointBuffer[n].depth < nearestDepth )
{
nearestDepth = pickedPointBuffer[n].depth;
nearestId = n;
}
if( nearestId >= 0 )
break;
}
}
}
else
{
nearestDepth = std::numeric_limits<float>::max();
for( int i=0; i<pickingWinArea; ++i )
if( pickedObjIdBuffer[i] && pickedPointBuffer[i].depth < nearestDepth )
{
nearestDepth = pickedPointBuffer[i].depth;
nearestId = i;
}
}
// If such a pixel has been found, recover the picked point information.
if( nearestId >= 0 )
{
picked.srcObject = orderedManageables[ pickedObjIdBuffer[nearestId]-1 ];
picked.position = pickedPointBuffer[nearestId].position;
picked.global = m_Displayables[picked.srcObject].GetTransform().map( picked.position );
// If such a pixel has been found, recover the picked point information.
if( nearestId >= 0 && nearestDepth < closestBoxDist )
{
picked.srcObject = orderedManageables[ pickedObjIdBuffer[nearestId]-1 ];
picked.position = pickedPointBuffer[nearestId].position;
picked.global = m_Displayables[picked.srcObject].GetTransform().map( picked.position );
pickingFound = true;
}
}
glPopAttrib();
return nearestId >= 0;
return pickingFound;
}
......@@ -2275,7 +2370,7 @@ void GLViewer::setSelectionEnabled( bool enabled )
m_SelectionEnabled = enabled;
setCursor( enabled? QCursor(Qt::CrossCursor) : QCursor(Qt::ArrowCursor) );
setMouseTracking( enabled );
//setMouseTracking( enabled );
if( enabled )
{
......
......@@ -137,6 +137,8 @@ protected:
GPU::Shader m_ZBufferShader;
GPU::Texture2D m_SelectionDepthBuffer;
DisplayableInfo *m_BelowCursor;
// View related transformations.
bool m_MustUpdateFocal;
......@@ -149,9 +151,11 @@ protected:
bool m_MustUpdateViewMatrix;
QMatrix4x4 m_ViewMatrix;
QMatrix4x4 m_ViewMatrixInverse;
QMatrix4x4 m_ViewRotationMatrixInverse;
QMatrix4x4 m_ViewProjectionMatrix;
QMatrix4x4 m_ViewProjectionMatrixInverse;
QMatrix4x4 m_PixelToRayMatrix;
/*****************************\
| Constructor(s) / destructor |
......@@ -196,6 +200,9 @@ protected:
void manageAnimations();
void findObjectUnderCursor( const QPoint& cursor );
void clearObjectUnderCursor();
public:
void init( DisplayDoF dof );
......@@ -211,7 +218,6 @@ public:
inline const QVector3D& focusPoint() const { return m_FocusPoint; }
inline float distToFocusPoint() const { return m_DistToFocusPoint; }
inline const QMatrix4x4& viewRotationMatrix() const { return m_ViewRotationMatrix; }
inline float fovY() const { return m_FovY; }
inline double focal() const { return m_Focal; }
inline float zNear() const { return m_ZNear; }
......@@ -219,20 +225,32 @@ public:
inline float pointSize() const { return m_PointSize; }
inline DisplayDoF dof() const { return m_DoF; }
const QMatrix4x4& projectionMatrix() const { return m_ProjectionMatrix; }
const QMatrix4x4& projectionMatrixInverse() const { return m_ProjectionMatrixInverse; }
const QMatrix4x4& viewMatrix() const { return m_ViewMatrix; }
const QMatrix4x4& viewMatrixInverse() const { return m_ViewMatrixInverse; }
inline const QMatrix4x4& projectionMatrix() const { return m_ProjectionMatrix; }
inline const QMatrix4x4& projectionMatrixInverse() const { return m_ProjectionMatrixInverse; }
inline const QMatrix4x4& viewMatrix() const { return m_ViewMatrix; }
inline const QMatrix4x4& viewMatrixInverse() const { return m_ViewMatrixInverse; }
inline const QMatrix4x4& viewRotationMatrix() const { return m_ViewRotationMatrix; }
inline const QMatrix4x4& viewRotationMatrixInverse() const { return m_ViewRotationMatrixInverse; }
QMatrix4x4 modelMatrix( const DisplayableInterface *d ) const;
QMatrix4x4 modelMatrixInverse( const DisplayableInterface *d ) const;
const QMatrix4x4& viewProjectionMatrix() const { return m_ViewProjectionMatrix; }
const QMatrix4x4& viewProjectionMatrixInverse() const { return m_ViewProjectionMatrixInverse; }
inline const QMatrix4x4& viewProjectionMatrix() const { return m_ViewProjectionMatrix; }
inline const QMatrix4x4& viewProjectionMatrixInverse() const { return m_ViewProjectionMatrixInverse; }
inline QMatrix4x4 modelViewMatrix( const DisplayableInterface *d ) const { return viewMatrix() * modelMatrix(d); }
inline QMatrix4x4 modelViewMatrixInverse( const DisplayableInterface *d ) const { return modelViewMatrix(d).inverted(); }
inline QMatrix4x4 MVPMatrix( const DisplayableInterface *d ) const { return viewProjectionMatrix() * modelMatrix(d); }
inline QMatrix4x4 MVPMatrixInverse( const DisplayableInterface *d ) const { return MVPMatrix(d).inverted(); }
inline QVector3D viewpointLocation() const
{
QMatrix4x4 R = viewMatrix();
return R.transposed().mapVector( -R.column(3).toVector3D() );
}
inline QVector3D pixelRay( int px, int py ) const
{
QVector4D clipCoord( 2.0f*px/width() - 1.0f, 2.0f*py/height() - 1.0f, 0.0f, 1.0f );
return m_PixelToRayMatrix.map( clipCoord ).toVector3D();
}
QMatrix4x4 viewportMatrix( bool flipY = false ) const;
inline QMatrix4x4 normalMatrix( const DisplayableInterface *d ) const { QMatrix4x4 m = modelViewMatrix(d); m(0,3) = m(1,3) = m(2,3) = 0.0f; return m; }
inline const QMatrix4x4& lightRotationMatrix() const { return m_LightRotationMatrix; }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment