QGIS API Documentation 3.37.0-Master (4ace69f83af)
Loading...
Searching...
No Matches
qgsphongmaterialsettings.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsphongmaterialsettings.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk 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#include "qgscolorutils.h"
18
19#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
20#include <Qt3DRender/QAttribute>
21#include <Qt3DRender/QBuffer>
22#include <Qt3DRender/QGeometry>
23
24typedef Qt3DRender::QAttribute Qt3DQAttribute;
25typedef Qt3DRender::QBuffer Qt3DQBuffer;
26typedef Qt3DRender::QGeometry Qt3DQGeometry;
27#else
28#include <Qt3DCore/QAttribute>
29#include <Qt3DCore/QBuffer>
30#include <Qt3DCore/QGeometry>
31
32typedef Qt3DCore::QAttribute Qt3DQAttribute;
33typedef Qt3DCore::QBuffer Qt3DQBuffer;
34typedef Qt3DCore::QGeometry Qt3DQGeometry;
35#endif
36#include <Qt3DRender/QParameter>
37#include <Qt3DRender/QEffect>
38#include <Qt3DRender/QTechnique>
39#include <Qt3DRender/QGraphicsApiFilter>
40#include <Qt3DRender/QNoDepthMask>
41#include <Qt3DRender/QBlendEquation>
42#include <Qt3DRender/QBlendEquationArguments>
43#include <QMap>
44
45
47{
48 return QStringLiteral( "phong" );
49}
50
68
73
78
79void QgsPhongMaterialSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
80{
81 mAmbient = QgsColorUtils::colorFromString( elem.attribute( QStringLiteral( "ambient" ), QStringLiteral( "25,25,25" ) ) );
82 mDiffuse = QgsColorUtils::colorFromString( elem.attribute( QStringLiteral( "diffuse" ), QStringLiteral( "178,178,178" ) ) );
83 mSpecular = QgsColorUtils::colorFromString( elem.attribute( QStringLiteral( "specular" ), QStringLiteral( "255,255,255" ) ) );
84 mShininess = elem.attribute( QStringLiteral( "shininess" ) ).toDouble();
85 mOpacity = elem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.0" ) ).toDouble();
86 mAmbientCoefficient = elem.attribute( QStringLiteral( "ka" ), QStringLiteral( "1.0" ) ).toDouble();
87 mDiffuseCoefficient = elem.attribute( QStringLiteral( "kd" ), QStringLiteral( "1.0" ) ).toDouble();
88 mSpecularCoefficient = elem.attribute( QStringLiteral( "ks" ), QStringLiteral( "1.0" ) ).toDouble();
89
91}
92
93void QgsPhongMaterialSettings::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
94{
95 elem.setAttribute( QStringLiteral( "ambient" ), QgsColorUtils::colorToString( mAmbient ) );
96 elem.setAttribute( QStringLiteral( "diffuse" ), QgsColorUtils::colorToString( mDiffuse ) );
97 elem.setAttribute( QStringLiteral( "specular" ), QgsColorUtils::colorToString( mSpecular ) );
98 elem.setAttribute( QStringLiteral( "shininess" ), mShininess );
99 elem.setAttribute( QStringLiteral( "opacity" ), mOpacity );
100 elem.setAttribute( QStringLiteral( "ka" ), mAmbientCoefficient );
101 elem.setAttribute( QStringLiteral( "kd" ), mDiffuseCoefficient );
102 elem.setAttribute( QStringLiteral( "ks" ), mSpecularCoefficient );
103
105}
106
107
109{
110 switch ( technique )
111 {
118 {
119 if ( dataDefinedProperties().hasActiveProperties() )
120 return dataDefinedMaterial();
121 else
122 return constantColorMaterial( context );
123 }
124
126 return nullptr;
127 }
128 return nullptr;
129}
130
132{
133 QMap<QString, QString> parameters;
134 parameters[ QStringLiteral( "Kd" ) ] = QStringLiteral( "%1 %2 %3" ).arg( mDiffuse.redF() ).arg( mDiffuse.greenF() ).arg( mDiffuse.blueF() );
135 parameters[ QStringLiteral( "Ka" ) ] = QStringLiteral( "%1 %2 %3" ).arg( mAmbient.redF() ).arg( mAmbient.greenF() ).arg( mAmbient.blueF() );
136 parameters[ QStringLiteral( "Ks" ) ] = QStringLiteral( "%1 %2 %3" ).arg( mSpecular.redF() ).arg( mSpecular.greenF() ).arg( mSpecular.blueF() );
137 parameters[ QStringLiteral( "Ns" ) ] = QString::number( mShininess );
138 return parameters;
139}
140
141void QgsPhongMaterialSettings::addParametersToEffect( Qt3DRender::QEffect *effect ) const
142{
143 Qt3DRender::QParameter *ambientParameter = new Qt3DRender::QParameter( QStringLiteral( "ambientColor" ),
144 QColor::fromRgbF( mAmbient.redF() * mAmbientCoefficient,
145 mAmbient.greenF() * mAmbientCoefficient,
146 mAmbient.blueF() * mAmbientCoefficient ) );
147 Qt3DRender::QParameter *diffuseParameter = new Qt3DRender::QParameter( QStringLiteral( "diffuseColor" ),
148 QColor::fromRgbF( mDiffuse.redF() * mDiffuseCoefficient,
149 mDiffuse.greenF() * mDiffuseCoefficient,
150 mDiffuse.blueF() * mDiffuseCoefficient ) );
151 Qt3DRender::QParameter *specularParameter = new Qt3DRender::QParameter( QStringLiteral( "specularColor" ),
152 QColor::fromRgbF( mSpecular.redF() * mSpecularCoefficient,
153 mSpecular.greenF() * mSpecularCoefficient,
154 mSpecular.blueF() * mSpecularCoefficient ) );
155 Qt3DRender::QParameter *shininessParameter = new Qt3DRender::QParameter( QStringLiteral( "shininess" ), static_cast< float >( mShininess ) );
156 Qt3DRender::QParameter *opacityParameter = new Qt3DRender::QParameter( QStringLiteral( "opacity" ), static_cast< float >( mOpacity ) );
157
158 effect->addParameter( ambientParameter );
159 effect->addParameter( diffuseParameter );
160 effect->addParameter( specularParameter );
161 effect->addParameter( shininessParameter );
162 effect->addParameter( opacityParameter );
163}
164
166{
167 const QColor ambient = dataDefinedProperties().valueAsColor( QgsAbstractMaterialSettings::Property::Ambient, expressionContext, mAmbient );
168 const QColor diffuse = dataDefinedProperties().valueAsColor( QgsAbstractMaterialSettings::Property::Diffuse, expressionContext, mDiffuse );
169 const QColor specular = dataDefinedProperties().valueAsColor( QgsAbstractMaterialSettings::Property::Specular, expressionContext, mSpecular );
170
171 QByteArray array;
172 if ( mDiffuseCoefficient < 1 || mAmbientCoefficient < 1 || mSpecularCoefficient < 1 )
173 {
174 // use floats if we are adjusting color component strength, bytes don't
175 // give us enough precision
176 array.resize( sizeof( float ) * 9 );
177 float *fptr = reinterpret_cast<float *>( array.data() );
178
179 *fptr++ = static_cast<float>( diffuse.redF() * mDiffuseCoefficient );
180 *fptr++ = static_cast<float>( diffuse.greenF() * mDiffuseCoefficient );
181 *fptr++ = static_cast<float>( diffuse.blueF() * mDiffuseCoefficient );
182
183 *fptr++ = static_cast<float>( ambient.redF() * mAmbientCoefficient );
184 *fptr++ = static_cast<float>( ambient.greenF() * mAmbientCoefficient );
185 *fptr++ = static_cast<float>( ambient.blueF() * mAmbientCoefficient );
186
187 *fptr++ = static_cast<float>( specular.redF() * mSpecularCoefficient );
188 *fptr++ = static_cast<float>( specular.greenF() * mSpecularCoefficient );
189 *fptr++ = static_cast<float>( specular.blueF() * mSpecularCoefficient );
190 }
191 else
192 {
193 array.resize( sizeof( unsigned char ) * 9 );
194 unsigned char *ptr = reinterpret_cast<unsigned char *>( array.data() );
195
196 *ptr++ = static_cast<unsigned char>( diffuse.red() );
197 *ptr++ = static_cast<unsigned char>( diffuse.green() );
198 *ptr++ = static_cast<unsigned char>( diffuse.blue() );
199
200 *ptr++ = static_cast<unsigned char>( ambient.red() );
201 *ptr++ = static_cast<unsigned char>( ambient.green() );
202 *ptr++ = static_cast<unsigned char>( ambient.blue() );
203
204 *ptr++ = static_cast<unsigned char>( specular.red() );
205 *ptr++ = static_cast<unsigned char>( specular.green() );
206 *ptr++ = static_cast<unsigned char>( specular.blue() );
207 }
208
209 return array;
210}
211
212int QgsPhongMaterialSettings::dataDefinedByteStride() const {return 9 * sizeof( unsigned char );}
213
214void QgsPhongMaterialSettings::applyDataDefinedToGeometry( Qt3DQGeometry *geometry, int vertexCount, const QByteArray &data ) const
215{
216 Qt3DQBuffer *dataBuffer = new Qt3DQBuffer( geometry );
217
218 // use floats if we are adjusting color component strength, bytes don't
219 // give us enough precision
220 const bool useFloats = mDiffuseCoefficient < 1 || mAmbientCoefficient < 1 || mSpecularCoefficient < 1;
221
222 Qt3DQAttribute *diffuseAttribute = new Qt3DQAttribute( geometry );
223 diffuseAttribute->setName( QStringLiteral( "dataDefinedDiffuseColor" ) );
224 diffuseAttribute->setVertexBaseType( useFloats ? Qt3DQAttribute::Float : Qt3DQAttribute::UnsignedByte );
225 diffuseAttribute->setVertexSize( 3 );
226 diffuseAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
227 diffuseAttribute->setBuffer( dataBuffer );
228 diffuseAttribute->setByteStride( 9 * ( useFloats ? sizeof( float ) : sizeof( unsigned char ) ) );
229 diffuseAttribute->setByteOffset( 0 );
230 diffuseAttribute->setCount( vertexCount );
231 geometry->addAttribute( diffuseAttribute );
232
233 Qt3DQAttribute *ambientAttribute = new Qt3DQAttribute( geometry );
234 ambientAttribute->setName( QStringLiteral( "dataDefinedAmbiantColor" ) );
235 ambientAttribute->setVertexBaseType( useFloats ? Qt3DQAttribute::Float : Qt3DQAttribute::UnsignedByte );
236 ambientAttribute->setVertexSize( 3 );
237 ambientAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
238 ambientAttribute->setBuffer( dataBuffer );
239 ambientAttribute->setByteStride( 9 * ( useFloats ? sizeof( float ) : sizeof( unsigned char ) ) );
240 ambientAttribute->setByteOffset( 3 * ( useFloats ? sizeof( float ) : sizeof( unsigned char ) ) );
241 ambientAttribute->setCount( vertexCount );
242 geometry->addAttribute( ambientAttribute );
243
244 Qt3DQAttribute *specularAttribute = new Qt3DQAttribute( geometry );
245 specularAttribute->setName( QStringLiteral( "dataDefinedSpecularColor" ) );
246 specularAttribute->setVertexBaseType( useFloats ? Qt3DQAttribute::Float : Qt3DQAttribute::UnsignedByte );
247 specularAttribute->setVertexSize( 3 );
248 specularAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
249 specularAttribute->setBuffer( dataBuffer );
250 specularAttribute->setByteStride( 9 * ( useFloats ? sizeof( float ) : sizeof( unsigned char ) ) );
251 specularAttribute->setByteOffset( 6 * ( useFloats ? sizeof( float ) : sizeof( unsigned char ) ) );
252 specularAttribute->setCount( vertexCount );
253 geometry->addAttribute( specularAttribute );
254
255 dataBuffer->setData( data );
256}
257
258Qt3DRender::QMaterial *QgsPhongMaterialSettings::constantColorMaterial( const QgsMaterialContext &context ) const
259{
260 Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
261
262 Qt3DRender::QEffect *eff = new Qt3DRender::QEffect( material );
263
264 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
265 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
266 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
267 technique->graphicsApiFilter()->setMajorVersion( 3 );
268 technique->graphicsApiFilter()->setMinorVersion( 3 );
269 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey();
270 filterKey->setName( QStringLiteral( "renderingStyle" ) );
271 filterKey->setValue( QStringLiteral( "forward" ) );
272 technique->addFilterKey( filterKey );
273
274 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass();
275 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram();
276
277 //Load shader programs
278 const QUrl urlVert( QStringLiteral( "qrc:/shaders/phongConstant.vert" ) );
279 shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Vertex, Qt3DRender::QShaderProgram::loadSource( urlVert ) );
280 const QUrl urlFrag( QStringLiteral( "qrc:/shaders/phongConstant.frag" ) );
281 shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Fragment, Qt3DRender::QShaderProgram::loadSource( urlFrag ) );
282
283 renderPass->setShaderProgram( shaderProgram );
284 technique->addRenderPass( renderPass );
285
286 const QColor ambient = context.isSelected() ? context.selectionColor().darker() : mAmbient;
287 const QColor diffuse = context.isSelected() ? context.selectionColor() : mDiffuse;
288
289 eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "shininess" ), static_cast< float >( mShininess ) ) );
290 eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "opacity" ), static_cast< float >( mOpacity ) ) );
291 eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ambientColor" ),
292 QColor::fromRgbF( ambient.redF() * mAmbientCoefficient,
293 ambient.greenF() * mAmbientCoefficient,
294 ambient.blueF() * mAmbientCoefficient ) ) );
295 eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "diffuseColor" ),
296 QColor::fromRgbF( diffuse.redF() * mDiffuseCoefficient,
297 diffuse.greenF() * mDiffuseCoefficient,
298 diffuse.blueF() * mDiffuseCoefficient ) ) );
299 eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "specularColor" ),
300 QColor::fromRgbF( mSpecular.redF() * mSpecularCoefficient,
301 mSpecular.greenF() * mSpecularCoefficient,
302 mSpecular.blueF() * mSpecularCoefficient ) ) );
303
304 if ( mOpacity < 1.0f )
305 {
306 Qt3DRender::QNoDepthMask *noDepthMask = new Qt3DRender::QNoDepthMask( renderPass );
307
308 Qt3DRender::QBlendEquationArguments *blendState = new Qt3DRender::QBlendEquationArguments( renderPass );
309 blendState->setSourceRgb( Qt3DRender::QBlendEquationArguments::SourceAlpha );
310 blendState->setDestinationRgb( Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha );
311
312 Qt3DRender::QBlendEquation *blendEquation = new Qt3DRender::QBlendEquation( renderPass );
313 blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
314
315 renderPass->addRenderState( noDepthMask );
316 renderPass->addRenderState( blendState );
317 renderPass->addRenderState( blendEquation );
318 }
319
320 eff->addTechnique( technique );
321 material->setEffect( eff );
322
323 return material;
324}
325
326Qt3DRender::QMaterial *QgsPhongMaterialSettings::dataDefinedMaterial() const
327{
328 Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
329
330 Qt3DRender::QEffect *eff = new Qt3DRender::QEffect( material );
331
332 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
333 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
334 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
335 technique->graphicsApiFilter()->setMajorVersion( 3 );
336 technique->graphicsApiFilter()->setMinorVersion( 3 );
337 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey();
338 filterKey->setName( QStringLiteral( "renderingStyle" ) );
339 filterKey->setValue( QStringLiteral( "forward" ) );
340 technique->addFilterKey( filterKey );
341
342 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass();
343 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram();
344
345 //Load shader programs
346 const QUrl urlVert( QStringLiteral( "qrc:/shaders/phongDataDefined.vert" ) );
347 shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Vertex, Qt3DRender::QShaderProgram::loadSource( urlVert ) );
348 const QUrl urlFrag( QStringLiteral( "qrc:/shaders/phongDataDefined.frag" ) );
349 shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Fragment, Qt3DRender::QShaderProgram::loadSource( urlFrag ) );
350
351 renderPass->setShaderProgram( shaderProgram );
352 technique->addRenderPass( renderPass );
353
354 eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "shininess" ), static_cast< float >( mShininess ) ) );
355 eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "opacity" ), static_cast< float >( mOpacity ) ) );
356
357 if ( mOpacity < 1.0f )
358 {
359 Qt3DRender::QNoDepthMask *noDepthMask = new Qt3DRender::QNoDepthMask( renderPass );
360
361 Qt3DRender::QBlendEquationArguments *blendState = new Qt3DRender::QBlendEquationArguments( renderPass );
362 blendState->setSourceRgb( Qt3DRender::QBlendEquationArguments::SourceAlpha );
363 blendState->setDestinationRgb( Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha );
364
365 Qt3DRender::QBlendEquation *blendEquation = new Qt3DRender::QBlendEquation( renderPass );
366 blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
367
368 renderPass->addRenderState( noDepthMask );
369 renderPass->addRenderState( blendState );
370 renderPass->addRenderState( blendEquation );
371 }
372
373 eff->addTechnique( technique );
374 material->setEffect( eff );
375
376 return material;
377}
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.
@ Ambient
Ambient color (phong material)
QgsPropertyCollection dataDefinedProperties() const
Returns the symbol material property collection, used for data defined overrides.
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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.
int dataDefinedByteStride() const override
Returns byte stride of the data defined colors,used to fill the vertex colors data defined buffer for...
Qt3DRender::QMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const override
Creates a new QMaterial object representing the material settings.
void addParametersToEffect(Qt3DRender::QEffect *effect) const override
Adds parameters from the material to a destination effect.
QString type() const override
Returns the unique type name for the material.
QColor diffuse() const
Returns diffuse color component.
QMap< QString, QString > toExportParameters() const override
Returns the parameters to be exported to .mtl file.
void applyDataDefinedToGeometry(Qt3DCore::QGeometry *geometry, int vertexCount, const QByteArray &data) const override
Applies the data defined bytes, dataDefinedBytes, on the geometry by filling a specific vertex buffer...
QColor specular() const
Returns specular color component.
QColor ambient() const
Returns ambient color component.
static QgsAbstractMaterialSettings * create()
Returns a new instance of QgsPhongMaterialSettings.
static bool supportsTechnique(QgsMaterialSettingsRenderingTechnique technique)
Returns true if the specified technique is supported by the Phong material.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const override
Writes settings to a DOM element.
QgsPhongMaterialSettings * clone() const override
Clones the material settings.
QgsPhongMaterialSettings()=default
Constructor for QgsPhongMaterialSettings.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads settings from a DOM element.
QByteArray dataDefinedVertexColorsAsByte(const QgsExpressionContext &expressionContext) const override
Returns byte array corresponding to the data defined colors depending of the expressionContext,...
The class is used as a container of context for various read/write operations on other objects.
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)
Qt3DCore::QAttribute Qt3DQAttribute
Definition qgs3daxis.cpp:28
Qt3DCore::QBuffer Qt3DQBuffer
Definition qgs3daxis.cpp:30
Qt3DCore::QGeometry Qt3DQGeometry
Definition qgs3daxis.cpp:29
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QGeometry Qt3DQGeometry