From efe803e006c4360a002684a7cf3215e1bad2e1d8 Mon Sep 17 00:00:00 2001 From: Jean Felder Date: Sun, 27 Oct 2024 09:37:57 +0100 Subject: [PATCH] qgs3dmapscene: Compute max clip planes The number of available clip planes depends on the OpenGL implementation. This change Introduces a new function in Qgs3DUtils function called `Qgs3DUtils::getOpenGLMaxClipPlanes` to compute this number (`GL_MAX_CLIP_PLANES`) and use it in the 3D scene. See: https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glClipPlane.xml --- python/3d/auto_generated/qgs3dmapscene.sip.in | 6 ++--- .../3d/auto_generated/qgs3dmapscene.sip.in | 6 ++--- src/3d/qgs3dmapscene.cpp | 9 ++++--- src/3d/qgs3dmapscene.h | 7 ++--- src/3d/qgs3dutils.cpp | 26 +++++++++++++++++++ src/3d/qgs3dutils.h | 8 ++++++ src/3d/shaders/clipplane.shaderinc | 2 +- 7 files changed, 51 insertions(+), 13 deletions(-) diff --git a/python/3d/auto_generated/qgs3dmapscene.sip.in b/python/3d/auto_generated/qgs3dmapscene.sip.in index 410b442120b6..7ef7b12981af 100644 --- a/python/3d/auto_generated/qgs3dmapscene.sip.in +++ b/python/3d/auto_generated/qgs3dmapscene.sip.in @@ -160,9 +160,9 @@ In mathematical terms, a 3d plane can be defined with the equation ``ax+by+cz+d= The normal is ``(a, b, c)`` with ``|a, b, c| = 1`` The distance is ``-d``. -By default, OpenGL supports up to 8 additional clipping planes. If ``clipPlaneEquations`` -contains more than 8 planes, only the first 8 ones will be used. -If ``clipPlaneEquations`` is empty, the clipping is disabled. +The number of available clip planes depends on the OpenGL implementation. It should at least handle +6 additional clip planes. When the map scene is created, this number is retrieved. +If, ``clipPlaneEquations`` contains more than this maximum, only the first ones will be kept. .. seealso:: :py:func:`disableClipping` diff --git a/python/PyQt6/3d/auto_generated/qgs3dmapscene.sip.in b/python/PyQt6/3d/auto_generated/qgs3dmapscene.sip.in index c3209dc6d09b..cb201b90db72 100644 --- a/python/PyQt6/3d/auto_generated/qgs3dmapscene.sip.in +++ b/python/PyQt6/3d/auto_generated/qgs3dmapscene.sip.in @@ -160,9 +160,9 @@ In mathematical terms, a 3d plane can be defined with the equation ``ax+by+cz+d= The normal is ``(a, b, c)`` with ``|a, b, c| = 1`` The distance is ``-d``. -By default, OpenGL supports up to 8 additional clipping planes. If ``clipPlaneEquations`` -contains more than 8 planes, only the first 8 ones will be used. -If ``clipPlaneEquations`` is empty, the clipping is disabled. +The number of available clip planes depends on the OpenGL implementation. It should at least handle +6 additional clip planes. When the map scene is created, this number is retrieved. +If, ``clipPlaneEquations`` contains more than this maximum, only the first ones will be kept. .. seealso:: :py:func:`disableClipping` diff --git a/src/3d/qgs3dmapscene.cpp b/src/3d/qgs3dmapscene.cpp index f30b32165eb9..78d6856df4e4 100644 --- a/src/3d/qgs3dmapscene.cpp +++ b/src/3d/qgs3dmapscene.cpp @@ -99,6 +99,9 @@ Qgs3DMapScene::Qgs3DMapScene( Qgs3DMapSettings &map, QgsAbstract3DEngine *engine QRect viewportRect( QPoint( 0, 0 ), mEngine->size() ); + // Get the maximum of clip planes available + mMaxClipPlanes = Qgs3DUtils::getOpenGLMaxClipPlanes(); + // Camera float aspectRatio = ( float )viewportRect.width() / viewportRect.height(); mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f ); @@ -1223,11 +1226,11 @@ void Qgs3DMapScene::handleClippingOnAllEntities() const void Qgs3DMapScene::enableClipping( const QList &clipPlaneEquations ) { - if ( clipPlaneEquations.size() > 8 ) + if ( clipPlaneEquations.size() > mMaxClipPlanes ) { - QgsDebugMsgLevel( QStringLiteral( "Qgs3DMapScene::enableClipping: it is not possible to use more than 8 clipping planes." ), 2 ); + QgsDebugMsgLevel( QStringLiteral( "Qgs3DMapScene::enableClipping: it is not possible to use more than %s clipping planes." ).arg( QString::number( mMaxClipPlanes ) ), 2 ); } - mClipPlanesEquations = clipPlaneEquations.mid( 0, 8 ); + mClipPlanesEquations = clipPlaneEquations.mid( 0, mMaxClipPlanes ); // enable the clip planes on the framegraph QgsFrameGraph *frameGraph = mEngine->frameGraph(); diff --git a/src/3d/qgs3dmapscene.h b/src/3d/qgs3dmapscene.h index 3a880f59d87c..17dde40ef692 100644 --- a/src/3d/qgs3dmapscene.h +++ b/src/3d/qgs3dmapscene.h @@ -227,9 +227,9 @@ class _3D_EXPORT Qgs3DMapScene : public QObject * The normal is ``(a, b, c)`` with ``|a, b, c| = 1`` * The distance is ``-d``. * - * By default, OpenGL supports up to 8 additional clipping planes. If \a clipPlaneEquations - * contains more than 8 planes, only the first 8 ones will be used. - * If \a clipPlaneEquations is empty, the clipping is disabled. + * The number of available clip planes depends on the OpenGL implementation. It should at least handle + * 6 additional clip planes. When the map scene is created, this number is retrieved. + * If, \a clipPlaneEquations contains more than this maximum, only the first ones will be kept. * * \see disableClipping() * \since QGIS 3.40 @@ -357,6 +357,7 @@ class _3D_EXPORT Qgs3DMapScene : public QObject bool mSceneUpdatesEnabled = true; QList mClipPlanesEquations; + int mMaxClipPlanes; }; #endif // QGS3DMAPSCENE_H diff --git a/src/3d/qgs3dutils.cpp b/src/3d/qgs3dutils.cpp index bbad2c8e1657..86572f7cb7c8 100644 --- a/src/3d/qgs3dutils.cpp +++ b/src/3d/qgs3dutils.cpp @@ -42,6 +42,10 @@ #include #include #include +#include +#include +#include + #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include @@ -952,3 +956,25 @@ QByteArray Qgs3DUtils::removeDefinesFromShaderCode( const QByteArray &shaderCode return newShaderCode; } + +int Qgs3DUtils::getOpenGLMaxClipPlanes() +{ + int nrPlanes = 0; + + QOffscreenSurface offscreen; + QOpenGLContext context; + + offscreen.setFormat( QSurfaceFormat::defaultFormat() ); + offscreen.create(); + Q_ASSERT_X( offscreen.isValid(), Q_FUNC_INFO, "Unable to create offscreen surface to gather capabilities" ); + + context.setFormat( QSurfaceFormat::defaultFormat() ); + if ( context.create() ) + { + context.makeCurrent( &offscreen ); + auto funcs = context.functions(); + funcs->glGetIntegerv( GL_MAX_CLIP_PLANES, &nrPlanes ); + } + + return nrPlanes; +} diff --git a/src/3d/qgs3dutils.h b/src/3d/qgs3dutils.h index ae0f8cf04aad..d901789125bd 100644 --- a/src/3d/qgs3dutils.h +++ b/src/3d/qgs3dutils.h @@ -331,6 +331,14 @@ class _3D_EXPORT Qgs3DUtils * \since QGIS 3.40 */ static QByteArray removeDefinesFromShaderCode( const QByteArray &shaderCode, const QStringList &defines ); + + /** + * Gets the maximum number of clip planes that can be used. + * This value depends on the OpenGL implementation. It should be at least 6. + * + * \since QGIS 3.42 + */ + static int getOpenGLMaxClipPlanes(); }; #endif // QGS3DUTILS_H diff --git a/src/3d/shaders/clipplane.shaderinc b/src/3d/shaders/clipplane.shaderinc index a3bc8e35b1b0..6c21c2f4c371 100644 --- a/src/3d/shaders/clipplane.shaderinc +++ b/src/3d/shaders/clipplane.shaderinc @@ -1,4 +1,4 @@ -const int MAX_PLANE = 8; +const int MAX_PLANE = 32; uniform int max_plane_real; uniform vec4 clipPlane[MAX_PLANE];