Merge pull request #8467 from wonder-sk/configure-lights

[3d] Configuration of lights in 3D map scene
This commit is contained in:
Martin Dobias 2018-11-14 13:53:27 +01:00 committed by GitHub
commit 018e9fa28d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 672 additions and 14 deletions

View File

@ -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

View File

@ -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() );

View File

@ -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

View File

@ -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();
}

View File

@ -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

View 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;
}

View 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

View File

@ -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();

View File

@ -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()

View 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 );
}

View 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

View File

@ -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

View File

@ -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();

View File

@ -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>

View 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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Attenuation (A&lt;span style=&quot; vertical-align:sub;&quot;&gt;0&lt;/span&gt;+A&lt;span style=&quot; vertical-align:sub;&quot;&gt;1&lt;/span&gt;*D+A&lt;span style=&quot; vertical-align:sub;&quot;&gt;2&lt;/span&gt;*D&lt;span style=&quot; vertical-align:super;&quot;&gt;2&lt;/span&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;0&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;1&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>

View File

@ -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() );