Skip to content
Permalink
Browse files

Merge pull request #39884 from NEDJIMAbelgacem/allow-user-adjustment-…

…of-flat-terrain-elevation

[3D] Allow user adjustment of terrain's elevation
  • Loading branch information
wonder-sk committed Nov 11, 2020
2 parents 53380b8 + 1a9061c commit 928997d557038cd44958890731172b036b8ed411
@@ -294,6 +294,20 @@ This value tells that when the given ground error is reached (e.g. 10 meters), i
to further split terrain tiles into finer ones because they will not add extra details anymore.
%End

void setTerrainElevationOffset( float offset );
%Docstring
Sets the terrain elevation offset (used to move the terrain up or down)

.. seealso:: :py:func:`terrainElevationOffset`

.. versionadded:: 3.18
%End

float terrainElevationOffset() const;
%Docstring
Returns the elevation offset of the terrain (used to move the terrain up or down)
%End


void setTerrainShadingEnabled( bool enabled );
%Docstring
@@ -631,6 +645,13 @@ Emitted when the maximum terrain screen error has changed
void maxTerrainGroundErrorChanged();
%Docstring
Emitted when the maximum terrain ground error has changed
%End

void terrainElevationOffsetChanged( float newElevation );
%Docstring
Emitted when the terrain elevation offset is changed

.. versionadded:: 3.16
%End

void terrainShadingChanged();
@@ -13,7 +13,6 @@




