Skip to content

Commit d3e81f6

Browse files
committedNov 11, 2018
[FEATURE] Add support for shading of terrain
This adds new options for user to choose how the terrain should be rendered: - shading disabled - color of terrain is determined only from map texture - shading enabled - color of terrain is determined using Phong's shading model, taking into account map texture, terrain normal vector, scene light(s) and terrain material's ambient+specular colors and shininess (configuration of lights is not there yet - now we always have a single point light with white color at the middle of the scene at 1km above the zero elevation)
1 parent cf24e65 commit d3e81f6

13 files changed

+151
-18
lines changed
 

‎python/3d/auto_generated/qgsphongmaterialsettings.sip.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Reads settings from a DOM element
7373
Writes settings to a DOM element
7474
%End
7575

76+
bool operator==( const QgsPhongMaterialSettings &other ) const;
77+
7678
};
7779

7880

‎src/3d/qgs3dmapscene.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
9292
connect( &map, &Qgs3DMapSettings::mapTileResolutionChanged, this, &Qgs3DMapScene::createTerrain );
9393
connect( &map, &Qgs3DMapSettings::maxTerrainScreenErrorChanged, this, &Qgs3DMapScene::createTerrain );
9494
connect( &map, &Qgs3DMapSettings::maxTerrainGroundErrorChanged, this, &Qgs3DMapScene::createTerrain );
95+
connect( &map, &Qgs3DMapSettings::terrainShadingChanged, this, &Qgs3DMapScene::createTerrain );
9596

9697
// create entities of renderers
9798

‎src/3d/qgs3dmapsettings.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
3737
, mMapTileResolution( other.mMapTileResolution )
3838
, mMaxTerrainScreenError( other.mMaxTerrainScreenError )
3939
, mMaxTerrainGroundError( other.mMaxTerrainGroundError )
40+
, mTerrainShadingEnabled( other.mTerrainShadingEnabled )
41+
, mTerrainShadingMaterial( other.mTerrainShadingMaterial )
4042
, mShowTerrainBoundingBoxes( other.mShowTerrainBoundingBoxes )
4143
, mShowTerrainTileInfo( other.mShowTerrainTileInfo )
4244
, mShowCameraViewCenter( other.mShowCameraViewCenter )
@@ -79,6 +81,10 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
7981
mMapTileResolution = elemTerrain.attribute( QStringLiteral( "texture-size" ), QStringLiteral( "512" ) ).toInt();
8082
mMaxTerrainScreenError = elemTerrain.attribute( QStringLiteral( "max-terrain-error" ), QStringLiteral( "3" ) ).toFloat();
8183
mMaxTerrainGroundError = elemTerrain.attribute( QStringLiteral( "max-ground-error" ), QStringLiteral( "1" ) ).toFloat();
84+
mTerrainShadingEnabled = elemTerrain.attribute( QStringLiteral( "shading-enabled" ), QStringLiteral( "0" ) ).toInt();
85+
QDomElement elemTerrainShadingMaterial = elemTerrain.firstChildElement( QStringLiteral( "shading-material" ) );
86+
if ( !elemTerrainShadingMaterial.isNull() )
87+
mTerrainShadingMaterial.readXml( elemTerrainShadingMaterial );
8288
mShowLabels = elemTerrain.attribute( QStringLiteral( "show-labels" ), QStringLiteral( "0" ) ).toInt();
8389
QDomElement elemMapLayers = elemTerrain.firstChildElement( QStringLiteral( "layers" ) );
8490
QDomElement elemMapLayer = elemMapLayers.firstChildElement( QStringLiteral( "layer" ) );
@@ -169,6 +175,10 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
169175
elemTerrain.setAttribute( QStringLiteral( "texture-size" ), mMapTileResolution );
170176
elemTerrain.setAttribute( QStringLiteral( "max-terrain-error" ), QString::number( mMaxTerrainScreenError ) );
171177
elemTerrain.setAttribute( QStringLiteral( "max-ground-error" ), QString::number( mMaxTerrainGroundError ) );
178+
elemTerrain.setAttribute( QStringLiteral( "shading-enabled" ), mTerrainShadingEnabled ? 1 : 0 );
179+
QDomElement elemTerrainShadingMaterial = doc.createElement( QStringLiteral( "shading-material" ) );
180+
mTerrainShadingMaterial.writeXml( elemTerrainShadingMaterial );
181+
elemTerrain.appendChild( elemTerrainShadingMaterial );
172182
elemTerrain.setAttribute( QStringLiteral( "show-labels" ), mShowLabels ? 1 : 0 );
173183
QDomElement elemMapLayers = doc.createElement( QStringLiteral( "layers" ) );
174184
Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
@@ -370,6 +380,24 @@ void Qgs3DMapSettings::setTerrainGenerator( QgsTerrainGenerator *gen )
370380
emit terrainGeneratorChanged();
371381
}
372382

