[Feature] directional lights support for QGIS 3D

This commit is contained in:
nedjima 2020-06-07 00:24:46 +01:00 committed by Nyall Dawson
parent 672d6ec5b2
commit 9556bd2147
13 changed files with 734 additions and 183 deletions

View File

@ -7,6 +7,7 @@
%Include auto_generated/qgslayoutitem3dmap.sip
%Include auto_generated/qgsphongmaterialsettings.sip
%Include auto_generated/qgspointlightsettings.sip
%Include auto_generated/qgsdirectionallightsettings.sip
%Include auto_generated/qgsrulebased3drenderer.sip
%Include auto_generated/qgsvectorlayer3drenderer.sip
%Include auto_generated/symbols/qgsabstract3dsymbol.sip

View File

@ -366,6 +366,13 @@ Returns whether to display labels on terrain tiles
Returns list of point lights defined in the scene
.. versionadded:: 3.6
%End
QList<QgsDirectionalLightSettings> directionalLights() const;
%Docstring
Returns list of directional lights defined in the scene
.. versionadded:: 3.16
%End
void setPointLights( const QList<QgsPointLightSettings> &pointLights );
@ -373,6 +380,13 @@ Returns list of point lights defined in the scene
Sets list of point lights defined in the scene
.. versionadded:: 3.6
%End
void setDirectionalLights( const QList<QgsDirectionalLightSettings> &pointLights );
%Docstring
Sets list of directional lights defined in the scene
.. versionadded:: 3.16
%End
float fieldOfView() const;
@ -487,6 +501,13 @@ Emitted when the flag whether labels are displayed on terrain tiles has changed
Emitted when the list of point lights changes
.. versionadded:: 3.6
%End
void directionalLightsChanged();
%Docstring
Emitted when the list of directional lights changes
.. versionadded:: 3.16
%End
void fieldOfViewChanged();

View File

