Skip to content

Commit

Permalink
[3D] [Feature] Shadow rendering (#38448)
Browse files Browse the repository at this point in the history
* Initial post processing render pass implementation

* Got shadows with directional lights working good enough

* Make the shadows more configurable

* Trying to reduce peter panning

* Add licence

* banned banned_keywords_check

* trying to remove renderStateSet memory leak

* removing include <Qt3DExtras>

* Add documentation

* remove the use of setFilterMode when using QFilterLayer

* Fixing docs

* Fix shadow rendering checkbox

* Added y coordinates for view extent

* Added shadow bias parameter

* Added shadow map texture resolution parameter

* Addressing reviews

* Set the shadow rendering parameters automatically

* Add QLayer components individually if QT_VERSION < QT_5_10

* Hide depth texture preview quad

* Remove unused member

* Fix spell check

* Remove stepType property from shadowBiasSpinBox

* Disable shadow render pass if the shadow rendering is not activated

* Clarify maximum shadow rendering distance documentation

* Add value range for shadow bias

* Delete .bom file

* Clarify the usefullness of maximum shadow rendering distance

* remove unused stuff in shaders

* Make the inverted camera matrices passed as parameters

* Move post processing shaders parameters into the post processing entity constructor

* refactor how shadow rendering update into 1 function

* Fix spelling

* Fix Save As Image tool

* Improve UI according to suggessions

* add missing docs

* remove QAbstractSpinBox::DefaultStepType
  • Loading branch information
NEDJIMAbelgacem committed Sep 10, 2020
1 parent 509c5e1 commit 85e444e
Show file tree
Hide file tree
Showing 33 changed files with 1,764 additions and 162 deletions.
9 changes: 9 additions & 0 deletions python/3d/auto_generated/qgs3dmapsettings.sip.in
Expand Up @@ -477,6 +477,8 @@ Default value is 96





bool isSkyboxEnabled() const;
%Docstring
Returns whether the skybox is enabled.
Expand Down Expand Up @@ -624,6 +626,13 @@ Emitted when the camera lens field of view changes
%Docstring
Emitted when skybox settings are changed

.. versionadded:: 3.16
%End

void shadowSettingsChanged();
%Docstring
Emitted when shadow rendering settings are changed

.. versionadded:: 3.16
%End

Expand Down
8 changes: 8 additions & 0 deletions src/3d/CMakeLists.txt
Expand Up @@ -32,6 +32,10 @@ SET(QGIS_3D_SRCS
qgswindow3dengine.cpp
qgsskyboxentity.cpp
qgsskyboxsettings.cpp
qgsshadowrenderingframegraph.cpp
qgspostprocessingentity.cpp
qgspreviewquad.cpp
qgsshadowsettings.cpp

chunks/qgschunkboundsentity_p.cpp
chunks/qgschunkedentity_p.cpp
Expand Down Expand Up @@ -107,6 +111,10 @@ SET(QGIS_3D_HDRS
qgswindow3dengine.h
qgsskyboxentity.h
qgsskyboxsettings.h
qgsshadowrenderingframegraph.h
qgspostprocessingentity.h
qgspreviewquad.h
qgsshadowsettings.h

materials/qgsabstractmaterialsettings.h
materials/qgsgoochmaterialsettings.h
Expand Down
73 changes: 70 additions & 3 deletions src/3d/qgs3dmapscene.cpp
Expand Up @@ -74,6 +74,8 @@
#include "qgsskyboxentity.h"
#include "qgsskyboxsettings.h"

#include "qgswindow3dengine.h"

Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *engine )
: mMap( map )
, mEngine( engine )
Expand Down Expand Up @@ -126,6 +128,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
connect( &map, &Qgs3DMapSettings::fieldOfViewChanged, this, &Qgs3DMapScene::updateCameraLens );
connect( &map, &Qgs3DMapSettings::renderersChanged, this, &Qgs3DMapScene::onRenderersChanged );
connect( &map, &Qgs3DMapSettings::skyboxSettingsChanged, this, &Qgs3DMapScene::onSkyboxSettingsChanged );
connect( &map, &Qgs3DMapSettings::shadowSettingsChanged, this, &Qgs3DMapScene::onShadowSettingsChanged );

connect( QgsApplication::instance()->sourceCache(), &QgsSourceCache::remoteSourceFetched, this, [ = ]( const QString & url )
{
Expand Down Expand Up @@ -206,6 +209,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
meshEntity->setParent( this );
#endif
onSkyboxSettingsChanged();

// force initial update of chunked entities
onCameraChanged();
}
Expand Down Expand Up @@ -276,7 +280,6 @@ void Qgs3DMapScene::onLayerEntityPickedObject( Qt3DRender::QPickEvent *pickEvent
}
}


float Qgs3DMapScene::worldSpaceError( float epsilon, float distance )
{
Qt3DRender::QCamera *camera = mCameraController->camera();
Expand Down Expand Up @@ -315,6 +318,37 @@ void Qgs3DMapScene::onCameraChanged()
updateScene();
updateCameraNearFarPlanes();
}

onShadowSettingsChanged();
}

void removeQLayerComponentsFromHierarchy( Qt3DCore::QEntity *entity )
{
QVector<Qt3DCore::QComponent *> toBeRemovedComponents;
for ( Qt3DCore::QComponent *component : entity->components() )
{
Qt3DRender::QLayer *layer = qobject_cast<Qt3DRender::QLayer *>( component );
if ( layer != nullptr )
toBeRemovedComponents.push_back( layer );
}
for ( Qt3DCore::QComponent *component : toBeRemovedComponents )
entity->removeComponent( component );
for ( Qt3DCore::QEntity *obj : entity->findChildren<Qt3DCore::QEntity *>() )
{
if ( obj != nullptr )
removeQLayerComponentsFromHierarchy( obj );
}
}

void addQLayerComponentsToHierarchy( Qt3DCore::QEntity *entity, const QVector<Qt3DRender::QLayer *> layers )
{
for ( Qt3DRender::QLayer *layer : layers )
entity->addComponent( layer );
for ( Qt3DCore::QEntity *child : entity->findChildren<Qt3DCore::QEntity *>() )
{
if ( child != nullptr )
addQLayerComponentsToHierarchy( child, layers );
}
}

void Qgs3DMapScene::updateScene()
Expand All @@ -325,7 +359,17 @@ void Qgs3DMapScene::updateScene()
if ( entity->isEnabled() )
entity->update( _sceneState( mCameraController ) );
}

