diff --git a/python/3d/auto_generated/qgsphongmaterialsettings.sip.in b/python/3d/auto_generated/qgsphongmaterialsettings.sip.in index b1e45aae953..59843cb3439 100644 --- a/python/3d/auto_generated/qgsphongmaterialsettings.sip.in +++ b/python/3d/auto_generated/qgsphongmaterialsettings.sip.in @@ -73,6 +73,8 @@ Reads settings from a DOM element Writes settings to a DOM element %End + bool operator==( const QgsPhongMaterialSettings &other ) const; + }; diff --git a/src/3d/qgs3dmapscene.cpp b/src/3d/qgs3dmapscene.cpp index e852eeb4dc7..6d674e889d7 100644 --- a/src/3d/qgs3dmapscene.cpp +++ b/src/3d/qgs3dmapscene.cpp @@ -92,6 +92,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine * connect( &map, &Qgs3DMapSettings::mapTileResolutionChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::maxTerrainScreenErrorChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::maxTerrainGroundErrorChanged, this, &Qgs3DMapScene::createTerrain ); + connect( &map, &Qgs3DMapSettings::terrainShadingChanged, this, &Qgs3DMapScene::createTerrain ); // create entities of renderers diff --git a/src/3d/qgs3dmapsettings.cpp b/src/3d/qgs3dmapsettings.cpp index 533bea6f045..765b72b2f4e 100644 --- a/src/3d/qgs3dmapsettings.cpp +++ b/src/3d/qgs3dmapsettings.cpp @@ -37,6 +37,8 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other ) , mMapTileResolution( other.mMapTileResolution ) , mMaxTerrainScreenError( other.mMaxTerrainScreenError ) , mMaxTerrainGroundError( other.mMaxTerrainGroundError ) + , mTerrainShadingEnabled( other.mTerrainShadingEnabled ) + , mTerrainShadingMaterial( other.mTerrainShadingMaterial ) , mShowTerrainBoundingBoxes( other.mShowTerrainBoundingBoxes ) , mShowTerrainTileInfo( other.mShowTerrainTileInfo ) , mShowCameraViewCenter( other.mShowCameraViewCenter ) @@ -79,6 +81,10 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte mMapTileResolution = elemTerrain.attribute( QStringLiteral( "texture-size" ), QStringLiteral( "512" ) ).toInt(); mMaxTerrainScreenError = elemTerrain.attribute( QStringLiteral( "max-terrain-error" ), QStringLiteral( "3" ) ).toFloat(); mMaxTerrainGroundError = elemTerrain.attribute( QStringLiteral( "max-ground-error" ), QStringLiteral( "1" ) ).toFloat(); + mTerrainShadingEnabled = elemTerrain.attribute( QStringLiteral( "shading-enabled" ), QStringLiteral( "0" ) ).toInt(); + QDomElement elemTerrainShadingMaterial = elemTerrain.firstChildElement( QStringLiteral( "shading-material" ) ); + if ( !elemTerrainShadingMaterial.isNull() ) + mTerrainShadingMaterial.readXml( elemTerrainShadingMaterial ); mShowLabels = elemTerrain.attribute( QStringLiteral( "show-labels" ), QStringLiteral( "0" ) ).toInt(); QDomElement elemMapLayers = elemTerrain.firstChildElement( QStringLiteral( "layers" ) ); QDomElement elemMapLayer = elemMapLayers.firstChildElement( QStringLiteral( "layer" ) ); @@ -169,6 +175,10 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon elemTerrain.setAttribute( QStringLiteral( "texture-size" ), mMapTileResolution ); elemTerrain.setAttribute( QStringLiteral( "max-terrain-error" ), QString::number( mMaxTerrainScreenError ) ); elemTerrain.setAttribute( QStringLiteral( "max-ground-error" ), QString::number( mMaxTerrainGroundError ) ); + elemTerrain.setAttribute( QStringLiteral( "shading-enabled" ), mTerrainShadingEnabled ? 1 : 0 ); + QDomElement elemTerrainShadingMaterial = doc.createElement( QStringLiteral( "shading-material" ) ); + mTerrainShadingMaterial.writeXml( elemTerrainShadingMaterial ); + elemTerrain.appendChild( elemTerrainShadingMaterial ); elemTerrain.setAttribute( QStringLiteral( "show-labels" ), mShowLabels ? 1 : 0 ); QDomElement elemMapLayers = doc.createElement( QStringLiteral( "layers" ) ); Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers ) @@ -370,6 +380,24 @@ void Qgs3DMapSettings::setTerrainGenerator( QgsTerrainGenerator *gen ) emit terrainGeneratorChanged(); } +void Qgs3DMapSettings::setTerrainShadingEnabled( bool enabled ) +{ + if ( mTerrainShadingEnabled == enabled ) + return; + + mTerrainShadingEnabled = enabled; + emit terrainShadingChanged(); +} + +void Qgs3DMapSettings::setTerrainShadingMaterial( const QgsPhongMaterialSettings &material ) +{ + if ( mTerrainShadingMaterial == material ) + return; + + mTerrainShadingMaterial = material; + emit terrainShadingChanged(); +} + void Qgs3DMapSettings::setRenderers( const QList &renderers ) { mRenderers = renderers; diff --git a/src/3d/qgs3dmapsettings.h b/src/3d/qgs3dmapsettings.h index 24d2dd010b9..b9032672b2b 100644 --- a/src/3d/qgs3dmapsettings.h +++ b/src/3d/qgs3dmapsettings.h @@ -24,6 +24,7 @@ #include "qgscoordinatereferencesystem.h" #include "qgsmaplayerref.h" +#include "qgsphongmaterialsettings.h" #include "qgsterraingenerator.h" #include "qgsvector3d.h" @@ -200,6 +201,35 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject //! Returns terrain generator. It takes care of producing terrain tiles from the input data. QgsTerrainGenerator *terrainGenerator() const { return mTerrainGenerator.get(); } + /** + * Sets whether terrain shading is enabled. + * \sa isTerrainShadingEnabled() + * \since QGIS 3.6 + */ + void setTerrainShadingEnabled( bool enabled ); + + /** + * Returns whether terrain shading is enabled. When enabled, in addition to the terrain texture + * generated from the map, the terrain rendering will take into account position of the lights, + * terrain normals and terrain shading material (ambient and specular colors, shininess). + * \since QGIS 3.6 + */ + bool isTerrainShadingEnabled() const { return mTerrainShadingEnabled; } + + /** + * Sets terrain shading material. + * \sa terrainShadingMaterial() + * \since QGIS 3.6 + */ + void setTerrainShadingMaterial( const QgsPhongMaterialSettings &material ); + + /** + * Returns terrain shading material. Diffuse color component is ignored since the diffuse component + * is provided by 2D rendered map texture. Only used when isTerrainShadingEnabled() is true. + * \since QGIS 3.6 + */ + QgsPhongMaterialSettings terrainShadingMaterial() const { return mTerrainShadingMaterial; } + //! Sets list of extra 3D renderers to use in the scene. Takes ownership of the objects. void setRenderers( const QList &renderers SIP_TRANSFER ); //! Returns list of extra 3D renderers @@ -261,6 +291,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject void maxTerrainScreenErrorChanged(); //! Emitted when the maximum terrain ground error has changed void maxTerrainGroundErrorChanged(); + + /** + * Emitted when terrain shading enabled flag or terrain shading material has changed + * \since QGIS 3.6 + */ + void terrainShadingChanged(); //! Emitted when the flag whether terrain's bounding boxes are shown has changed void showTerrainBoundingBoxesChanged(); //! Emitted when the flag whether terrain's tile info is shown has changed @@ -285,6 +321,8 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject int mMapTileResolution = 512; //!< Size of map textures of tiles in pixels (width/height) float mMaxTerrainScreenError = 3.f; //!< Maximum allowed terrain error in pixels (determines when tiles are switched to more detailed ones) float mMaxTerrainGroundError = 1.f; //!< Maximum allowed horizontal map error in map units (determines how many zoom levels will be used) + bool mTerrainShadingEnabled = false; //!< Whether terrain should be shaded taking lights into account + QgsPhongMaterialSettings mTerrainShadingMaterial; //!< Material to use for the terrain (if shading is enabled). Diffuse color is ignored. bool mShowTerrainBoundingBoxes = false; //!< Whether to show bounding boxes of entities - useful for debugging bool mShowTerrainTileInfo = false; //!< Whether to draw extra information about terrain tiles to the textures - useful for debugging bool mShowCameraViewCenter = false; //!< Whether to show camera view center as a sphere - useful for debugging diff --git a/src/3d/qgsphongmaterialsettings.h b/src/3d/qgsphongmaterialsettings.h index 851dd75bc55..531a61a9a1b 100644 --- a/src/3d/qgsphongmaterialsettings.h +++ b/src/3d/qgsphongmaterialsettings.h @@ -65,6 +65,14 @@ class _3D_EXPORT QgsPhongMaterialSettings //! Writes settings to a DOM element void writeXml( QDomElement &elem ) const; + bool operator==( const QgsPhongMaterialSettings &other ) const + { + return mAmbient == other.mAmbient && + mDiffuse == other.mDiffuse && + mSpecular == other.mSpecular && + mShininess == other.mShininess; + } + private: QColor mAmbient; QColor mDiffuse; diff --git a/src/3d/terrain/qgsdemterraintileloader_p.cpp b/src/3d/terrain/qgsdemterraintileloader_p.cpp index e0bfcb2ae38..b3dee198b25 100644 --- a/src/3d/terrain/qgsdemterraintileloader_p.cpp +++ b/src/3d/terrain/qgsdemterraintileloader_p.cpp @@ -94,7 +94,7 @@ Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *par // create material - createTextureComponent( entity ); + createTextureComponent( entity, map.isTerrainShadingEnabled(), map.terrainShadingMaterial() ); // create transform diff --git a/src/3d/terrain/qgsflatterraingenerator.cpp b/src/3d/terrain/qgsflatterraingenerator.cpp index c404d79393f..7600c69a6de 100644 --- a/src/3d/terrain/qgsflatterraingenerator.cpp +++ b/src/3d/terrain/qgsflatterraingenerator.cpp @@ -52,7 +52,8 @@ Qt3DCore::QEntity *FlatTerrainChunkLoader::createEntity( Qt3DCore::QEntity *pare // create material - createTextureComponent( entity ); + const Qgs3DMapSettings &map = terrain()->map3D(); + createTextureComponent( entity, map.isTerrainShadingEnabled(), map.terrainShadingMaterial() ); // create transform diff --git a/src/3d/terrain/qgsterraintileloader_p.cpp b/src/3d/terrain/qgsterraintileloader_p.cpp index 0a195de468f..ac0d25d3b8b 100644 --- a/src/3d/terrain/qgsterraintileloader_p.cpp +++ b/src/3d/terrain/qgsterraintileloader_p.cpp @@ -25,11 +25,8 @@ #include -#if QT_VERSION >= 0x050900 #include -#else #include -#endif #include "quantizedmeshterraingenerator.h" @@ -67,23 +64,32 @@ void QgsTerrainTileLoader::loadTexture() mTextureJobId = mTerrain->textureGenerator()->render( mExtentMapCrs, mTileDebugText ); } -void QgsTerrainTileLoader::createTextureComponent( QgsTerrainTileEntity *entity ) +void QgsTerrainTileLoader::createTextureComponent( QgsTerrainTileEntity *entity, bool isShadingEnabled, const QgsPhongMaterialSettings &shadingMaterial ) { Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D( entity ); QgsTerrainTextureImage *textureImage = new QgsTerrainTextureImage( mTextureImage, mExtentMapCrs, mTileDebugText ); texture->addTextureImage( textureImage ); texture->setMinificationFilter( Qt3DRender::QTexture2D::Linear ); texture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear ); - Qt3DExtras::QTextureMaterial *material = nullptr; -#if QT_VERSION >= 0x050900 - material = new Qt3DExtras::QTextureMaterial; - material->setTexture( texture ); -#else - material = new Qt3DExtras::QDiffuseMapMaterial; - material->setDiffuse( texture ); - material->setShininess( 1 ); - material->setAmbient( Qt::white ); -#endif + + Qt3DRender::QMaterial *material = nullptr; + if ( isShadingEnabled ) + { + Qt3DExtras::QDiffuseMapMaterial *diffuseMapMaterial; + diffuseMapMaterial = new Qt3DExtras::QDiffuseMapMaterial; + diffuseMapMaterial->setDiffuse( texture ); + diffuseMapMaterial->setAmbient( shadingMaterial.ambient() ); + diffuseMapMaterial->setSpecular( shadingMaterial.specular() ); + diffuseMapMaterial->setShininess( shadingMaterial.shininess() ); + material = diffuseMapMaterial; + } + else + { + Qt3DExtras::QTextureMaterial *textureMaterial = new Qt3DExtras::QTextureMaterial; + textureMaterial->setTexture( texture ); + material = textureMaterial; + } + entity->setTextureImage( textureImage ); entity->addComponent( material ); // takes ownership if the component has no parent } diff --git a/src/3d/terrain/qgsterraintileloader_p.h b/src/3d/terrain/qgsterraintileloader_p.h index ffd3001e90a..8a1d7915b09 100644 --- a/src/3d/terrain/qgsterraintileloader_p.h +++ b/src/3d/terrain/qgsterraintileloader_p.h @@ -32,6 +32,7 @@ #include #include "qgsrectangle.h" +class QgsPhongMaterialSettings; class QgsTerrainEntity; class QgsTerrainTileEntity; @@ -54,7 +55,7 @@ class QgsTerrainTileLoader : public QgsChunkLoader //! Starts asynchronous rendering of map texture void loadTexture(); //! Creates material component for the entity with the rendered map as a texture - void createTextureComponent( QgsTerrainTileEntity *entity ); + void createTextureComponent( QgsTerrainTileEntity *entity, bool isShadingEnabled, const QgsPhongMaterialSettings &shadingMaterial ); //! Gives access to the terain entity QgsTerrainEntity *terrain() { return mTerrain; } diff --git a/src/app/3d/qgs3dmapconfigwidget.cpp b/src/app/3d/qgs3dmapconfigwidget.cpp index cdf35ac1504..4986ba1c0cb 100644 --- a/src/app/3d/qgs3dmapconfigwidget.cpp +++ b/src/app/3d/qgs3dmapconfigwidget.cpp @@ -69,6 +69,10 @@ Qgs3DMapConfigWidget::Qgs3DMapConfigWidget( Qgs3DMapSettings *map, QgsMapCanvas chkShowBoundingBoxes->setChecked( mMap->showTerrainBoundingBoxes() ); chkShowCameraViewCenter->setChecked( mMap->showCameraViewCenter() ); + groupTerrainShading->setChecked( mMap->isTerrainShadingEnabled() ); + widgetTerrainMaterial->setDiffuseVisible( false ); + widgetTerrainMaterial->setMaterial( mMap->terrainShadingMaterial() ); + connect( cboTerrainLayer, static_cast( &QgsMapLayerComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainLayerChanged ); connect( spinMapResolution, static_cast( &QSpinBox::valueChanged ), this, &Qgs3DMapConfigWidget::updateMaxZoomLevel ); connect( spinGroundError, static_cast( &QDoubleSpinBox::valueChanged ), this, &Qgs3DMapConfigWidget::updateMaxZoomLevel ); @@ -134,6 +138,9 @@ void Qgs3DMapConfigWidget::apply() mMap->setShowTerrainTilesInfo( chkShowTileInfo->isChecked() ); mMap->setShowTerrainBoundingBoxes( chkShowBoundingBoxes->isChecked() ); mMap->setShowCameraViewCenter( chkShowCameraViewCenter->isChecked() ); + + mMap->setTerrainShadingEnabled( groupTerrainShading->isChecked() ); + mMap->setTerrainShadingMaterial( widgetTerrainMaterial->material() ); } void Qgs3DMapConfigWidget::onTerrainLayerChanged() diff --git a/src/app/3d/qgsphongmaterialwidget.cpp b/src/app/3d/qgsphongmaterialwidget.cpp index 76d02d0cc70..fa30d028ed9 100644 --- a/src/app/3d/qgsphongmaterialwidget.cpp +++ b/src/app/3d/qgsphongmaterialwidget.cpp @@ -31,6 +31,17 @@ QgsPhongMaterialWidget::QgsPhongMaterialWidget( QWidget *parent ) connect( spinShininess, static_cast( &QDoubleSpinBox::valueChanged ), this, &QgsPhongMaterialWidget::changed ); } +void QgsPhongMaterialWidget::setDiffuseVisible( bool visible ) +{ + label->setVisible( visible ); + btnDiffuse->setVisible( visible ); +} + +bool QgsPhongMaterialWidget::isDiffuseVisible() const +{ + return btnDiffuse->isVisible(); +} + void QgsPhongMaterialWidget::setMaterial( const QgsPhongMaterialSettings &material ) { btnDiffuse->setColor( material.diffuse() ); diff --git a/src/app/3d/qgsphongmaterialwidget.h b/src/app/3d/qgsphongmaterialwidget.h index 855f63d1283..596e298362b 100644 --- a/src/app/3d/qgsphongmaterialwidget.h +++ b/src/app/3d/qgsphongmaterialwidget.h @@ -30,6 +30,9 @@ class QgsPhongMaterialWidget : public QWidget, private Ui::PhongMaterialWidget public: explicit QgsPhongMaterialWidget( QWidget *parent = nullptr ); + void setDiffuseVisible( bool visible ); + bool isDiffuseVisible() const; + void setMaterial( const QgsPhongMaterialSettings &material ); QgsPhongMaterialSettings material() const; diff --git a/src/ui/3d/map3dconfigwidget.ui b/src/ui/3d/map3dconfigwidget.ui index 2cfa2f18b53..7b66de42051 100644 --- a/src/ui/3d/map3dconfigwidget.ui +++ b/src/ui/3d/map3dconfigwidget.ui @@ -7,7 +7,7 @@ 0 0 691 - 830 + 1135 @@ -87,6 +87,21 @@ + + + + Terrain shading + + + true + + + + + + + + @@ -224,6 +239,18 @@ QSpinBox
qgsspinbox.h
+ + QgsPhongMaterialWidget + QWidget +
qgsphongmaterialwidget.h
+ 1 +
+ + QgsCollapsibleGroupBox + QGroupBox +
qgscollapsiblegroupbox.h
+ 1 +
cboTerrainLayer