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