#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
QgsWindow3DEngine *windowEngine = qobject_cast<QgsWindow3DEngine *>( mEngine );
if ( windowEngine != nullptr )
{
QVector<Qt3DRender::QLayer *> layers;
layers.push_back( windowEngine->shadowRenderingFrameGraph()->castShadowsLayer() );
layers.push_back( windowEngine->shadowRenderingFrameGraph()->forwardRenderLayer() );
removeQLayerComponentsFromHierarchy( this );
addQLayerComponentsToHierarchy( this, layers );
}
#endif
updateSceneState();
}

Expand Down Expand Up @@ -483,7 +527,6 @@ void Qgs3DMapScene::onBackgroundColorChanged()
mEngine->setClearColor( mMap.backgroundColor() );
}


void Qgs3DMapScene::updateLights()
{
for ( Qt3DCore::QEntity *entity : qgis::as_const( mLightEntities ) )
Expand Down Expand Up @@ -558,6 +601,8 @@ void Qgs3DMapScene::updateLights()
lightEntity->setParent( this );
mLightEntities << lightEntity;
}

onShadowSettingsChanged();
}

void Qgs3DMapScene::updateCameraLens()
Expand Down Expand Up @@ -885,6 +930,28 @@ void Qgs3DMapScene::onSkyboxSettingsChanged()
}
}