class QgsVectorLayer3DRendererMetadata : Qgs3DRendererAbstractMetadata
{
%Docstring
@@ -42,6 +42,7 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
, mMapTileResolution( other.mMapTileResolution )
, mMaxTerrainScreenError( other.mMaxTerrainScreenError )
, mMaxTerrainGroundError( other.mMaxTerrainGroundError )
, mTerrainElevationOffset( other.mTerrainElevationOffset )
, mTerrainShadingEnabled( other.mTerrainShadingEnabled )
, mTerrainShadingMaterial( other.mTerrainShadingMaterial )
, mTerrainMapTheme( other.mTerrainMapTheme )
@@ -60,8 +61,17 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
, mPathResolver( other.mPathResolver )
, mMapThemes( other.mMapThemes )
, mIsSkyboxEnabled( other.mIsSkyboxEnabled )
, mSkyboxSettings()
, mShadowSettings()
, mSkyboxSettings( other.mSkyboxSettings )
, mShadowSettings( other.mShadowSettings )
, mEyeDomeLightingEnabled( other.mEyeDomeLightingEnabled )
, mEyeDomeLightingStrength( other.mEyeDomeLightingStrength )
, mEyeDomeLightingDistance( other.mEyeDomeLightingDistance )
, mDebugShadowMapEnabled( other.mDebugShadowMapEnabled )
, mDebugShadowMapCorner( other.mDebugShadowMapCorner )
, mDebugShadowMapSize( other.mDebugShadowMapSize )
, mDebugDepthMapEnabled( other.mDebugDepthMapEnabled )
, mDebugDepthMapCorner( other.mDebugDepthMapCorner )
, mDebugDepthMapSize( other.mDebugDepthMapSize )
{
Q_FOREACH ( QgsAbstract3DRenderer *renderer, other.mRenderers )
{
@@ -104,6 +114,8 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
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();
mTerrainElevationOffset = elemTerrain.attribute( QStringLiteral( "elevation-offset" ), QStringLiteral( "0.0" ) ).toFloat();

QDomElement elemTerrainShadingMaterial = elemTerrain.firstChildElement( QStringLiteral( "shading-material" ) );
if ( !elemTerrainShadingMaterial.isNull() )
mTerrainShadingMaterial.readXml( elemTerrainShadingMaterial, context );
@@ -292,6 +304,8 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
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 );
elemTerrain.setAttribute( QStringLiteral( "elevation-offset" ), mTerrainElevationOffset );

QDomElement elemTerrainShadingMaterial = doc.createElement( QStringLiteral( "shading-material" ) );
mTerrainShadingMaterial.writeXml( elemTerrainShadingMaterial, context );
elemTerrain.appendChild( elemTerrainShadingMaterial );
@@ -569,6 +583,14 @@ void Qgs3DMapSettings::setMaxTerrainGroundError( float error )
emit maxTerrainGroundErrorChanged();
}

void Qgs3DMapSettings::setTerrainElevationOffset( float offset )
{
if ( mTerrainElevationOffset == offset )
return;
mTerrainElevationOffset = offset;
emit terrainElevationOffsetChanged( mTerrainElevationOffset );
}

float Qgs3DMapSettings::maxTerrainGroundError() const
{
return mMaxTerrainGroundError;
@@ -263,6 +263,18 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
*/
float maxTerrainGroundError() const;

/**
* Sets the terrain elevation offset (used to move the terrain up or down)
* \see terrainElevationOffset()
* \since QGIS 3.18
*/
void setTerrainElevationOffset( float offset );

/**
* Returns the elevation offset of the terrain (used to move the terrain up or down)
*/
float terrainElevationOffset() const { return mTerrainElevationOffset; }

/**
* Sets terrain generator. It takes care of producing terrain tiles from the input data.
* Takes ownership of the generator
@@ -541,6 +553,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
//! Emitted when the maximum terrain ground error has changed
void maxTerrainGroundErrorChanged();

/**
* Emitted when the terrain elevation offset is changed
* \since QGIS 3.16
*/
void terrainElevationOffsetChanged( float newElevation );

/**
* Emitted when terrain shading enabled flag or terrain shading material has changed
* \since QGIS 3.6
@@ -655,6 +673,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
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)
float mTerrainElevationOffset = 0.0f; //!< Terrain elevation offset (used to adjust the position of the terrain and move it up and down)
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.
QString mTerrainMapTheme; //!< Name of map theme used for terrain's texture (empty means use the current map theme)
@@ -181,7 +181,10 @@ void QgsCameraController::resetView( float distance )
void QgsCameraController::setViewFromTop( float worldX, float worldY, float distance, float yaw )
{
QgsCameraPose camPose;
camPose.setCenterPoint( QgsVector3D( worldX, 0, worldY ) );
if ( mTerrainEntity )
camPose.setCenterPoint( QgsVector3D( worldX, mTerrainEntity->terrainElevationOffset(), worldY ) );
else
camPose.setCenterPoint( QgsVector3D( worldX, 0.0f, worldY ) );
camPose.setDistanceFromCenterPoint( distance );
camPose.setHeadingAngle( yaw );

@@ -275,6 +278,12 @@ void QgsCameraController::updateCameraFromPose( bool centerPointChanged )
mCameraPose.setCenterPoint( QgsVector3D( intersectionPoint ) );
mCameraPose.updateCamera( mCamera );
}
else
{
QgsVector3D centerPoint = mCameraPose.centerPoint();
centerPoint.set( centerPoint.x(), mTerrainEntity->terrainElevationOffset(), centerPoint.z() );
mCameraPose.setCenterPoint( centerPoint );
}
}

emit cameraChanged();
@@ -389,7 +389,7 @@ Qt3DCore::QEntity *QgsRuleBased3DRenderer::createEntity( const Qgs3DMapSettings
double zMin, zMax;
Qgs3DUtils::estimateVectorLayerZRange( vl, zMin, zMax );

return new QgsRuleBasedChunkedEntity( vl, zMin, zMax, tilingSettings(), mRootRule, map );
return new QgsRuleBasedChunkedEntity( vl, zMin + map.terrainElevationOffset(), zMax + map.terrainElevationOffset(), tilingSettings(), mRootRule, map );
}

void QgsRuleBased3DRenderer::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
@@ -171,6 +171,11 @@ QgsRuleBasedChunkedEntity::QgsRuleBasedChunkedEntity( QgsVectorLayer *vl, double
: QgsChunkedEntity( -1, // max. allowed screen error (negative tau means that we need to go until leaves are reached)
new QgsRuleBasedChunkLoaderFactory( map, vl, rootRule, tilingSettings.zoomLevelsCount() - 1, zMin, zMax ), true )
{
mTransform = new Qt3DCore::QTransform;
mTransform->setTranslation( QVector3D( 0.0f, map.terrainElevationOffset(), 0.0f ) );
this->addComponent( mTransform );
connect( &map, &Qgs3DMapSettings::terrainElevationOffsetChanged, this, &QgsRuleBasedChunkedEntity::onTerrainElevationOffsetChanged );

setShowBoundingBoxes( tilingSettings.showBoundingBoxes() );
}

@@ -180,4 +185,9 @@ QgsRuleBasedChunkedEntity::~QgsRuleBasedChunkedEntity()
cancelActiveJobs();
}

void QgsRuleBasedChunkedEntity::onTerrainElevationOffsetChanged( float newOffset )
{
mTransform->setTranslation( QVector3D( 0.0f, newOffset, 0.0f ) );
}

/// @endcond
@@ -40,6 +40,10 @@ class QgsVectorLayerFeatureSource;
class QgsAbstract3DSymbol;
class QgsFeature3DHandler;

namespace Qt3DCore
{
class QTransform;
}

/**
* \ingroup 3d
@@ -113,6 +117,10 @@ class QgsRuleBasedChunkedEntity : public QgsChunkedEntity
explicit QgsRuleBasedChunkedEntity( QgsVectorLayer *vl, double zMin, double zMax, const QgsVectorLayer3DTilingSettings &tilingSettings, QgsRuleBased3DRenderer::Rule *rootRule, const Qgs3DMapSettings &map );

~QgsRuleBasedChunkedEntity();
private slots:
void onTerrainElevationOffsetChanged( float newOffset );
private:
Qt3DCore::QTransform *mTransform = nullptr;
};

/// @endcond
@@ -20,6 +20,26 @@
#include "qgsreadwritecontext.h"
#include "qgssymbollayerutils.h"

QgsShadowSettings::QgsShadowSettings( const QgsShadowSettings &other )
: mRenderShadows( other.mRenderShadows )
, mSelectedDirectionalLight( other.mSelectedDirectionalLight )
, mMaximumShadowRenderingDistance( other.mMaximumShadowRenderingDistance )
, mShadowBias( other.mShadowBias )
, mShadowMapResolution( other.mShadowMapResolution )
{

}

QgsShadowSettings &QgsShadowSettings::operator=( QgsShadowSettings const &rhs )
{
this->mRenderShadows = rhs.mRenderShadows;
this->mSelectedDirectionalLight = rhs.mSelectedDirectionalLight;
this->mMaximumShadowRenderingDistance = rhs.mMaximumShadowRenderingDistance;
this->mShadowBias = rhs.mShadowBias;
this->mShadowMapResolution = rhs.mShadowMapResolution;
return *this;
}

void QgsShadowSettings::readXml( const QDomElement &element, const QgsReadWriteContext &context )
{
Q_UNUSED( context );
@@ -34,6 +34,12 @@ class QDomElement;
class _3D_EXPORT QgsShadowSettings
{
public:
//! Default constructor
QgsShadowSettings() = default;
//! Copy constructor
QgsShadowSettings( const QgsShadowSettings &other );
//! delete assignment operator
QgsShadowSettings &operator=( QgsShadowSettings const &rhs );

//! Reads settings from a DOM \a element
void readXml( const QDomElement &element, const QgsReadWriteContext &context );
@@ -20,6 +20,22 @@
#include "qgsreadwritecontext.h"
#include "qgssymbollayerutils.h"

QgsSkyboxSettings::QgsSkyboxSettings( const QgsSkyboxSettings &other )
: mSkyboxType( other.mSkyboxType )
, mPanoramicTexturePath( other.mPanoramicTexturePath )
, mCubeMapFacesPaths( other.mCubeMapFacesPaths )
{

}

QgsSkyboxSettings &QgsSkyboxSettings::operator=( QgsSkyboxSettings const &rhs )
{
this->mSkyboxType = rhs.mSkyboxType;
this->mPanoramicTexturePath = rhs.mPanoramicTexturePath;
this->mCubeMapFacesPaths = rhs.mCubeMapFacesPaths;
return *this;
}

void QgsSkyboxSettings::readXml( const QDomElement &element, const QgsReadWriteContext &context )
{
const QgsPathResolver &pathResolver = context.pathResolver();
@@ -35,6 +35,12 @@ class QDomElement;
class _3D_EXPORT QgsSkyboxSettings
{
public:
//! default constructor
QgsSkyboxSettings() = default;
//! copy constructor
QgsSkyboxSettings( const QgsSkyboxSettings &other );
//! delete assignment operator
QgsSkyboxSettings &operator=( QgsSkyboxSettings const &rhs );

//! Reads settings from a DOM \a element
void readXml( const QDomElement &element, const QgsReadWriteContext &context );
@@ -73,7 +73,7 @@ Qt3DCore::QEntity *QgsVectorLayer3DRenderer::createEntity( const Qgs3DMapSetting
double zMin, zMax;
Qgs3DUtils::estimateVectorLayerZRange( vl, zMin, zMax );

return new QgsVectorLayerChunkedEntity( vl, zMin, zMax, tilingSettings(), mSymbol.get(), map );
return new QgsVectorLayerChunkedEntity( vl, zMin + map.terrainElevationOffset(), zMax + + map.terrainElevationOffset(), tilingSettings(), mSymbol.get(), map );
}

void QgsVectorLayer3DRenderer::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
@@ -31,7 +31,6 @@

class QgsVectorLayer;


/**
* \ingroup core
* Metadata for vector layer 3D renderer to allow creation of its instances from XML
@@ -32,6 +32,7 @@
#include "qgs3dsymbolregistry.h"

#include <QtConcurrent>
#include <Qt3DCore/QTransform>

///@cond PRIVATE

@@ -157,6 +158,12 @@ QgsVectorLayerChunkedEntity::QgsVectorLayerChunkedEntity( QgsVectorLayer *vl, do
: QgsChunkedEntity( -1, // max. allowed screen error (negative tau means that we need to go until leaves are reached)
new QgsVectorLayerChunkLoaderFactory( map, vl, symbol, tilingSettings.zoomLevelsCount() - 1, zMin, zMax ), true )
{
mTransform = new Qt3DCore::QTransform;
mTransform->setTranslation( QVector3D( 0.0f, map.terrainElevationOffset(), 0.0f ) );
this->addComponent( mTransform );

connect( &map, &Qgs3DMapSettings::terrainElevationOffsetChanged, this, &QgsVectorLayerChunkedEntity::onTerrainElevationOffsetChanged );

setShowBoundingBoxes( tilingSettings.showBoundingBoxes() );
}

@@ -166,4 +173,10 @@ QgsVectorLayerChunkedEntity::~QgsVectorLayerChunkedEntity()
cancelActiveJobs();
}

void QgsVectorLayerChunkedEntity::onTerrainElevationOffsetChanged( float newOffset )
{
qDebug() << "QgsVectorLayerChunkedEntity::onTerrainElevationOffsetChanged";
mTransform->setTranslation( QVector3D( 0.0f, newOffset, 0.0f ) );
}

/// @endcond
@@ -40,6 +40,11 @@ class QgsVectorLayerFeatureSource;
class QgsAbstract3DSymbol;
class QgsFeature3DHandler;

namespace Qt3DCore
{
class QTransform;
}

#include <QFutureWatcher>


@@ -112,6 +117,11 @@ class QgsVectorLayerChunkedEntity : public QgsChunkedEntity
explicit QgsVectorLayerChunkedEntity( QgsVectorLayer *vl, double zMin, double zMax, const QgsVectorLayer3DTilingSettings &tilingSettings, QgsAbstract3DSymbol *symbol, const Qgs3DMapSettings &map );

~QgsVectorLayerChunkedEntity();
private slots:
void onTerrainElevationOffsetChanged( float newOffset );

private:
Qt3DCore::QTransform *mTransform = nullptr;
};

/// @endcond
@@ -92,11 +92,11 @@ float edlFactor(vec2 coords)
vec2 texelSize = 2.0 / textureSize(depthTexture, 0);
vec2 neighbours[4] = vec2[4](vec2(-1.0f, 0.0f), vec2(1.0f, 0.0f), vec2(0.0f, -1.0f), vec2(0.0f, 1.0f) );
float factor = 0.0f;
float centerDepth = texture2D(depthTexture, coords).r;
float centerDepth = linearizeDepth( texture2D(depthTexture, coords).r ) / farPlane;
for (int i = 0; i < 4; i++)
{
vec2 neighbourCoords = coords + edlDistance * texelSize * neighbours[i];
float neighbourDepth = texture2D(depthTexture, neighbourCoords).r;
float neighbourDepth = linearizeDepth( texture2D(depthTexture, neighbourCoords).r ) / farPlane;
neighbourDepth = (neighbourDepth == 1.0) ? 0.0 : neighbourDepth;
if (neighbourDepth != 0.0f)
{

0 comments on commit 928997d

Please sign in to comment.
You can’t perform that action at this time.