mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-06 00:07:29 -04:00
Refactor 3D globe panning logic
Instead of raycasting based on a previously-captured depth buffer, which only works well for featureless scenes, construct a virtual sphere and intersect the mouse pointer's ray with that.
This commit is contained in:
parent
f5d4c39334
commit
8f33234255
@ -678,17 +678,30 @@ void QgsCameraController::onPositionChangedGlobeTerrainNavigation( Qt3DInput::QM
|
|||||||
mDragPointCalculated = true;
|
mDragPointCalculated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QgsVector3D mapPressPos = QgsVector3D( mDragPoint ) + mOrigin;
|
const QgsVector3D mapStartPos = QgsVector3D( mDragPoint ) + mOrigin;
|
||||||
|
// Approximate the globe as a sphere with a center in mOrigin and of radius
|
||||||
double newDepth = sampleDepthBuffer( mouse->x(), mouse->y() );
|
// the same as at mapStartPos.
|
||||||
if ( newDepth == 1 )
|
const double sphereRadius = mapStartPos.length();
|
||||||
return; // the mouse is somewhere in the void...
|
// Find the intersection of this sphere and the ray from the current clicked point.
|
||||||
|
const QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mouse->x(), mouse->y() ), mScene->engine()->size(), mCameraBefore.get() );
|
||||||
const QVector3D newWorldPosition = Qgs3DUtils::screenPointToWorldPos( QPoint( mouse->x(), mouse->y() ), newDepth, mScene->engine()->size(), mDepthBufferCamera.get() );
|
const QgsVector3D rayOriginShifted = QgsVector3D( ray.origin() ) + mOrigin;
|
||||||
if ( !std::isfinite( newWorldPosition.x() ) || !std::isfinite( newWorldPosition.y() ) || !std::isfinite( newWorldPosition.z() ) )
|
// From equations of ray and sphere
|
||||||
|
const double quadA = QVector3D::dotProduct( ray.direction(), ray.direction() );
|
||||||
|
const double quadB = 2 * QgsVector3D::dotProduct( ray.direction(), rayOriginShifted );
|
||||||
|
const double quadC = QgsVector3D::dotProduct( rayOriginShifted, rayOriginShifted ) - sphereRadius * sphereRadius;
|
||||||
|
const double disc = quadB * quadB - 4 * quadA * quadC;
|
||||||
|
if ( disc < 0 )
|
||||||
|
// Ray misses sphere
|
||||||
return;
|
return;
|
||||||
|
// Distance to intersection along ray (take smaller root, closer to camera)
|
||||||
const QgsVector3D newMapPos = QgsVector3D( newWorldPosition ) + mOrigin;
|
const double rayDist = ( -quadB - sqrt( disc ) ) / ( 2 * quadA );
|
||||||
|
if ( rayDist < 0 )
|
||||||
|
{
|
||||||
|
QgsDebugError( QStringLiteral( "Sphere intersection result negative, cancelling move" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QVector3D sphereIntersection = ray.origin() + ( float ) rayDist * ray.direction();
|
||||||
|
const QgsVector3D newMapPos = QgsVector3D( sphereIntersection ) + mOrigin;
|
||||||
|
|
||||||
// now that we have old and new mouse position in ECEF coordinates,
|
// now that we have old and new mouse position in ECEF coordinates,
|
||||||
// let's figure out the difference in lat/lon angles and update the center point
|
// let's figure out the difference in lat/lon angles and update the center point
|
||||||
@ -696,7 +709,7 @@ void QgsCameraController::onPositionChangedGlobeTerrainNavigation( Qt3DInput::QM
|
|||||||
QgsVector3D oldLatLon, newLatLon;
|
QgsVector3D oldLatLon, newLatLon;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
oldLatLon = mGlobeCrsToLatLon.transform( mapPressPos );
|
oldLatLon = mGlobeCrsToLatLon.transform( mapStartPos );
|
||||||
newLatLon = mGlobeCrsToLatLon.transform( newMapPos );
|
newLatLon = mGlobeCrsToLatLon.transform( newMapPos );
|
||||||
}
|
}
|
||||||
catch ( const QgsCsException & )
|
catch ( const QgsCsException & )
|
||||||
@ -710,6 +723,7 @@ void QgsCameraController::onPositionChangedGlobeTerrainNavigation( Qt3DInput::QM
|
|||||||
|
|
||||||
const QgsVector3D newVC = moveGeocentricPoint( mMousePressViewCenter, latDiff, lonDiff );
|
const QgsVector3D newVC = moveGeocentricPoint( mMousePressViewCenter, latDiff, lonDiff );
|
||||||
const QgsVector3D newVCWorld = newVC - mOrigin;
|
const QgsVector3D newVCWorld = newVC - mOrigin;
|
||||||
|
|
||||||
mCameraPose.setCenterPoint( newVCWorld );
|
mCameraPose.setCenterPoint( newVCWorld );
|
||||||
updateCameraFromPose();
|
updateCameraFromPose();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user