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;
|
||||
}
|
||||
|
||||
const QgsVector3D mapPressPos = QgsVector3D( mDragPoint ) + mOrigin;
|
||||
|
||||
double newDepth = sampleDepthBuffer( mouse->x(), mouse->y() );
|
||||
if ( newDepth == 1 )
|
||||
return; // the mouse is somewhere in the void...
|
||||
|
||||
const QVector3D newWorldPosition = Qgs3DUtils::screenPointToWorldPos( QPoint( mouse->x(), mouse->y() ), newDepth, mScene->engine()->size(), mDepthBufferCamera.get() );
|
||||
if ( !std::isfinite( newWorldPosition.x() ) || !std::isfinite( newWorldPosition.y() ) || !std::isfinite( newWorldPosition.z() ) )
|
||||
const QgsVector3D mapStartPos = QgsVector3D( mDragPoint ) + mOrigin;
|
||||
// Approximate the globe as a sphere with a center in mOrigin and of radius
|
||||
// the same as at mapStartPos.
|
||||
const double sphereRadius = mapStartPos.length();
|
||||
// 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 QgsVector3D rayOriginShifted = QgsVector3D( ray.origin() ) + mOrigin;
|
||||
// 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;
|
||||
|
||||
const QgsVector3D newMapPos = QgsVector3D( newWorldPosition ) + mOrigin;
|
||||
// Distance to intersection along ray (take smaller root, closer to camera)
|
||||
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,
|
||||
// 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;
|
||||
try
|
||||
{
|
||||
oldLatLon = mGlobeCrsToLatLon.transform( mapPressPos );
|
||||
oldLatLon = mGlobeCrsToLatLon.transform( mapStartPos );
|
||||
newLatLon = mGlobeCrsToLatLon.transform( newMapPos );
|
||||
}
|
||||
catch ( const QgsCsException & )
|
||||
@ -710,6 +723,7 @@ void QgsCameraController::onPositionChangedGlobeTerrainNavigation( Qt3DInput::QM
|
||||
|
||||
const QgsVector3D newVC = moveGeocentricPoint( mMousePressViewCenter, latDiff, lonDiff );
|
||||
const QgsVector3D newVCWorld = newVC - mOrigin;
|
||||
|
||||
mCameraPose.setCenterPoint( newVCWorld );
|
||||
updateCameraFromPose();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user