@ -0,0 +1,75 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/3d/qgsdirectionallightsettings.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsDirectionalLightSettings
{
%Docstring
Definition of a directional light in a 3D map scene
.. versionadded:: 3.16
%End
%TypeHeaderCode
#include "qgsdirectionallightsettings.h"
%End
public:
QgsDirectionalLightSettings();
%Docstring
Construct a directional light with default values
%End
QgsVector3D direction() const;
%Docstring
Returns the direction of the light in degrees
%End
void setDirection( const QgsVector3D &direction );
%Docstring
Sets the direction of the light in degrees
%End
QColor color() const;
%Docstring
Returns color of the light
%End
void setColor( const QColor &color );
%Docstring
Sets color of the light
%End
float intensity() const;
%Docstring
Returns intensity of the light
%End
void setIntensity( float intensity );
%Docstring
Sets intensity of the light
%End
QDomElement writeXml( QDomDocument &doc ) const;
%Docstring
Writes configuration to a new DOM element and returns it
%End
void readXml( const QDomElement &elem );
%Docstring
Reads configuration from a DOM element previously written using writeXml()
%End
bool operator==( const QgsDirectionalLightSettings &other );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/3d/qgsdirectionallightsettings.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -16,6 +16,7 @@ SET(QGIS_3D_SRCS
qgsoffscreen3dengine.cpp
qgsphongmaterialsettings.cpp
qgspointlightsettings.cpp
qgsdirectionallightsettings.cpp
qgsraycastingutils_p.cpp
qgsrulebased3drenderer.cpp
qgsrulebasedchunkloader_p.cpp
@ -87,6 +88,7 @@ SET(QGIS_3D_HDRS
qgsoffscreen3dengine.h
qgsphongmaterialsettings.h
qgspointlightsettings.h
qgsdirectionallightsettings.h
qgsrulebased3drenderer.h
qgstessellatedpolygongeometry.h
qgstilingscheme.h

View File

@ -22,6 +22,7 @@
#include <Qt3DRender/QPickingSettings>
#include <Qt3DRender/QPickTriangleEvent>
#include <Qt3DRender/QPointLight>
#include <Qt3DRender/QDirectionalLight>
#include <Qt3DRender/QRenderSettings>
#include <Qt3DRender/QSceneLoader>
#include <Qt3DExtras/QForwardRenderer>
@ -103,6 +104,7 @@ Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *
connect( &map, &Qgs3DMapSettings::maxTerrainGroundErrorChanged, this, &Qgs3DMapScene::createTerrain );
connect( &map, &Qgs3DMapSettings::terrainShadingChanged, this, &Qgs3DMapScene::createTerrain );
connect( &map, &Qgs3DMapSettings::pointLightsChanged, this, &Qgs3DMapScene::updateLights );
connect( &map, &Qgs3DMapSettings::directionalLightsChanged, this, &Qgs3DMapScene::updateLights );
connect( &map, &Qgs3DMapSettings::fieldOfViewChanged, this, &Qgs3DMapScene::updateCameraLens );
connect( &map, &Qgs3DMapSettings::renderersChanged, this, &Qgs3DMapScene::onRenderersChanged );
@ -474,6 +476,24 @@ void Qgs3DMapScene::updateLights()
lightEntity->setParent( this );
mLightEntities << lightEntity;
}
const auto newDirectionalLights = mMap.directionalLights();
for ( const QgsDirectionalLightSettings &pointLightSettings : newDirectionalLights )
{
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity;
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform;
Qt3DRender::QDirectionalLight *light = new Qt3DRender::QDirectionalLight;
light->setColor( pointLightSettings.color() );
light->setIntensity( pointLightSettings.intensity() );
QgsVector3D direction = pointLightSettings.direction();
light->setWorldDirection( QVector3D( direction.x(), direction.y(), direction.z() ) );
lightEntity->addComponent( light );
lightEntity->addComponent( lightTransform );
lightEntity->setParent( this );
mLightEntities << lightEntity;
}
}
void Qgs3DMapScene::updateCameraLens()

View File

@ -49,6 +49,7 @@ Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
, mShowCameraViewCenter( other.mShowCameraViewCenter )
, mShowLabels( other.mShowLabels )
, mPointLights( other.mPointLights )
, mDirectionalLights( other.mDirectionalLights )
, mFieldOfView( other.mFieldOfView )
, mLayers( other.mLayers )
, mRenderers() // initialized in body
@ -127,6 +128,20 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
mPointLights << defaultLight;
}
mDirectionalLights.clear();
QDomElement elemDirectionalLights = elem.firstChildElement( QStringLiteral( "directional-lights" ) );
if ( !elemDirectionalLights.isNull() )
{
QDomElement elemDirectionalLight = elemDirectionalLights.firstChildElement( QStringLiteral( "directional-light" ) );
while ( !elemDirectionalLight.isNull() )
{
QgsDirectionalLightSettings directionalLight;
directionalLight.readXml( elemDirectionalLight );
mDirectionalLights << directionalLight;
elemDirectionalLight = elemDirectionalLight.nextSiblingElement( QStringLiteral( "directional-light" ) );
}
}
QDomElement elemMapLayers = elemTerrain.firstChildElement( QStringLiteral( "layers" ) );
QDomElement elemMapLayer = elemMapLayers.firstChildElement( QStringLiteral( "layer" ) );
QList<QgsMapLayerRef> mapLayers;
@ -250,6 +265,14 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
}
elem.appendChild( elemPointLights );
QDomElement elemDirectionalLights = doc.createElement( QStringLiteral( "directional-lights" ) );
for ( const QgsDirectionalLightSettings &directionalLight : qgis::as_const( mDirectionalLights ) )
{
QDomElement elemDirectionalLight = directionalLight.writeXml( doc );
elemDirectionalLights.appendChild( elemDirectionalLight );
}
elem.appendChild( elemDirectionalLights );
QDomElement elemMapLayers = doc.createElement( QStringLiteral( "layers" ) );
Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
{
@ -535,6 +558,15 @@ void Qgs3DMapSettings::setPointLights( const QList<QgsPointLightSettings> &point
emit pointLightsChanged();
}
void Qgs3DMapSettings::setDirectionalLights( const QList<QgsDirectionalLightSettings> &directionalLights )
{
if ( mDirectionalLights == directionalLights )
return;
mDirectionalLights = directionalLights;
emit directionalLightsChanged();
}
void Qgs3DMapSettings::setFieldOfView( const float fieldOfView )
{
if ( mFieldOfView == fieldOfView )

View File

@ -27,6 +27,7 @@
#include "qgsmesh3dsymbol.h"
#include "qgsphongmaterialsettings.h"
#include "qgspointlightsettings.h"
#include "qgsdirectionallightsettings.h"
#include "qgsterraingenerator.h"
#include "qgsvector3d.h"
@ -325,12 +326,24 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
*/
QList<QgsPointLightSettings> pointLights() const { return mPointLights; }
/**
* Returns list of directional lights defined in the scene
* \since QGIS 3.16
*/
QList<QgsDirectionalLightSettings> directionalLights() const { return mDirectionalLights; }
/**
* Sets list of point lights defined in the scene
* \since QGIS 3.6
*/
void setPointLights( const QList<QgsPointLightSettings> &pointLights );
/**
* Sets list of directional lights defined in the scene
* \since QGIS 3.16
*/
void setDirectionalLights( const QList<QgsDirectionalLightSettings> &pointLights );
/**
* Returns the camera lens' field of view
* \since QGIS 3.8
@ -413,6 +426,12 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
*/
void pointLightsChanged();
/**
* Emitted when the list of directional lights changes
* \since QGIS 3.16
*/
void directionalLightsChanged();
/**
* Emitted when the camera lens field of view changes
* \since QGIS 3.8
@ -442,7 +461,8 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject, public QgsTemporalRangeObjec
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<QgsPointLightSettings> mPointLights; //!< List of point lights defined for the scene
QList<QgsDirectionalLightSettings> mDirectionalLights; //!< List of directional lights defined for the scene
float mFieldOfView = 45.0f; //<! Camera lens field of view value
QList<QgsMapLayerRef> mLayers; //!< Layers to be rendered
QList<QgsAbstract3DRenderer *> mRenderers; //!< Extra stuff to render as 3D object

View File

@ -0,0 +1,46 @@
/***************************************************************************
qgsdirectionallightsettings.cpp
--------------------------------------
Date : June 2020
Copyright : (C) 2020 by Belgacem Nedjima
Email : gb underscore nedjima at esi dot dz
***************************************************************************
* *
* 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 "qgsdirectionallightsettings.h"
#include <QDomDocument>
#include "qgssymbollayerutils.h"
QDomElement QgsDirectionalLightSettings::writeXml( QDomDocument &doc ) const
{
QDomElement elemLight = doc.createElement( QStringLiteral( "directional-light" ) );
elemLight.setAttribute( QStringLiteral( "x" ), mDirection.x() );
elemLight.setAttribute( QStringLiteral( "y" ), mDirection.y() );
elemLight.setAttribute( QStringLiteral( "z" ), mDirection.z() );
elemLight.setAttribute( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
elemLight.setAttribute( QStringLiteral( "intensity" ), mIntensity );
return elemLight;
}
void QgsDirectionalLightSettings::readXml( const QDomElement &elem )
{
mDirection.set( elem.attribute( QStringLiteral( "x" ) ).toFloat(),
elem.attribute( QStringLiteral( "y" ) ).toFloat(),
elem.attribute( QStringLiteral( "z" ) ).toFloat() );
mColor = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "color" ) ) );
mIntensity = elem.attribute( QStringLiteral( "intensity" ) ).toFloat();
}
bool QgsDirectionalLightSettings::operator==( const QgsDirectionalLightSettings &other )
{
return mDirection == other.mDirection && mColor == other.mColor && mIntensity == other.mIntensity;
}

View File

@ -0,0 +1,66 @@
#ifndef QGSDIRECTIONALLIGHTSETTINGS_H
#define QGSDIRECTIONALLIGHTSETTINGS_H
/***************************************************************************
qgsdirectionallightsettings.h
--------------------------------------
Date : June 2020
Copyright : (C) 2020 by Belgacem Nedjima
Email : gb underscore nedjima at esi dot dz
***************************************************************************
* *
* 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 "qgis_3d.h"
#include "qgsvector3d.h"
#include <QColor>
class QDomDocument;
class QDomElement;
/**
* \ingroup 3d
* Definition of a directional light in a 3D map scene
*
* \since QGIS 3.16
*/
class _3D_EXPORT QgsDirectionalLightSettings
{
public:
//! Construct a directional light with default values
QgsDirectionalLightSettings() = default;
//! Returns the direction of the light in degrees
QgsVector3D direction() const { return mDirection; }
//! Sets the direction of the light in degrees
void setDirection( const QgsVector3D &direction ) { mDirection = direction; }
//! 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; }
//! 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 QgsDirectionalLightSettings &other );
private:
QgsVector3D mDirection = QgsVector3D( 0.0, -1.0, 0.0 );
QColor mColor = Qt::white;
float mIntensity = 0.5;
};
#endif // QGSDIRECTIONALLIGHTSETTINGS_H

View File

@ -108,6 +108,7 @@ Qgs3DMapConfigWidget::Qgs3DMapConfigWidget( Qgs3DMapSettings *map, QgsMapCanvas
widgetTerrainMaterial->setMaterial( mMap->terrainShadingMaterial() );
widgetLights->setPointLights( mMap->pointLights() );
widgetLights->setDirectionalLights( mMap->directionalLights() );
connect( cboTerrainType, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainTypeChanged );
connect( cboTerrainLayer, static_cast<void ( QComboBox::* )( int )>( &QgsMapLayerComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainLayerChanged );
@ -226,6 +227,7 @@ void Qgs3DMapConfigWidget::apply()
mMap->setTerrainShadingMaterial( widgetTerrainMaterial->material() );
mMap->setPointLights( widgetLights->pointLights() );
mMap->setDirectionalLights( widgetLights->directionalLights() );
}
void Qgs3DMapConfigWidget::onTerrainTypeChanged()

View File

@ -41,6 +41,19 @@ QgsLightsWidget::QgsLightsWidget( QWidget *parent )
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 );
btnAddDirectionalLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
btnRemoveDirectionalLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
connect( btnAddDirectionalLight, &QToolButton::clicked, this, &QgsLightsWidget::onAddDirectionalLight );
connect( btnRemoveDirectionalLight, &QToolButton::clicked, this, &QgsLightsWidget::onRemoveDirectionalLight );
connect( cboDirectionalLights, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLightsWidget::onCurrentDirectionalLightChanged );
connect( spinDirectionX, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentDirectionalLightParameters );
connect( spinDirectionY, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentDirectionalLightParameters );
connect( spinDirectionZ, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentDirectionalLightParameters );
connect( spinDirectionalIntensity, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentDirectionalLightParameters );
connect( btnDirectionalColor, &QgsColorButton::colorChanged, this, &QgsLightsWidget::updateCurrentDirectionalLightParameters );
}
void QgsLightsWidget::setPointLights( const QList<QgsPointLightSettings> &pointLights )
@ -51,11 +64,24 @@ void QgsLightsWidget::setPointLights( const QList<QgsPointLightSettings> &pointL
onCurrentLightChanged( 0 );
}
void QgsLightsWidget::setDirectionalLights( const QList<QgsDirectionalLightSettings> &directionalLights )
{
mDirectionalLights = directionalLights;
updateDirectionalLightsList();
cboDirectionalLights->setCurrentIndex( 0 );
onCurrentDirectionalLightChanged( 0 );
}
QList<QgsPointLightSettings> QgsLightsWidget::pointLights()
{
return mPointLights;
}
QList<QgsDirectionalLightSettings> QgsLightsWidget::directionalLights()
{
return mDirectionalLights;
}
void QgsLightsWidget::onCurrentLightChanged( int index )
{
if ( index < 0 || index >= cboLights->count() )
@ -72,6 +98,20 @@ void QgsLightsWidget::onCurrentLightChanged( int index )
whileBlocking( spinA2 )->setValue( light.quadraticAttenuation() );
}
void QgsLightsWidget::onCurrentDirectionalLightChanged( int index )
{
if ( index < 0 || index >= cboDirectionalLights->count() )
return;
QgsDirectionalLightSettings light = mDirectionalLights.at( index );
whileBlocking( spinDirectionX )->setValue( light.direction().x() );
whileBlocking( spinDirectionY )->setValue( light.direction().y() );
whileBlocking( spinDirectionZ )->setValue( light.direction().z() );
whileBlocking( btnDirectionalColor )->setColor( light.color() );
whileBlocking( spinDirectionalIntensity )->setValue( light.intensity() );
}
void QgsLightsWidget::updateCurrentLightParameters()
{
int index = cboLights->currentIndex();
@ -88,6 +128,19 @@ void QgsLightsWidget::updateCurrentLightParameters()
mPointLights[index] = light;
}
void QgsLightsWidget::updateCurrentDirectionalLightParameters()
{
int index = cboDirectionalLights->currentIndex();
if ( index < 0 || index >= cboDirectionalLights->count() )
return;
QgsDirectionalLightSettings light;
light.setDirection( QgsVector3D( spinDirectionX->value(), spinDirectionY->value(), spinDirectionZ->value() ) );
light.setColor( btnDirectionalColor->color() );
light.setIntensity( spinDirectionalIntensity->value() );
mDirectionalLights[index] = light;
}
void QgsLightsWidget::onAddLight()
{
if ( mPointLights.count() >= 8 )
@ -99,6 +152,23 @@ void QgsLightsWidget::onAddLight()
mPointLights << QgsPointLightSettings();
updateLightsList();
cboLights->setCurrentIndex( cboLights->count() - 1 );
// To set default parameters of the light
onCurrentDirectionalLightChanged( 0 );
}
void QgsLightsWidget::onAddDirectionalLight()
{
if ( mDirectionalLights.count() >= 4 )
{
QMessageBox::warning( this, tr( "Add Directional Light" ), tr( "It is not possible to add more than 4 directional lights to the scene." ) );
return;
}
mDirectionalLights << QgsDirectionalLightSettings();
updateDirectionalLightsList();
cboDirectionalLights->setCurrentIndex( cboDirectionalLights->count() - 1 );
// To set default parameters of the light
onCurrentDirectionalLightChanged( 0 );
}
void QgsLightsWidget::onRemoveLight()
@ -115,6 +185,20 @@ void QgsLightsWidget::onRemoveLight()
onCurrentLightChanged( index );
}
void QgsLightsWidget::onRemoveDirectionalLight()
{
int index = cboDirectionalLights->currentIndex();
if ( index < 0 || index >= cboDirectionalLights->count() )
return;
mDirectionalLights.removeAt( index );
updateDirectionalLightsList();
if ( index >= cboDirectionalLights->count() )
--index; // in case we removed the last light
cboDirectionalLights->setCurrentIndex( index );
onCurrentDirectionalLightChanged( index );
}
void QgsLightsWidget::updateLightsList()
{
cboLights->blockSignals( true );
@ -125,3 +209,14 @@ void QgsLightsWidget::updateLightsList()
}
cboLights->blockSignals( false );
}
void QgsLightsWidget::updateDirectionalLightsList()
{
cboDirectionalLights->blockSignals( true );
cboDirectionalLights->clear();
for ( int i = 0; i < mDirectionalLights.count(); ++i )
{
cboDirectionalLights->addItem( tr( "Directional light %1" ).arg( i + 1 ) );
}
cboDirectionalLights->blockSignals( false );
}

