QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
qgsphongtexturedmaterialsettings.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsphongtexturedmaterialsettings.cpp
3 --------------------------------------
4 Date : August 2020
5 Copyright : (C) 2020 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgssymbollayerutils.h"
19#include "qgsapplication.h"
20#include "qgsimagecache.h"
21#include "qgsimagetexture.h"
23#include <Qt3DRender/QPaintedTextureImage>
24#include <Qt3DRender/QTexture>
25#include <Qt3DRender/QParameter>
26#include <Qt3DRender/QEffect>
27#include <Qt3DRender/QTechnique>
28#include <Qt3DRender/QGraphicsApiFilter>
29#include <QMap>
30
31
33{
34 return QStringLiteral( "phongtextured" );
35}
36
38{
39 switch ( technique )
40 {
42 case QgsMaterialSettingsRenderingTechnique::TrianglesDataDefined: //technique is supported but color can't be datadefined
43 return true;
44
50 return false;
51 }
52 return false;
53}
54
56{
58}
59
61{
62 return new QgsPhongTexturedMaterialSettings( *this );
63}
64
66{
67 return mTextureRotation;
68}
69
70void QgsPhongTexturedMaterialSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
71{
72 mAmbient = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "ambient" ), QStringLiteral( "25,25,25" ) ) );
73 mSpecular = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "specular" ), QStringLiteral( "255,255,255" ) ) );
74 mShininess = elem.attribute( QStringLiteral( "shininess" ) ).toFloat();
75 mOpacity = elem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.0" ) ).toFloat();
76 mDiffuseTexturePath = elem.attribute( QStringLiteral( "diffuse_texture_path" ), QString() );
77 mTextureScale = elem.attribute( QStringLiteral( "texture_scale" ), QString( "1.0" ) ).toFloat();
78 mTextureRotation = elem.attribute( QStringLiteral( "texture-rotation" ), QString( "0.0" ) ).toFloat();
79
81}
82
83void QgsPhongTexturedMaterialSettings::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
84{
85 elem.setAttribute( QStringLiteral( "ambient" ), QgsSymbolLayerUtils::encodeColor( mAmbient ) );
86 elem.setAttribute( QStringLiteral( "specular" ), QgsSymbolLayerUtils::encodeColor( mSpecular ) );
87 elem.setAttribute( QStringLiteral( "shininess" ), mShininess );
88 elem.setAttribute( QStringLiteral( "opacity" ), mOpacity );
89 elem.setAttribute( QStringLiteral( "diffuse_texture_path" ), mDiffuseTexturePath );
90 elem.setAttribute( QStringLiteral( "texture_scale" ), mTextureScale );
91 elem.setAttribute( QStringLiteral( "texture-rotation" ), mTextureRotation );
92
94}
95
97{
98 switch ( technique )
99 {
106 {
107 bool fitsInCache = false;
108 const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( mDiffuseTexturePath, QSize(), true, 1.0, fitsInCache );
109 ( void )fitsInCache;
110
111 // No texture image was provided.
112 // Fallback to QgsPhongMaterialSettings.
113 if ( textureSourceImage.isNull() )
114 {
116 phongSettings.setAmbient( mAmbient );
117 phongSettings.setDiffuse( QColor::fromRgbF( 0.7f, 0.7f, 0.7f, 1.0f ) ); // default diffuse color from QDiffuseSpecularMaterial
118 phongSettings.setOpacity( mOpacity );
119 phongSettings.setShininess( mShininess );
120 phongSettings.setSpecular( mSpecular );
121 Qt3DRender::QMaterial *material = phongSettings.toMaterial( technique, context );
122 return material;
123 }
124
125 // Use a custom material because Qt3DRender::QTexture2D does not handle opacity.
126 Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
127
128 Qt3DRender::QEffect *effect = new Qt3DRender::QEffect( material );
129
130 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
131 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
132 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
133 technique->graphicsApiFilter()->setMajorVersion( 3 );
134 technique->graphicsApiFilter()->setMinorVersion( 3 );
135 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey();
136 filterKey->setName( QStringLiteral( "renderingStyle" ) );
137 filterKey->setValue( QStringLiteral( "forward" ) );
138 technique->addFilterKey( filterKey );
139
140 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass();
141 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram();
142
143 //Load shader programs
144 const QUrl urlVert( QStringLiteral( "qrc:/shaders/diffuseSpecular.vert" ) );
145 shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Vertex, Qt3DRender::QShaderProgram::loadSource( urlVert ) );
146 const QUrl urlFrag( QStringLiteral( "qrc:/shaders/diffuseSpecular.frag" ) );
147 shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Fragment, Qt3DRender::QShaderProgram::loadSource( urlFrag ) );
148
149 renderPass->setShaderProgram( shaderProgram );
150 technique->addRenderPass( renderPass );
151
152 int opacity = mOpacity * 255;
153 QColor ambient = context.isSelected() ? context.selectionColor().darker() : mAmbient;
154 effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ka" ), QColor( ambient.red(), ambient.green(), ambient.blue(), opacity ) ) );
155 effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ks" ), QColor( mSpecular.red(), mSpecular.green(), mSpecular.blue(), opacity ) ) );
156 effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "shininess" ), mShininess ) );
157 effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "opacity" ), mOpacity ) );
158
159 // TODO : if ( context.isSelected() ) dampen the color of diffuse texture
160 // with context.map().selectionColor()
161 QgsImageTexture *textureImage = new QgsImageTexture( textureSourceImage );
162 Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D();
163 texture->addTextureImage( textureImage );
164
165 texture->wrapMode()->setX( Qt3DRender::QTextureWrapMode::Repeat );
166 texture->wrapMode()->setY( Qt3DRender::QTextureWrapMode::Repeat );
167 texture->wrapMode()->setZ( Qt3DRender::QTextureWrapMode::Repeat );
168
169 texture->setSamples( 4 );
170
171 texture->setGenerateMipMaps( true );
172 texture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
173 texture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
174
175 effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "diffuseTexture" ), QVariant::fromValue( texture ) ) );
176 effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "texCoordScale" ), mTextureScale ) );
177
178 effect->addTechnique( technique );
179 material->setEffect( effect );
180 return material;
181 }
182
184 return nullptr;
185
186 }
187 return nullptr;
188}
189
191{
192 QMap<QString, QString> parameters;
193 parameters[ QStringLiteral( "Ka" ) ] = QStringLiteral( "%1 %2 %3" ).arg( mAmbient.redF() ).arg( mAmbient.greenF() ).arg( mAmbient.blueF() );
194 parameters[ QStringLiteral( "Ks" ) ] = QStringLiteral( "%1 %2 %3" ).arg( mSpecular.redF() ).arg( mSpecular.greenF() ).arg( mSpecular.blueF() );
195 parameters[ QStringLiteral( "Ns" ) ] = QString::number( mShininess );
196 return parameters;
197}
198
199void QgsPhongTexturedMaterialSettings::addParametersToEffect( Qt3DRender::QEffect *effect ) const
200{
201 Qt3DRender::QParameter *ambientParameter = new Qt3DRender::QParameter( QStringLiteral( "ka" ), QColor::fromRgbF( 0.05f, 0.05f, 0.05f, 1.0f ) );
202 Qt3DRender::QParameter *specularParameter = new Qt3DRender::QParameter( QStringLiteral( "ks" ), QColor::fromRgbF( 0.01f, 0.01f, 0.01f, 1.0f ) );
203 Qt3DRender::QParameter *shininessParameter = new Qt3DRender::QParameter( QStringLiteral( "shininess" ), 150.0f );
204
205 ambientParameter->setValue( mAmbient );
206 specularParameter->setValue( mSpecular );
207 shininessParameter->setValue( mShininess );
208
209 effect->addParameter( ambientParameter );
210 effect->addParameter( specularParameter );
211 effect->addParameter( shininessParameter );
212}
virtual void writeXml(QDomElement &element, const QgsReadWriteContext &) const
Writes settings to a DOM element.
virtual void readXml(const QDomElement &element, const QgsReadWriteContext &)
Reads settings from a DOM element.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
Holds an image that can be used as a texture in the 3D view.
QColor selectionColor() const
Returns the color for representing materials in a selected state.
bool isSelected() const
Returns true if the material should represent a selected state.
void setDiffuse(const QColor &diffuse)
Sets diffuse color component.
Qt3DRender::QMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const override
Creates a new QMaterial object representing the material settings.
void setOpacity(float opacity)
Sets opacity of the surface.
void setAmbient(const QColor &ambient)
Sets ambient color component.
void setShininess(float shininess)
Sets shininess of the surface.
void setSpecular(const QColor &specular)
Sets specular color component.
QgsPhongTexturedMaterialSettings()=default
Constructor for QgsPhongTexturedMaterialSettings.
void addParametersToEffect(Qt3DRender::QEffect *effect) const override
Adds parameters from the material to a destination effect.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const override
Writes settings to a DOM element.
float textureRotation() const
Returns the texture rotation, in degrees.
QString type() const override
Returns the unique type name for the material.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads settings from a DOM element.
static bool supportsTechnique(QgsMaterialSettingsRenderingTechnique technique)
Returns true if the specified technique is supported by the Phong material.
QgsPhongTexturedMaterialSettings * clone() const override
Clones the material settings.
static QgsAbstractMaterialSettings * create()
Returns a new instance of QgsPhongTexturedMaterialSettings.
QMap< QString, QString > toExportParameters() const override
Returns the parameters to be exported to .mtl file.
QColor ambient() const
Returns ambient color component.
float opacity() const
Returns the opacity of the surface.
Qt3DRender::QMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const override
Creates a new QMaterial object representing the material settings.
The class is used as a container of context for various read/write operations on other objects.
static QColor decodeColor(const QString &str)
static QString encodeColor(const QColor &color)
QgsMaterialSettingsRenderingTechnique
Material rendering techniques 3.
@ Points
Point based rendering, requires point data.
@ Triangles
Triangle based rendering (default)
@ TrianglesFromModel
Triangle based rendering, using a model object source.
@ Lines
Line based rendering, requires line data.
@ TrianglesDataDefined
Triangle based rendering with possibility of datadefined color.
@ InstancedPoints
Instanced based rendering, requiring triangles and point data.
@ TrianglesWithFixedTexture
Triangle based rendering, using a fixed, non-user-configurable texture (e.g. for terrain rendering)