383+
void Qgs3DMapSettings::setTerrainShadingEnabled( bool enabled )
384+
{
385+
if ( mTerrainShadingEnabled == enabled )
386+
return;
387+
388+
mTerrainShadingEnabled = enabled;
389+
emit terrainShadingChanged();
390+
}
391+
392+
void Qgs3DMapSettings::setTerrainShadingMaterial( const QgsPhongMaterialSettings &material )
393+
{
394+
if ( mTerrainShadingMaterial == material )
395+
return;
396+
397+
mTerrainShadingMaterial = material;
398+
emit terrainShadingChanged();
399+
}
400+
373401
void Qgs3DMapSettings::setRenderers( const QList<QgsAbstract3DRenderer *> &renderers )
374402
{
375403
mRenderers = renderers;

‎src/3d/qgs3dmapsettings.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "qgscoordinatereferencesystem.h"
2626
#include "qgsmaplayerref.h"
27+
#include "qgsphongmaterialsettings.h"
2728
#include "qgsterraingenerator.h"
2829
#include "qgsvector3d.h"
2930

@@ -200,6 +201,35 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
200201
//! Returns terrain generator. It takes care of producing terrain tiles from the input data.
201202
QgsTerrainGenerator *terrainGenerator() const { return mTerrainGenerator.get(); }
202203

204+
/**
205+
* Sets whether terrain shading is enabled.
206+
* \sa isTerrainShadingEnabled()
207+
* \since QGIS 3.6
208+
*/
209+
void setTerrainShadingEnabled( bool enabled );
210+
211+
/**
212+
* Returns whether terrain shading is enabled. When enabled, in addition to the terrain texture
213+
* generated from the map, the terrain rendering will take into account position of the lights,
214+
* terrain normals and terrain shading material (ambient and specular colors, shininess).
215+
* \since QGIS 3.6
216+
*/
217+
bool isTerrainShadingEnabled() const { return mTerrainShadingEnabled; }
218+
219+
/**
220+
* Sets terrain shading material.
221+
* \sa terrainShadingMaterial()
222+
* \since QGIS 3.6
223+
*/
224+
void setTerrainShadingMaterial( const QgsPhongMaterialSettings &material );
225+
226+
/**
227+
* Returns terrain shading material. Diffuse color component is ignored since the diffuse component
228+
* is provided by 2D rendered map texture. Only used when isTerrainShadingEnabled() is true.
229+
* \since QGIS 3.6
230+
*/
231+
QgsPhongMaterialSettings terrainShadingMaterial() const { return mTerrainShadingMaterial; }
232+
203233
//! Sets list of extra 3D renderers to use in the scene. Takes ownership of the objects.
204234
void setRenderers( const QList<QgsAbstract3DRenderer *> &renderers SIP_TRANSFER );
205235
//! Returns list of extra 3D renderers
@@ -261,6 +291,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
261291
void maxTerrainScreenErrorChanged();
262292
//! Emitted when the maximum terrain ground error has changed
263293
void maxTerrainGroundErrorChanged();
294+
295+
/**
296+
* Emitted when terrain shading enabled flag or terrain shading material has changed
297+
* \since QGIS 3.6
298+
*/
299+
void terrainShadingChanged();
264300
//! Emitted when the flag whether terrain's bounding boxes are shown has changed
265301
void showTerrainBoundingBoxesChanged();
266302
//! Emitted when the flag whether terrain's tile info is shown has changed
@@ -285,6 +321,8 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
285321
int mMapTileResolution = 512; //!< Size of map textures of tiles in pixels (width/height)
286322
float mMaxTerrainScreenError = 3.f; //!< Maximum allowed terrain error in pixels (determines when tiles are switched to more detailed ones)
287323
float mMaxTerrainGroundError = 1.f; //!< Maximum allowed horizontal map error in map units (determines how many zoom levels will be used)
324+
bool mTerrainShadingEnabled = false; //!< Whether terrain should be shaded taking lights into account
325+
QgsPhongMaterialSettings mTerrainShadingMaterial; //!< Material to use for the terrain (if shading is enabled). Diffuse color is ignored.
288326
bool mShowTerrainBoundingBoxes = false; //!< Whether to show bounding boxes of entities - useful for debugging
289327
bool mShowTerrainTileInfo = false; //!< Whether to draw extra information about terrain tiles to the textures - useful for debugging
290328
bool mShowCameraViewCenter = false; //!< Whether to show camera view center as a sphere - useful for debugging

‎src/3d/qgsphongmaterialsettings.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ class _3D_EXPORT QgsPhongMaterialSettings
6565
//! Writes settings to a DOM element
6666
void writeXml( QDomElement &elem ) const;
6767

68+
bool operator==( const QgsPhongMaterialSettings &other ) const
69+
{
70+
return mAmbient == other.mAmbient &&
71+
mDiffuse == other.mDiffuse &&
72+
mSpecular == other.mSpecular &&
73+
mShininess == other.mShininess;
74+
}
75+
6876
private:
6977
QColor mAmbient;
7078
QColor mDiffuse;

‎src/3d/terrain/qgsdemterraintileloader_p.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *par
9494

9595
// create material
9696

97-
createTextureComponent( entity );
97+
createTextureComponent( entity, map.isTerrainShadingEnabled(), map.terrainShadingMaterial() );
9898

9999
// create transform
100100

‎src/3d/terrain/qgsflatterraingenerator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ Qt3DCore::QEntity *FlatTerrainChunkLoader::createEntity( Qt3DCore::QEntity *pare
5252

5353
// create material
5454

55-
createTextureComponent( entity );
55+
const Qgs3DMapSettings &map = terrain()->map3D();
56+
createTextureComponent( entity, map.isTerrainShadingEnabled(), map.terrainShadingMaterial() );
5657

5758
// create transform
5859

‎src/3d/terrain/qgsterraintileloader_p.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@
2525

2626
#include <Qt3DRender/QTexture>
2727

28-
#if QT_VERSION >= 0x050900
2928
#include <Qt3DExtras/QTextureMaterial>
30-
#else
3129
#include <Qt3DExtras/QDiffuseMapMaterial>
32-
#endif
3330

3431
#include "quantizedmeshterraingenerator.h"
3532

@@ -67,23 +64,32 @@ void QgsTerrainTileLoader::loadTexture()
6764
mTextureJobId = mTerrain->textureGenerator()->render( mExtentMapCrs, mTileDebugText );
6865
}
6966

70-
void QgsTerrainTileLoader::createTextureComponent( QgsTerrainTileEntity *entity )
67+
void QgsTerrainTileLoader::createTextureComponent( QgsTerrainTileEntity *entity, bool isShadingEnabled, const QgsPhongMaterialSettings &shadingMaterial )
7168
{
7269
Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D( entity );
7370
QgsTerrainTextureImage *textureImage = new QgsTerrainTextureImage( mTextureImage, mExtentMapCrs, mTileDebugText );
7471
texture->addTextureImage( textureImage );
7572
texture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
7673
texture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
77-
Qt3DExtras::QTextureMaterial *material = nullptr;
78-
#if QT_VERSION >= 0x050900
79-
material = new Qt3DExtras::QTextureMaterial;
80-
material->setTexture( texture );
81-
#else
82-
material = new Qt3DExtras::QDiffuseMapMaterial;
83-
material->setDiffuse( texture );
84-
material->setShininess( 1 );
85-
material->setAmbient( Qt::white );
86-
#endif
74+
75+
Qt3DRender::QMaterial *material = nullptr;
76+
if ( isShadingEnabled )
77+
{
78+
Qt3DExtras::QDiffuseMapMaterial *diffuseMapMaterial;
79+
diffuseMapMaterial = new Qt3DExtras::QDiffuseMapMaterial;
80+
diffuseMapMaterial->setDiffuse( texture );
81+
diffuseMapMaterial->setAmbient( shadingMaterial.ambient() );
82+
diffuseMapMaterial->setSpecular( shadingMaterial.specular() );
83+
diffuseMapMaterial->setShininess( shadingMaterial.shininess() );
84+
material = diffuseMapMaterial;
85+
}
86+
else
87+
{
88+
Qt3DExtras::QTextureMaterial *textureMaterial = new Qt3DExtras::QTextureMaterial;
89+
textureMaterial->setTexture( texture );
90+
material = textureMaterial;
91+
}
92+
8793
entity->setTextureImage( textureImage );
8894
entity->addComponent( material ); // takes ownership if the component has no parent
8995
}

‎src/3d/terrain/qgsterraintileloader_p.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <QImage>
3333
#include "qgsrectangle.h"
3434

35+
class QgsPhongMaterialSettings;
3536
class QgsTerrainEntity;
3637
class QgsTerrainTileEntity;
3738

@@ -54,7 +55,7 @@ class QgsTerrainTileLoader : public QgsChunkLoader
5455
//! Starts asynchronous rendering of map texture
5556
void loadTexture();
5657
//! Creates material component for the entity with the rendered map as a texture
57-
void createTextureComponent( QgsTerrainTileEntity *entity );
58+
void createTextureComponent( QgsTerrainTileEntity *entity, bool isShadingEnabled, const QgsPhongMaterialSettings &shadingMaterial );
5859
//! Gives access to the terain entity
5960
QgsTerrainEntity *terrain() { return mTerrain; }
6061

‎src/app/3d/qgs3dmapconfigwidget.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ Qgs3DMapConfigWidget::Qgs3DMapConfigWidget( Qgs3DMapSettings *map, QgsMapCanvas
6969
chkShowBoundingBoxes->setChecked( mMap->showTerrainBoundingBoxes() );
7070
chkShowCameraViewCenter->setChecked( mMap->showCameraViewCenter() );
7171

72+
groupTerrainShading->setChecked( mMap->isTerrainShadingEnabled() );
73+
widgetTerrainMaterial->setDiffuseVisible( false );
74+
widgetTerrainMaterial->setMaterial( mMap->terrainShadingMaterial() );
75+
7276
connect( cboTerrainLayer, static_cast<void ( QComboBox::* )( int )>( &QgsMapLayerComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainLayerChanged );
7377
connect( spinMapResolution, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &Qgs3DMapConfigWidget::updateMaxZoomLevel );
7478
connect( spinGroundError, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &Qgs3DMapConfigWidget::updateMaxZoomLevel );
@@ -134,6 +138,9 @@ void Qgs3DMapConfigWidget::apply()
134138
mMap->setShowTerrainTilesInfo( chkShowTileInfo->isChecked() );
135139
mMap->setShowTerrainBoundingBoxes( chkShowBoundingBoxes->isChecked() );
136140
mMap->setShowCameraViewCenter( chkShowCameraViewCenter->isChecked() );
141+
142+
mMap->setTerrainShadingEnabled( groupTerrainShading->isChecked() );
143+
mMap->setTerrainShadingMaterial( widgetTerrainMaterial->material() );
137144
}
138145

139146
void Qgs3DMapConfigWidget::onTerrainLayerChanged()

‎src/app/3d/qgsphongmaterialwidget.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ QgsPhongMaterialWidget::QgsPhongMaterialWidget( QWidget *parent )
3131
connect( spinShininess, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPhongMaterialWidget::changed );
3232
}
3333

34+
void QgsPhongMaterialWidget::setDiffuseVisible( bool visible )
35+
{
36+
label->setVisible( visible );
37+
btnDiffuse->setVisible( visible );
38+
}
39+
40+
bool QgsPhongMaterialWidget::isDiffuseVisible() const
41+
{
42+
return btnDiffuse->isVisible();
43+
}
44+
3445
void QgsPhongMaterialWidget::setMaterial( const QgsPhongMaterialSettings &material )
3546
{
3647
btnDiffuse->setColor( material.diffuse() );

‎src/app/3d/qgsphongmaterialwidget.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class QgsPhongMaterialWidget : public QWidget, private Ui::PhongMaterialWidget
3030
public:
3131
explicit QgsPhongMaterialWidget( QWidget *parent = nullptr );
3232

33+
void setDiffuseVisible( bool visible );
34+
bool isDiffuseVisible() const;
35+
3336
void setMaterial( const QgsPhongMaterialSettings &material );
3437
QgsPhongMaterialSettings material() const;
3538

‎src/ui/3d/map3dconfigwidget.ui

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>691</width>
10-
<height>830</height>
10+
<height>1135</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -87,6 +87,21 @@
8787
</layout>
8888
</widget>
8989
</item>
90+
<item>
91+
<widget class="QgsCollapsibleGroupBox" name="groupTerrainShading">
92+
<property name="title">
93+
<string>Terrain shading</string>
94+
</property>
95+
<property name="checkable">
96+
<bool>true</bool>
97+
</property>
98+
<layout class="QVBoxLayout" name="verticalLayout_2">
99+
<item>
100+
<widget class="QgsPhongMaterialWidget" name="widgetTerrainMaterial" native="true"/>
101+
</item>
102+
</layout>
103+
</widget>
104+
</item>
90105
<item>
91106
<layout class="QGridLayout" name="gridLayout_2">
92107
<item row="2" column="0">
@@ -224,6 +239,18 @@
224239
<extends>QSpinBox</extends>
225240
<header>qgsspinbox.h</header>
226241
</customwidget>
242+
<customwidget>
243+
<class>QgsPhongMaterialWidget</class>
244+
<extends>QWidget</extends>
245+
<header>qgsphongmaterialwidget.h</header>
246+
<container>1</container>
247+
</customwidget>
248+
<customwidget>
249+
<class>QgsCollapsibleGroupBox</class>
250+
<extends>QGroupBox</extends>
251+
<header>qgscollapsiblegroupbox.h</header>
252+
<container>1</container>
253+
</customwidget>
227254
</customwidgets>
228255
<tabstops>
229256
<tabstop>cboTerrainLayer</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.