View File

@ -21,6 +21,7 @@
#include "ui_qgslightswidget.h"
#include "qgspointlightsettings.h"
#include "qgsdirectionallightsettings.h"
/**
@ -34,8 +35,10 @@ class QgsLightsWidget : public QWidget, private Ui::QgsLightsWidget
explicit QgsLightsWidget( QWidget *parent = nullptr );
void setPointLights( const QList<QgsPointLightSettings> &pointLights );
void setDirectionalLights( const QList<QgsDirectionalLightSettings> &directionalLights );
QList<QgsPointLightSettings> pointLights();
QList<QgsDirectionalLightSettings> directionalLights();
signals:
@ -45,11 +48,18 @@ class QgsLightsWidget : public QWidget, private Ui::QgsLightsWidget
void onAddLight();
void onRemoveLight();
void onCurrentDirectionalLightChanged( int index );
void updateCurrentDirectionalLightParameters();
void onAddDirectionalLight();
void onRemoveDirectionalLight();
private:
void updateLightsList();
void updateDirectionalLightsList();
private:
QList<QgsPointLightSettings> mPointLights;
QList<QgsDirectionalLightSettings> mDirectionalLights;
};
#endif // QGSLIGHTSWIDGET_H

View File

@ -15,187 +15,349 @@
</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>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</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>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Point lights</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<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 row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<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="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>
<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="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="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="4" column="1">
<widget class="QgsColorButton" name="btnColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<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="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="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Intensity</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="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>X</string>
</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>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Directional lights</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3">
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="spinDirectionZ">
<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="1">
<widget class="QgsColorButton" name="btnDirectionalColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Intensity</string>
</property>
</widget>
</item>
<item row="2" column="0" rowspan="2">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="2" column="1" rowspan="2">
<widget class="QDoubleSpinBox" name="spinDirectionY">
<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">
<widget class="QDoubleSpinBox" name="spinDirectionX">
<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="6" column="1">
<widget class="QDoubleSpinBox" name="spinDirectionalIntensity">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Light direction:</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="btnRemoveDirectionalLight">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QToolButton" name="btnAddDirectionalLight">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="cboDirectionalLights"/>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
@ -208,7 +370,6 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>cboLights</tabstop>
<tabstop>btnAddLight</tabstop>
<tabstop>btnRemoveLight</tabstop>
<tabstop>spinPositionX</tabstop>