mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-17 00:04:02 -04:00
Merge pull request #8467 from wonder-sk/configure-lights
[3d] Configuration of lights in 3D map scene
This commit is contained in:
commit
018e9fa28d
@ -12,6 +12,7 @@ SET(QGIS_3D_SRCS
|
||||
qgslayoutitem3dmap.cpp
|
||||
qgsoffscreen3dengine.cpp
|
||||
qgsphongmaterialsettings.cpp
|
||||
qgspointlightsettings.cpp
|
||||
qgsraycastingutils_p.cpp
|
||||
qgstessellatedpolygongeometry.cpp
|
||||
qgstilingscheme.cpp
|
||||
@ -93,6 +94,7 @@ SET(QGIS_3D_HDRS
|
||||
qgslayoutitem3dmap.h
|
||||
qgsoffscreen3dengine.h
|
||||
qgsphongmaterialsettings.h
|
||||
qgspointlightsettings.h
|
||||
qgsraycastingutils_p.h
|
||||
qgstessellatedpolygongeometry.h
|
||||
qgstilingscheme.h
|
||||
|
@ -93,6 +93,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
|
||||
connect( &map, &Qgs3DMapSettings::maxTerrainScreenErrorChanged, this, &Qgs3DMapScene::createTerrain );
|
||||
connect( &map, &Qgs3DMapSettings::maxTerrainGroundErrorChanged, this, &Qgs3DMapScene::createTerrain );
|
||||
connect( &map, &Qgs3DMapSettings::terrainShadingChanged, this, &Qgs3DMapScene::createTerrain );
|
||||
connect( &map, &Qgs3DMapSettings::pointLightsChanged, this, &Qgs3DMapScene::updateLights );
|
||||
|
||||
// create entities of renderers
|
||||
|
||||
@ -105,19 +106,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
|
||||
// listen to changes of layers in order to add/remove 3D renderer entities
|
||||
connect( &map, &Qgs3DMapSettings::layersChanged, this, &Qgs3DMapScene::onLayersChanged );
|
||||
|
||||
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity;
|
||||
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform;
|
||||
lightTransform->setTranslation( QVector3D( 0, 1000, 0 ) );
|
||||
// defaults: white, intensity 0.5
|
||||
// attenuation: constant 1.0, linear 0.0, quadratic 0.0
|
||||
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight;
|
||||
light->setConstantAttenuation( 0 );
|
||||
//light->setColor(Qt::white);
|
||||
//light->setIntensity(0.5);
|
||||
lightEntity->addComponent( light );
|
||||
lightEntity->addComponent( lightTransform );
|
||||
lightEntity->setParent( this );
|
||||
|
||||
updateLights();
|
||||
|
||||
#if 0
|
||||
ChunkedEntity *testChunkEntity = new ChunkedEntity( AABB( -500, 0, -500, 500, 100, 500 ), 2.f, 3.f, 7, new TestChunkLoaderFactory );
|
||||
@ -465,6 +454,36 @@ void Qgs3DMapScene::onLayerEntityPickEvent( Qt3DRender::QPickEvent *event )
|
||||
|
||||
}
|
||||
|
||||
void Qgs3DMapScene::updateLights()
|
||||
{
|
||||
for ( Qt3DCore::QEntity *entity : qgis::as_const( mLightEntities ) )
|
||||
entity->deleteLater();
|
||||
mLightEntities.clear();
|
||||
|
||||
const auto newPointLights = mMap.pointLights();
|
||||
for ( const QgsPointLightSettings &pointLightSettings : newPointLights )
|
||||
{
|
||||
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity;
|
||||
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform;
|
||||
lightTransform->setTranslation( QVector3D( pointLightSettings.position().x(),
|
||||
pointLightSettings.position().y(),
|
||||
pointLightSettings.position().z() ) );
|
||||
|
||||
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight;
|
||||
light->setColor( pointLightSettings.color() );
|
||||
light->setIntensity( pointLightSettings.intensity() );
|
||||
|
||||
light->setConstantAttenuation( pointLightSettings.constantAttenuation() );
|
||||
light->setLinearAttenuation( pointLightSettings.linearAttenuation() );
|
||||
light->setQuadraticAttenuation( pointLightSettings.quadraticAttenuation() );
|
||||
|
||||
lightEntity->addComponent( light );
|
||||
lightEntity->addComponent( lightTransform );
|
||||
lightEntity->setParent( this );
|
||||
mLightEntities << lightEntity;
|
||||
}
|
||||
}
|
||||
|
||||
void Qgs3DMapScene::onLayerRenderer3DChanged()
|
||||
{
|
||||
QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
|
||||
|
@ -106,6 +106,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
|
||||
void createTerrainDeferred();
|
||||
void onBackgroundColorChanged();
|
||||
void onLayerEntityPickEvent( Qt3DRender::QPickEvent *event );
|
||||
void updateLights();
|
||||
|
||||
private:
|
||||
void addLayerEntity( QgsMapLayer *layer );
|
||||
@ -132,6 +133,8 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
|
||||
SceneState mSceneState = Ready;
|
||||
//! List of currently registered pick handlers (used by identify tool)
|
||||
QList<Qgs3DMapScenePickHandler *> mPickHandlers;
|
||||
//! List of lights in the scene
|
||||
QList<Qt3DCore::QEntity *> mLightEntities;
|
||||
};
|
||||
|
||||
#endif // QGS3DMAPSCENE_H
|
||||
|
@ -42,6 +42,8 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
|
||||
, mShowTerrainBoundingBoxes( other.mShowTerrainBoundingBoxes )
|
||||
, mShowTerrainTileInfo( other.mShowTerrainTileInfo )
|
||||
, mShowCameraViewCenter( other.mShowCameraViewCenter )
|
||||
, mShowLabels( other.mShowLabels )
|
||||
, mPointLights( other.mPointLights )
|
||||
, mLayers( other.mLayers )
|
||||
, mSkyboxEnabled( other.mSkyboxEnabled )
|
||||
, mSkyboxFileBase( other.mSkyboxFileBase )
|
||||
@ -86,6 +88,28 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
|
||||
if ( !elemTerrainShadingMaterial.isNull() )
|
||||
mTerrainShadingMaterial.readXml( elemTerrainShadingMaterial );
|
||||
mShowLabels = elemTerrain.attribute( QStringLiteral( "show-labels" ), QStringLiteral( "0" ) ).toInt();
|
||||
|
||||
mPointLights.clear();
|
||||
QDomElement elemPointLights = elem.firstChildElement( QStringLiteral( "point-lights" ) );
|
||||
if ( !elemPointLights.isNull() )
|
||||
{
|
||||
QDomElement elemPointLight = elemPointLights.firstChildElement( QStringLiteral( "point-light" ) );
|
||||
while ( !elemPointLight.isNull() )
|
||||
{
|
||||
QgsPointLightSettings pointLight;
|
||||
pointLight.readXml( elemPointLight );
|
||||
mPointLights << pointLight;
|
||||
elemPointLight = elemPointLight.nextSiblingElement( QStringLiteral( "point-light" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// QGIS <= 3.4 did not have light configuration
|
||||
QgsPointLightSettings defaultLight;
|
||||
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
|
||||
mPointLights << defaultLight;
|
||||
}
|
||||
|
||||
QDomElement elemMapLayers = elemTerrain.firstChildElement( QStringLiteral( "layers" ) );
|
||||
QDomElement elemMapLayer = elemMapLayers.firstChildElement( QStringLiteral( "layer" ) );
|
||||
QList<QgsMapLayerRef> mapLayers;
|
||||
@ -95,6 +119,7 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
|
||||
elemMapLayer = elemMapLayer.nextSiblingElement( QStringLiteral( "layer" ) );
|
||||
}
|
||||
mLayers = mapLayers; // needs to resolve refs afterwards
|
||||
|
||||
QDomElement elemTerrainGenerator = elemTerrain.firstChildElement( QStringLiteral( "generator" ) );
|
||||
QString terrainGenType = elemTerrainGenerator.attribute( QStringLiteral( "type" ) );
|
||||
if ( terrainGenType == QLatin1String( "dem" ) )
|
||||
@ -180,6 +205,15 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
|
||||
mTerrainShadingMaterial.writeXml( elemTerrainShadingMaterial );
|
||||
elemTerrain.appendChild( elemTerrainShadingMaterial );
|
||||
elemTerrain.setAttribute( QStringLiteral( "show-labels" ), mShowLabels ? 1 : 0 );
|
||||
|
||||
QDomElement elemPointLights = doc.createElement( QStringLiteral( "point-lights" ) );
|
||||
for ( const QgsPointLightSettings &pointLight : qgis::as_const( mPointLights ) )
|
||||
{
|
||||
QDomElement elemPointLight = pointLight.writeXml( doc );
|
||||
elemPointLights.appendChild( elemPointLight );
|
||||
}
|
||||
elem.appendChild( elemPointLights );
|
||||
|
||||
QDomElement elemMapLayers = doc.createElement( QStringLiteral( "layers" ) );
|
||||
Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
|
||||
{
|
||||
@ -438,3 +472,12 @@ void Qgs3DMapSettings::setShowLabels( bool enabled )
|
||||
mShowLabels = enabled;
|
||||
emit showLabelsChanged();
|
||||
}
|
||||
|
||||
void Qgs3DMapSettings::setPointLights( const QList<QgsPointLightSettings> &pointLights )
|
||||
{
|
||||
if ( mPointLights == pointLights )
|
||||
return;
|
||||
|
||||
mPointLights = pointLights;
|
||||
emit pointLightsChanged();
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsmaplayerref.h"
|
||||
#include "qgsphongmaterialsettings.h"
|
||||
#include "qgspointlightsettings.h"
|
||||
#include "qgsterraingenerator.h"
|
||||
#include "qgsvector3d.h"
|
||||
|
||||
@ -274,6 +275,18 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
|
||||
//! Returns whether to display labels on terrain tiles
|
||||
bool showLabels() const { return mShowLabels; }
|
||||
|
||||
/**
|
||||
* Returns list of point lights defined in the scene
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
QList<QgsPointLightSettings> pointLights() const { return mPointLights; }
|
||||
|
||||
/**
|
||||
* Sets list of point lights defined in the scene
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
void setPointLights( const QList<QgsPointLightSettings> &pointLights );
|
||||
|
||||
signals:
|
||||
//! Emitted when the background color has changed
|
||||
void backgroundColorChanged();
|
||||
@ -310,6 +323,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
|
||||
//! Emitted when the flag whether labels are displayed on terrain tiles has changed
|
||||
void showLabelsChanged();
|
||||
|
||||
/**
|
||||
* Emitted when the list of point lights changes
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
void pointLightsChanged();
|
||||
|
||||
private:
|
||||
//! Offset in map CRS coordinates at which our 3D world has origin (0,0,0)
|
||||
QgsVector3D mOrigin;
|
||||
@ -327,6 +346,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
|
||||
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
|
||||
bool mShowLabels = false; //!< Whether to display labels on terrain tiles
|
||||
QList<QgsPointLightSettings> mPointLights; //!< List of lights defined for the scene
|
||||
QList<QgsMapLayerRef> mLayers; //!< Layers to be rendered
|
||||
QList<QgsAbstract3DRenderer *> mRenderers; //!< Extra stuff to render as 3D object
|
||||
bool mSkyboxEnabled = false; //!< Whether to render skybox
|
||||
|
54
src/3d/qgspointlightsettings.cpp
Normal file
54
src/3d/qgspointlightsettings.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/***************************************************************************
|
||||
qgspointlightsettings.cpp
|
||||
--------------------------------------
|
||||
Date : November 2018
|
||||
Copyright : (C) 2018 by Martin Dobias
|
||||
Email : wonder dot sk at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgspointlightsettings.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
#include "qgssymbollayerutils.h"
|
||||
|
||||
|
||||
QDomElement QgsPointLightSettings::writeXml( QDomDocument &doc ) const
|
||||
{
|
||||
QDomElement elemLight = doc.createElement( QStringLiteral( "point-light" ) );
|
||||
elemLight.setAttribute( QStringLiteral( "x" ), mPosition.x() );
|
||||
elemLight.setAttribute( QStringLiteral( "y" ), mPosition.y() );
|
||||
elemLight.setAttribute( QStringLiteral( "z" ), mPosition.z() );
|
||||
elemLight.setAttribute( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
|
||||
elemLight.setAttribute( QStringLiteral( "intensity" ), mIntensity );
|
||||
elemLight.setAttribute( QStringLiteral( "attenuation-0" ), mConstantAttenuation );
|
||||
elemLight.setAttribute( QStringLiteral( "attenuation-1" ), mLinearAttenuation );
|
||||
elemLight.setAttribute( QStringLiteral( "attenuation-2" ), mQuadraticAttenuation );
|
||||
return elemLight;
|
||||
}
|
||||
|
||||
void QgsPointLightSettings::readXml( const QDomElement &elem )
|
||||
{
|
||||
mPosition.set( elem.attribute( QStringLiteral( "x" ) ).toDouble(),
|
||||
elem.attribute( QStringLiteral( "y" ) ).toDouble(),
|
||||
elem.attribute( QStringLiteral( "z" ) ).toDouble() );
|
||||
mColor = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "color" ) ) );
|
||||
mIntensity = elem.attribute( QStringLiteral( "intensity" ) ).toFloat();
|
||||
mConstantAttenuation = elem.attribute( QStringLiteral( "attenuation-0" ) ).toDouble();
|
||||
mLinearAttenuation = elem.attribute( QStringLiteral( "attenuation-1" ) ).toDouble();
|
||||
mQuadraticAttenuation = elem.attribute( QStringLiteral( "attenuation-2" ) ).toDouble();
|
||||
}
|
||||
|
||||
bool QgsPointLightSettings::operator==( const QgsPointLightSettings &other )
|
||||
{
|
||||
return mPosition == other.mPosition && mColor == other.mColor && mIntensity == other.mIntensity &&
|
||||
mConstantAttenuation == other.mConstantAttenuation && mLinearAttenuation == other.mLinearAttenuation &&
|
||||
mQuadraticAttenuation == other.mQuadraticAttenuation;
|
||||
}
|
88
src/3d/qgspointlightsettings.h
Normal file
88
src/3d/qgspointlightsettings.h
Normal file
@ -0,0 +1,88 @@
|
||||
/***************************************************************************
|
||||
qgspointlightsettings.h
|
||||
--------------------------------------
|
||||
Date : November 2018
|
||||
Copyright : (C) 2018 by Martin Dobias
|
||||
Email : wonder dot sk at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSPOINTLIGHTSETTINGS_H
|
||||
#define QGSPOINTLIGHTSETTINGS_H
|
||||
|
||||
#include "qgsvector3d.h"
|
||||
#include <QColor>
|
||||
|
||||
class QDomDocument;
|
||||
class QDomElement;
|
||||
|
||||
/**
|
||||
* \ingroup 3d
|
||||
* Definition of a point light in a 3D map scene
|
||||
*
|
||||
* Total light at the distance D from a point light with intensity I
|
||||
* is (I / TA) where TA is total attenuation which is calculated as
|
||||
* (A_0 + A_1 * D + A_2 * D^2). The terms A_0, A_1 and A_2 stand for
|
||||
* constant, linear and quadratic attenuation.
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
class QgsPointLightSettings
|
||||
{
|
||||
public:
|
||||
//! Construct a point light with default values
|
||||
QgsPointLightSettings() = default;
|
||||
|
||||
//! Returns position of the light (in 3D world coordinates)
|
||||
QgsVector3D position() const { return mPosition; }
|
||||
//! Sets position of the light (in 3D world coordinates)
|
||||
void setPosition( const QgsVector3D &pos ) { mPosition = pos; }
|
||||
|
||||
//! Returns color of the light
|
||||
QColor color() const { return mColor; }
|
||||
//! Sets color of the light
|
||||
void setColor( const QColor &color ) { mColor = color; }
|
||||
|
||||
//! Returns intensity of the light
|
||||
float intensity() const { return mIntensity; }
|
||||
//! Sets intensity of the light
|
||||
void setIntensity( float intensity ) { mIntensity = intensity; }
|
||||
|
||||
//! Returns constant attenuation (A_0)
|
||||
float constantAttenuation() const { return mConstantAttenuation; }
|
||||
//! Sets constant attenuation (A_0)
|
||||
void setConstantAttenuation( float value ) { mConstantAttenuation = value; }
|
||||
|
||||
//! Returns linear attenuation (A_1)
|
||||
float linearAttenuation() const { return mLinearAttenuation; }
|
||||
//! Sets linear attenuation (A_1)
|
||||
void setLinearAttenuation( float value ) { mLinearAttenuation = value; }
|
||||
|
||||
//! Returns quadratic attenuation (A_2)
|
||||
float quadraticAttenuation() const { return mQuadraticAttenuation; }
|
||||
//! Sets quadratic attenuation (A_2)
|
||||
void setQuadraticAttenuation( float value ) { mQuadraticAttenuation = value; }
|
||||
|
||||
//! Writes configuration to a new DOM element and returns it
|
||||
QDomElement writeXml( QDomDocument &doc ) const;
|
||||
//! Reads configuration from a DOM element previously written using writeXml()
|
||||
void readXml( const QDomElement &elem );
|
||||
|
||||
bool operator==( const QgsPointLightSettings &other );
|
||||
|
||||
private:
|
||||
QgsVector3D mPosition;
|
||||
QColor mColor = Qt::white;
|
||||
float mIntensity = 0.5;
|
||||
float mConstantAttenuation = 1.0f;
|
||||
float mLinearAttenuation = 0.0f;
|
||||
float mQuadraticAttenuation = 0.0f;
|
||||
};
|
||||
|
||||
#endif // QGSPOINTLIGHTSETTINGS_H
|
@ -69,7 +69,7 @@ void Qgs3DAnimationWidget::setCameraController( QgsCameraController *cameraContr
|
||||
|
||||
void Qgs3DAnimationWidget::setAnimation( const Qgs3DAnimationSettings &animSettings )
|
||||
{
|
||||
cboInterpolation->setCurrentIndex( animSettings.easingCurve().type() );
|
||||
whileBlocking( cboInterpolation )->setCurrentIndex( animSettings.easingCurve().type() );
|
||||
|
||||
// initialize GUI from the given animation
|
||||
cboKeyframe->clear();
|
||||
|
@ -73,6 +73,8 @@ Qgs3DMapConfigWidget::Qgs3DMapConfigWidget( Qgs3DMapSettings *map, QgsMapCanvas
|
||||
widgetTerrainMaterial->setDiffuseVisible( false );
|
||||
widgetTerrainMaterial->setMaterial( mMap->terrainShadingMaterial() );
|
||||
|
||||
widgetLights->setPointLights( mMap->pointLights() );
|
||||
|
||||
connect( cboTerrainLayer, static_cast<void ( QComboBox::* )( int )>( &QgsMapLayerComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainLayerChanged );
|
||||
connect( spinMapResolution, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &Qgs3DMapConfigWidget::updateMaxZoomLevel );
|
||||
connect( spinGroundError, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &Qgs3DMapConfigWidget::updateMaxZoomLevel );
|
||||
@ -141,6 +143,8 @@ void Qgs3DMapConfigWidget::apply()
|
||||
|
||||
mMap->setTerrainShadingEnabled( groupTerrainShading->isChecked() );
|
||||
mMap->setTerrainShadingMaterial( widgetTerrainMaterial->material() );
|
||||
|
||||
mMap->setPointLights( widgetLights->pointLights() );
|
||||
}
|
||||
|
||||
void Qgs3DMapConfigWidget::onTerrainLayerChanged()
|
||||
|
126
src/app/3d/qgslightswidget.cpp
Normal file
126
src/app/3d/qgslightswidget.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
/***************************************************************************
|
||||
qgslightswidget.cpp
|
||||
--------------------------------------
|
||||
Date : November 2018
|
||||
Copyright : (C) 2018 by Martin Dobias
|
||||
Email : wonder dot sk at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgslightswidget.h"
|
||||
|
||||
#include "qgs3dmapsettings.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
|
||||
QgsLightsWidget::QgsLightsWidget( QWidget *parent )
|
||||
: QWidget( parent )
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
btnAddLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
|
||||
btnRemoveLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
|
||||
|
||||
connect( btnAddLight, &QToolButton::clicked, this, &QgsLightsWidget::onAddLight );
|
||||
connect( btnRemoveLight, &QToolButton::clicked, this, &QgsLightsWidget::onRemoveLight );
|
||||
|
||||
connect( cboLights, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLightsWidget::onCurrentLightChanged );
|
||||
connect( spinPositionX, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
connect( spinPositionY, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
connect( spinPositionZ, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
connect( spinIntensity, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
connect( btnColor, &QgsColorButton::colorChanged, this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
connect( spinA0, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
connect( spinA1, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
connect( spinA2, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
|
||||
}
|
||||
|
||||
void QgsLightsWidget::setPointLights( const QList<QgsPointLightSettings> &pointLights )
|
||||
{
|
||||
mPointLights = pointLights;
|
||||
updateLightsList();
|
||||
cboLights->setCurrentIndex( 0 );
|
||||
onCurrentLightChanged( 0 );
|
||||
}
|
||||
|
||||
QList<QgsPointLightSettings> QgsLightsWidget::pointLights()
|
||||
{
|
||||
return mPointLights;
|
||||
}
|
||||
|
||||
void QgsLightsWidget::onCurrentLightChanged( int index )
|
||||
{
|
||||
if ( index < 0 || index >= cboLights->count() )
|
||||
return;
|
||||
|
||||
QgsPointLightSettings light = mPointLights.at( index );
|
||||
whileBlocking( spinPositionX )->setValue( light.position().x() );
|
||||
whileBlocking( spinPositionY )->setValue( light.position().y() );
|
||||
whileBlocking( spinPositionZ )->setValue( light.position().z() );
|
||||
whileBlocking( btnColor )->setColor( light.color() );
|
||||
whileBlocking( spinIntensity )->setValue( light.intensity() );
|
||||
whileBlocking( spinA0 )->setValue( light.constantAttenuation() );
|
||||
whileBlocking( spinA1 )->setValue( light.linearAttenuation() );
|
||||
whileBlocking( spinA2 )->setValue( light.quadraticAttenuation() );
|
||||
}
|
||||
|
||||
void QgsLightsWidget::updateCurrentLightParameters()
|
||||
{
|
||||
int index = cboLights->currentIndex();
|
||||
if ( index < 0 || index >= cboLights->count() )
|
||||
return;
|
||||
|
||||
QgsPointLightSettings light;
|
||||
light.setPosition( QgsVector3D( spinPositionX->value(), spinPositionY->value(), spinPositionZ->value() ) );
|
||||
light.setColor( btnColor->color() );
|
||||
light.setIntensity( spinIntensity->value() );
|
||||
light.setConstantAttenuation( spinA0->value() );
|
||||
light.setLinearAttenuation( spinA1->value() );
|
||||
light.setQuadraticAttenuation( spinA2->value() );
|
||||
mPointLights[index] = light;
|
||||
}
|
||||
|
||||
void QgsLightsWidget::onAddLight()
|
||||
{
|
||||
if ( mPointLights.count() >= 8 )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Add Light" ), tr( "It is not possible to add more than 8 lights to the scene." ) );
|
||||
return;
|
||||
}
|
||||
|
||||
mPointLights << QgsPointLightSettings();
|
||||
updateLightsList();
|
||||
cboLights->setCurrentIndex( cboLights->count() - 1 );
|
||||
}
|
||||
|
||||
void QgsLightsWidget::onRemoveLight()
|
||||
{
|
||||
int index = cboLights->currentIndex();
|
||||
if ( index < 0 || index >= cboLights->count() )
|
||||
return;
|
||||
|
||||
mPointLights.removeAt( index );
|
||||
updateLightsList();
|
||||
if ( index >= cboLights->count() )
|
||||
--index; // in case we removed the last light
|
||||
cboLights->setCurrentIndex( index );
|
||||
onCurrentLightChanged( index );
|
||||
}
|
||||
|
||||
void QgsLightsWidget::updateLightsList()
|
||||
{
|
||||
cboLights->blockSignals( true );
|
||||
cboLights->clear();
|
||||
for ( int i = 0; i < mPointLights.count(); ++i )
|
||||
{
|
||||
cboLights->addItem( tr( "Light %1" ).arg( i + 1 ) );
|
||||
}
|
||||
cboLights->blockSignals( false );
|
||||
}
|
55
src/app/3d/qgslightswidget.h
Normal file
55
src/app/3d/qgslightswidget.h
Normal file
@ -0,0 +1,55 @@
|
||||
/***************************************************************************
|
||||
qgslightswidget.h
|
||||
--------------------------------------
|
||||
Date : November 2018
|
||||
Copyright : (C) 2018 by Martin Dobias
|
||||
Email : wonder dot sk at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSLIGHTSWIDGET_H
|
||||
#define QGSLIGHTSWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "ui_qgslightswidget.h"
|
||||
|
||||
#include "qgspointlightsettings.h"
|
||||
|
||||
|
||||
/**
|
||||
* Widget for configuration of lights in 3D map scene
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
class QgsLightsWidget : public QWidget, private Ui::QgsLightsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QgsLightsWidget( QWidget *parent = nullptr );
|
||||
|
||||
void setPointLights( const QList<QgsPointLightSettings> &pointLights );
|
||||
|
||||
QList<QgsPointLightSettings> pointLights();
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void onCurrentLightChanged( int index );
|
||||
void updateCurrentLightParameters();
|
||||
void onAddLight();
|
||||
void onRemoveLight();
|
||||
|
||||
private:
|
||||
void updateLightsList();
|
||||
|
||||
private:
|
||||
QList<QgsPointLightSettings> mPointLights;
|
||||
};
|
||||
|
||||
#endif // QGSLIGHTSWIDGET_H
|
@ -470,6 +470,7 @@ IF (WITH_3D)
|
||||
3d/qgs3dmapconfigwidget.cpp
|
||||
3d/qgs3dmaptool.cpp
|
||||
3d/qgs3dmaptoolidentify.cpp
|
||||
3d/qgslightswidget.cpp
|
||||
3d/qgsline3dsymbolwidget.cpp
|
||||
3d/qgspoint3dsymbolwidget.cpp
|
||||
3d/qgspolygon3dsymbolwidget.cpp
|
||||
@ -486,6 +487,7 @@ IF (WITH_3D)
|
||||
3d/qgs3dmapconfigwidget.h
|
||||
3d/qgs3dmaptool.h
|
||||
3d/qgs3dmaptoolidentify.h
|
||||
3d/qgslightswidget.h
|
||||
3d/qgsline3dsymbolwidget.h
|
||||
3d/qgspoint3dsymbolwidget.h
|
||||
3d/qgspolygon3dsymbolwidget.h
|
||||
|
@ -11134,6 +11134,11 @@ void QgisApp::new3DMapCanvas()
|
||||
flatTerrain->setExtent( fullExtent );
|
||||
map->setTerrainGenerator( flatTerrain );
|
||||
|
||||
QgsPointLightSettings defaultPointLight;
|
||||
defaultPointLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
|
||||
defaultPointLight.setConstantAttenuation( 0 );
|
||||
map->setPointLights( QList<QgsPointLightSettings>() << defaultPointLight );
|
||||
|
||||
dock->setMapSettings( map );
|
||||
|
||||
QgsRectangle extent = mMapCanvas->extent();
|
||||
|
@ -102,6 +102,18 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsCollapsibleGroupBox" name="groupLights">
|
||||
<property name="title">
|
||||
<string>Lights</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QgsLightsWidget" name="widgetLights" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="0">
|
||||
@ -251,6 +263,12 @@
|
||||
<header>qgscollapsiblegroupbox.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsLightsWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qgslightswidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>cboTerrainLayer</tabstop>
|
||||
|
216
src/ui/3d/qgslightswidget.ui
Normal file
216
src/ui/3d/qgslightswidget.ui
Normal file
@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsLightsWidget</class>
|
||||
<widget class="QWidget" name="QgsLightsWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>633</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="cboLights"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnAddLight">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnRemoveLight">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinA0">
|
||||
<property name="maximum">
|
||||
<double>9.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinA1">
|
||||
<property name="maximum">
|
||||
<double>9.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinPositionX">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-9999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" rowspan="2">
|
||||
<widget class="QDoubleSpinBox" name="spinPositionY">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-9999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" rowspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinPositionZ">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-9999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Intensity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinIntensity">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Attenuation (A<span style=" vertical-align:sub;">0</span>+A<span style=" vertical-align:sub;">1</span>*D+A<span style=" vertical-align:sub;">2</span>*D<span style=" vertical-align:super;">2</span>)</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QgsColorButton" name="btnColor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinA2">
|
||||
<property name="maximum">
|
||||
<double>9.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>A<span style=" vertical-align:sub;">0</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>A<span style=" vertical-align:sub;">1</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>A<span style=" vertical-align:sub;">2</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsColorButton</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>qgscolorbutton.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>cboLights</tabstop>
|
||||
<tabstop>btnAddLight</tabstop>
|
||||
<tabstop>btnRemoveLight</tabstop>
|
||||
<tabstop>spinPositionX</tabstop>
|
||||
<tabstop>spinPositionY</tabstop>
|
||||
<tabstop>spinPositionZ</tabstop>
|
||||
<tabstop>btnColor</tabstop>
|
||||
<tabstop>spinIntensity</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -185,6 +185,9 @@ void TestQgs3DRendering::testExtrudedPolygons()
|
||||
map->setCrs( mProject->crs() );
|
||||
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
|
||||
map->setLayers( QList<QgsMapLayer *>() << mLayerRgb << mLayerBuildings );
|
||||
QgsPointLightSettings defaultLight;
|
||||
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
|
||||
map->setPointLights( QList<QgsPointLightSettings>() << defaultLight );
|
||||
|
||||
QgsFlatTerrainGenerator *flatTerrain = new QgsFlatTerrainGenerator;
|
||||
flatTerrain->setCrs( map->crs() );
|
||||
|
Loading…
x
Reference in New Issue
Block a user