void Qgs3DMapScene::onShadowSettingsChanged()
{
QgsWindow3DEngine *windowEngine = dynamic_cast<QgsWindow3DEngine *>( mEngine );
if ( windowEngine == nullptr )
return;
QgsShadowRenderingFrameGraph *shadowRenderingFrameGraph = windowEngine->shadowRenderingFrameGraph();

QList<QgsDirectionalLightSettings> directionalLights = mMap.directionalLights();
QgsShadowSettings shadowSettings = mMap.shadowSettings();
int selectedLight = shadowSettings.selectedDirectionalLight();
if ( shadowSettings.renderShadows() && selectedLight >= 0 && selectedLight < directionalLights.count() )
{
shadowRenderingFrameGraph->setShadowRenderingEnabled( true );
shadowRenderingFrameGraph->setShadowBias( shadowSettings.shadowBias() );
shadowRenderingFrameGraph->setShadowMapResolution( shadowSettings.shadowMapResolution() );
QgsDirectionalLightSettings light = directionalLights[selectedLight];
shadowRenderingFrameGraph->setupDirectionalLight( light, shadowSettings.maximumShadowRenderingDistance() );
}
else
shadowRenderingFrameGraph->setShadowRenderingEnabled( false );
}

void Qgs3DMapScene::exportScene( const Qgs3DMapExportSettings &exportSettings )
{
QVector<QString> notParsedLayers;
Expand Down
6 changes: 5 additions & 1 deletion src/3d/qgs3dmapscene.h
Expand Up @@ -21,6 +21,7 @@
#include <Qt3DCore/QEntity>

#include "qgsfeatureid.h"
#include "qgsshadowrenderingframegraph.h"

namespace Qt3DRender
{
Expand Down Expand Up @@ -52,6 +53,9 @@ class QgsChunkedEntity;
class QgsSkyboxEntity;
class QgsSkyboxSettings;
class Qgs3DMapExportSettings;
class QgsShadowRenderingFrameGraph;
class QgsPostprocessingEntity;


#define SIP_NO_FILE

Expand Down Expand Up @@ -139,6 +143,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
void updateCameraLens();
void onRenderersChanged();
void onSkyboxSettingsChanged();
void onShadowSettingsChanged();

private:
void addLayerEntity( QgsMapLayer *layer );
Expand Down Expand Up @@ -174,7 +179,6 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
QList<Qt3DCore::QEntity *> mLightOriginEntities;
QList<QgsMapLayer *> mModelVectorLayers;
QgsSkyboxEntity *mSkybox = nullptr;

};

#endif // QGS3DMAPSCENE_H
14 changes: 14 additions & 0 deletions src/3d/qgs3dmapsettings.cpp
Expand Up @@ -60,6 +60,7 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
, mMapThemes( other.mMapThemes )
, mIsSkyboxEnabled( other.mIsSkyboxEnabled )
, mSkyboxSettings()
, mShadowSettings()
{
Q_FOREACH ( QgsAbstract3DRenderer *renderer, other.mRenderers )
{
Expand Down Expand Up @@ -228,6 +229,9 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
mIsSkyboxEnabled = elemSkybox.attribute( QStringLiteral( "skybox-enabled" ) ).toInt();
mSkyboxSettings.readXml( elemSkybox, context );

QDomElement elemShadows = elem.firstChildElement( QStringLiteral( "shadow-rendering" ) );
mShadowSettings.readXml( elemShadows, context );

QDomElement elemDebug = elem.firstChildElement( QStringLiteral( "debug" ) );
mShowTerrainBoundingBoxes = elemDebug.attribute( QStringLiteral( "bounding-boxes" ), QStringLiteral( "0" ) ).toInt();
mShowTerrainTileInfo = elemDebug.attribute( QStringLiteral( "terrain-tile-info" ), QStringLiteral( "0" ) ).toInt();
Expand Down Expand Up @@ -330,6 +334,10 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
mSkyboxSettings.writeXml( elemSkybox, context );
elem.appendChild( elemSkybox );

QDomElement elemShadows = doc.createElement( QStringLiteral( "shadow-rendering" ) );
mShadowSettings.writeXml( elemShadows, context );
elem.appendChild( elemShadows );

QDomElement elemDebug = doc.createElement( QStringLiteral( "debug" ) );
elemDebug.setAttribute( QStringLiteral( "bounding-boxes" ), mShowTerrainBoundingBoxes ? 1 : 0 );
elemDebug.setAttribute( QStringLiteral( "terrain-tile-info" ), mShowTerrainTileInfo ? 1 : 0 );
Expand Down Expand Up @@ -650,3 +658,9 @@ void Qgs3DMapSettings::setSkyboxSettings( const QgsSkyboxSettings &skyboxSetting
mSkyboxSettings = skyboxSettings;
emit skyboxSettingsChanged();
}

void Qgs3DMapSettings::setShadowSettings( const QgsShadowSettings &shadowSettings )
{
mShadowSettings = shadowSettings;
emit shadowSettingsChanged();
}
22 changes: 21 additions & 1 deletion src/3d/qgs3dmapsettings.h
Expand Up @@ -31,6 +31,7 @@
#include "qgsterraingenerator.h"
#include "qgsvector3d.h"
#include "qgsskyboxsettings.h"
#include "qgsshadowsettings.h"

class QgsMapLayer;
class QgsRasterLayer;
Expand Down Expand Up @@ -418,12 +419,24 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
*/
QgsSkyboxSettings skyboxSettings() const SIP_SKIP { return mSkyboxSettings; }

/**
* Returns the current configuration of shadows
* \return QGIS 3.16
*/
QgsShadowSettings shadowSettings() const SIP_SKIP { return mShadowSettings; }

/**
* Sets the current configuration of the skybox
* \since QGIS 3.16
*/
void setSkyboxSettings( const QgsSkyboxSettings &skyboxSettings ) SIP_SKIP;

/**
* Sets the current configuration of shadow rendering
* \since QGIS 3.16
*/
void setShadowSettings( const QgsShadowSettings &shadowSettings ) SIP_SKIP;

/**
* Returns whether the skybox is enabled.
* \see setIsSkyboxEnabled()
Expand Down Expand Up @@ -537,6 +550,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
*/
void skyboxSettingsChanged();

/**
* Emitted when shadow rendering settings are changed
* \since QGIS 3.16
*/
void shadowSettingsChanged();

private:
#ifdef SIP_RUN
Qgs3DMapSettings &operator=( const Qgs3DMapSettings & );
Expand All @@ -563,7 +582,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
bool mShowLabels = false; //!< Whether to display labels on terrain tiles
QList<QgsPointLightSettings> mPointLights; //!< List of point lights defined for the scene
QList<QgsDirectionalLightSettings> mDirectionalLights; //!< List of directional lights defined for the scene
float mFieldOfView = 45.0f; //!< Camera lens field of view value
float mFieldOfView = 45.0f; //<! Camera lens field of view value
QList<QgsMapLayerRef> mLayers; //!< Layers to be rendered
QList<QgsMapLayerRef> mTerrainLayers; //!< Terrain layers to be rendered
QList<QgsAbstract3DRenderer *> mRenderers; //!< Extra stuff to render as 3D object
Expand All @@ -575,6 +594,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec

bool mIsSkyboxEnabled = false; //!< Whether the skybox is enabled
QgsSkyboxSettings mSkyboxSettings; //!< Skybox related configuration
QgsShadowSettings mShadowSettings; //!< Shadow rendering related settings
};


Expand Down
1 change: 1 addition & 0 deletions src/3d/qgsabstract3dengine.h
Expand Up @@ -35,6 +35,7 @@ namespace Qt3DRender
{
class QRenderSettings;
class QCamera;
class QFrameGraphNode;
}

/**
Expand Down
5 changes: 4 additions & 1 deletion src/3d/qgslayoutitem3dmap.cpp
Expand Up @@ -22,7 +22,9 @@
#include "qgslayoutmodel.h"
#include "qgslayoutitemregistry.h"
#include "qgsoffscreen3dengine.h"

#include "qgspostprocessingentity.h"
#include "qgsshadowrenderingframegraph.h"
#include "qgswindow3dengine.h"

QgsLayoutItem3DMap::QgsLayoutItem3DMap( QgsLayout *layout )
: QgsLayoutItem( layout )
Expand Down Expand Up @@ -149,6 +151,7 @@ void QgsLayoutItem3DMap::draw( QgsLayoutItemRenderContext &context )
connect( mScene, &Qgs3DMapScene::sceneStateChanged, this, &QgsLayoutItem3DMap::onSceneStateChanged );

mEngine->setRootEntity( mScene );

}

if ( mEngine->size() != sizePixelsInt )
Expand Down

0 comments on commit 85e444e

Please sign in to comment.