QGIS API Documentation 3.40.0-Bratislava (b56115d8743)
Loading...
Searching...
No Matches
qgsmetalroughmaterial.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmetalroughmaterial.cpp
3 --------------------------------------
4 Date : December 2023
5 Copyright : (C) 2023 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#include "qgs3dutils.h"
18#include <Qt3DRender/QParameter>
19#include <Qt3DRender/QRenderPass>
20#include <Qt3DRender/QTechnique>
21#include <Qt3DRender/QTexture>
22#include <Qt3DRender/QAbstractTexture>
23#include <Qt3DRender/QShaderProgramBuilder>
24#include <Qt3DRender/QGraphicsApiFilter>
25
27QgsMetalRoughMaterial::QgsMetalRoughMaterial( QNode *parent )
28 : QgsMaterial( parent )
29 , mBaseColorParameter( new Qt3DRender::QParameter( QStringLiteral( "baseColor" ), QColor( "grey" ), this ) )
30 , mMetalnessParameter( new Qt3DRender::QParameter( QStringLiteral( "metalness" ), 0.0f, this ) )
31 , mRoughnessParameter( new Qt3DRender::QParameter( QStringLiteral( "roughness" ), 0.0f, this ) )
32 , mBaseColorMapParameter( new Qt3DRender::QParameter( QStringLiteral( "baseColorMap" ), QVariant(), this ) )
33 , mMetalnessMapParameter( new Qt3DRender::QParameter( QStringLiteral( "metalnessMap" ), QVariant(), this ) )
34 , mRoughnessMapParameter( new Qt3DRender::QParameter( QStringLiteral( "roughnessMap" ), QVariant(), this ) )
35 , mAmbientOcclusionMapParameter( new Qt3DRender::QParameter( QStringLiteral( "ambientOcclusionMap" ), QVariant(), this ) )
36 , mNormalMapParameter( new Qt3DRender::QParameter( QStringLiteral( "normalMap" ), QVariant(), this ) )
37 , mTextureScaleParameter( new Qt3DRender::QParameter( QStringLiteral( "texCoordScale" ), 1.0f, this ) )
38 , mMetalRoughEffect( new Qt3DRender::QEffect( this ) )
39 , mMetalRoughGL3Technique( new Qt3DRender::QTechnique( this ) )
40 , mMetalRoughGL3RenderPass( new Qt3DRender::QRenderPass( this ) )
41 , mMetalRoughGL3Shader( new Qt3DRender::QShaderProgram( this ) )
42 , mFilterKey( new Qt3DRender::QFilterKey( this ) )
43{
44 init();
45}
46
47QgsMetalRoughMaterial::~QgsMetalRoughMaterial() = default;
48
49QVariant QgsMetalRoughMaterial::baseColor() const
50{
51 return mBaseColorParameter->value();
52}
53
54QVariant QgsMetalRoughMaterial::metalness() const
55{
56 return mMetalnessParameter->value();
57}
58
59QVariant QgsMetalRoughMaterial::roughness() const
60{
61 return mRoughnessParameter->value();
62}
63
64QVariant QgsMetalRoughMaterial::ambientOcclusion() const
65{
66 return mAmbientOcclusionMapParameter->value();
67}
68
69QVariant QgsMetalRoughMaterial::normal() const
70{
71 return mNormalMapParameter->value();
72}
73
74float QgsMetalRoughMaterial::textureScale() const
75{
76 return mTextureScaleParameter->value().toFloat();
77}
78
79void QgsMetalRoughMaterial::setBaseColor( const QVariant &baseColor )
80{
81 mBaseColorParameter->setValue( baseColor );
82 mBaseColorMapParameter->setValue( baseColor );
83 bool oldUsingBaseColorMap = mUsingBaseColorMap;
84
85 if ( baseColor.value<Qt3DRender::QAbstractTexture *>() )
86 {
87 mUsingBaseColorMap = true;
88 mMetalRoughEffect->addParameter( mBaseColorMapParameter );
89 if ( mMetalRoughEffect->parameters().contains( mBaseColorParameter ) )
90 mMetalRoughEffect->removeParameter( mBaseColorParameter );
91 }
92 else
93 {
94 mUsingBaseColorMap = false;
95 if ( mMetalRoughEffect->parameters().contains( mBaseColorMapParameter ) )
96 mMetalRoughEffect->removeParameter( mBaseColorMapParameter );
97 mMetalRoughEffect->addParameter( mBaseColorParameter );
98 }
99
100 if ( oldUsingBaseColorMap != mUsingBaseColorMap )
101 updateFragmentShader();
102}
103
104void QgsMetalRoughMaterial::setMetalness( const QVariant &metalness )
105{
106 mMetalnessParameter->setValue( metalness );
107 mMetalnessMapParameter->setValue( metalness );
108 bool oldUsingMetalnessMap = mUsingMetalnessMap;
109
110 if ( metalness.value<Qt3DRender::QAbstractTexture *>() )
111 {
112 mUsingMetalnessMap = true;
113 mMetalRoughEffect->addParameter( mMetalnessMapParameter );
114 if ( mMetalRoughEffect->parameters().contains( mMetalnessParameter ) )
115 mMetalRoughEffect->removeParameter( mMetalnessParameter );
116 }
117 else
118 {
119 mUsingMetalnessMap = false;
120 if ( mMetalRoughEffect->parameters().contains( mMetalnessMapParameter ) )
121 mMetalRoughEffect->removeParameter( mMetalnessMapParameter );
122 mMetalRoughEffect->addParameter( mMetalnessParameter );
123 }
124
125 if ( oldUsingMetalnessMap != mUsingMetalnessMap )
126 updateFragmentShader();
127}
128
129void QgsMetalRoughMaterial::setRoughness( const QVariant &roughness )
130{
131 mRoughnessParameter->setValue( roughness );
132 mRoughnessMapParameter->setValue( roughness );
133 bool oldUsingRoughnessMap = mUsingRoughnessMap;
134
135 if ( roughness.value<Qt3DRender::QAbstractTexture *>() )
136 {
137 mUsingRoughnessMap = true;
138 mMetalRoughEffect->addParameter( mRoughnessMapParameter );
139 if ( mMetalRoughEffect->parameters().contains( mRoughnessParameter ) )
140 mMetalRoughEffect->removeParameter( mRoughnessParameter );
141 }
142 else
143 {
144 mUsingRoughnessMap = false;
145 if ( mMetalRoughEffect->parameters().contains( mRoughnessMapParameter ) )
146 mMetalRoughEffect->removeParameter( mRoughnessMapParameter );
147 mMetalRoughEffect->addParameter( mRoughnessParameter );
148 }
149
150 if ( oldUsingRoughnessMap != mUsingRoughnessMap )
151 updateFragmentShader();
152}
153
154void QgsMetalRoughMaterial::setAmbientOcclusion( const QVariant &ambientOcclusion )
155{
156 mAmbientOcclusionMapParameter->setValue( ambientOcclusion );
157 bool oldUsingAmbientOcclusionMap = mUsingAmbientOcclusionMap;
158
159 if ( ambientOcclusion.value<Qt3DRender::QAbstractTexture *>() )
160 {
161 mUsingAmbientOcclusionMap = true;
162 mMetalRoughEffect->addParameter( mAmbientOcclusionMapParameter );
163 }
164 else
165 {
166 mUsingAmbientOcclusionMap = false;
167 if ( mMetalRoughEffect->parameters().contains( mAmbientOcclusionMapParameter ) )
168 mMetalRoughEffect->removeParameter( mAmbientOcclusionMapParameter );
169 }
170
171 if ( oldUsingAmbientOcclusionMap != mUsingAmbientOcclusionMap )
172 updateFragmentShader();
173}
174
175void QgsMetalRoughMaterial::setNormal( const QVariant &normal )
176{
177 mNormalMapParameter->setValue( normal );
178 bool oldUsingNormalMap = mUsingNormalMap;
179
180 if ( normal.value<Qt3DRender::QAbstractTexture *>() )
181 {
182 mUsingNormalMap = true;
183 mMetalRoughEffect->addParameter( mNormalMapParameter );
184 }
185 else
186 {
187 mUsingNormalMap = false;
188 if ( mMetalRoughEffect->parameters().contains( mNormalMapParameter ) )
189 mMetalRoughEffect->removeParameter( mNormalMapParameter );
190 }
191
192 if ( oldUsingNormalMap != mUsingNormalMap )
193 updateFragmentShader();
194}
195
196void QgsMetalRoughMaterial::setTextureScale( float textureScale )
197{
198 mTextureScaleParameter->setValue( textureScale );
199}
200
201void QgsMetalRoughMaterial::init()
202{
203 QObject::connect( mBaseColorParameter, &Qt3DRender::QParameter::valueChanged,
204 this, &QgsMetalRoughMaterial::baseColorChanged );
205 QObject::connect( mMetalnessParameter, &Qt3DRender::QParameter::valueChanged,
206 this, &QgsMetalRoughMaterial::metalnessChanged );
207 QObject::connect( mRoughnessParameter, &Qt3DRender::QParameter::valueChanged,
208 this, &QgsMetalRoughMaterial::roughnessChanged );
209 QObject::connect( mAmbientOcclusionMapParameter, &Qt3DRender::QParameter::valueChanged,
210 this, &QgsMetalRoughMaterial::ambientOcclusionChanged );
211 QObject::connect( mNormalMapParameter, &Qt3DRender::QParameter::valueChanged,
212 this, &QgsMetalRoughMaterial::normalChanged );
213 connect( mTextureScaleParameter, &Qt3DRender::QParameter::valueChanged,
214 this, &QgsMetalRoughMaterial::handleTextureScaleChanged );
215
216 mMetalRoughGL3Shader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/default.vert" ) ) ) );
217
218 updateFragmentShader();
219
220 mMetalRoughGL3Technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
221 mMetalRoughGL3Technique->graphicsApiFilter()->setMajorVersion( 3 );
222 mMetalRoughGL3Technique->graphicsApiFilter()->setMinorVersion( 1 );
223 mMetalRoughGL3Technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
224
225 mFilterKey->setParent( this );
226 mFilterKey->setName( QStringLiteral( "renderingStyle" ) );
227 mFilterKey->setValue( QStringLiteral( "forward" ) );
228
229 mMetalRoughGL3Technique->addFilterKey( mFilterKey );
230 mMetalRoughGL3RenderPass->setShaderProgram( mMetalRoughGL3Shader );
231 mMetalRoughGL3Technique->addRenderPass( mMetalRoughGL3RenderPass );
232 mMetalRoughEffect->addTechnique( mMetalRoughGL3Technique );
233
234 // Given parameters a parent
235 mBaseColorMapParameter->setParent( mMetalRoughEffect );
236 mMetalnessMapParameter->setParent( mMetalRoughEffect );
237 mRoughnessMapParameter->setParent( mMetalRoughEffect );
238
239 mMetalRoughEffect->addParameter( mBaseColorParameter );
240 mMetalRoughEffect->addParameter( mMetalnessParameter );
241 mMetalRoughEffect->addParameter( mRoughnessParameter );
242 mMetalRoughEffect->addParameter( mTextureScaleParameter );
243
244 setEffect( mMetalRoughEffect );
245}
246
247void QgsMetalRoughMaterial::updateFragmentShader()
248{
249 // pre-process fragment shader and add #defines based on whether using maps for some properties
250 QByteArray fragmentShaderCode = Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/metalrough.frag" ) ) );
251 QStringList defines;
252 if ( mUsingBaseColorMap )
253 defines += "BASE_COLOR_MAP";
254 if ( mUsingMetalnessMap )
255 defines += "METALNESS_MAP";
256 if ( mUsingRoughnessMap )
257 defines += "ROUGHNESS_MAP";
258 if ( mUsingAmbientOcclusionMap )
259 defines += "AMBIENT_OCCLUSION_MAP";
260 if ( mUsingNormalMap )
261 defines += "NORMAL_MAP";
262
263 if ( mFlatShading )
264 defines += "FLAT_SHADING";
265
266 QByteArray finalShaderCode = Qgs3DUtils::addDefinesToShaderCode( fragmentShaderCode, defines );
267 mMetalRoughGL3Shader->setFragmentShaderCode( finalShaderCode );
268}
269
270void QgsMetalRoughMaterial::handleTextureScaleChanged( const QVariant &var )
271{
272 emit textureScaleChanged( var.toFloat() );
273}
274
275bool QgsMetalRoughMaterial::flatShadingEnabled() const
276{
277 return mFlatShading;
278}
279
280void QgsMetalRoughMaterial::setFlatShadingEnabled( bool enabled )
281{
282 if ( enabled != mFlatShading )
283 {
284 mFlatShading = enabled;
285 updateFragmentShader();
286 }
287}
288
static QByteArray addDefinesToShaderCode(const QByteArray &shaderCode, const QStringList &defines)
Inserts some define macros into a shader source code.