QGIS API Documentation 3.39.0-Master (d85f3c2a281)
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/QEffect>
24#include <Qt3DRender/QShaderProgramBuilder>
25#include <Qt3DRender/QGraphicsApiFilter>
26
28QgsMetalRoughMaterial::QgsMetalRoughMaterial( QNode *parent )
29 : QMaterial( 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,
205 this, &QgsMetalRoughMaterial::baseColorChanged );
206 QObject::connect( mMetalnessParameter, &Qt3DRender::QParameter::valueChanged,
207 this, &QgsMetalRoughMaterial::metalnessChanged );
208 QObject::connect( mRoughnessParameter, &Qt3DRender::QParameter::valueChanged,
209 this, &QgsMetalRoughMaterial::roughnessChanged );
210 QObject::connect( mAmbientOcclusionMapParameter, &Qt3DRender::QParameter::valueChanged,
211 this, &QgsMetalRoughMaterial::ambientOcclusionChanged );
212 QObject::connect( mNormalMapParameter, &Qt3DRender::QParameter::valueChanged,
213 this, &QgsMetalRoughMaterial::normalChanged );
214 connect( mTextureScaleParameter, &Qt3DRender::QParameter::valueChanged,
215 this, &QgsMetalRoughMaterial::handleTextureScaleChanged );
216
217 mMetalRoughGL3Shader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/default.vert" ) ) ) );
218
219 updateFragmentShader();
220
221 mMetalRoughGL3Technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
222 mMetalRoughGL3Technique->graphicsApiFilter()->setMajorVersion( 3 );
223 mMetalRoughGL3Technique->graphicsApiFilter()->setMinorVersion( 1 );
224 mMetalRoughGL3Technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
225
226 mFilterKey->setParent( this );
227 mFilterKey->setName( QStringLiteral( "renderingStyle" ) );
228 mFilterKey->setValue( QStringLiteral( "forward" ) );
229
230 mMetalRoughGL3Technique->addFilterKey( mFilterKey );
231 mMetalRoughGL3RenderPass->setShaderProgram( mMetalRoughGL3Shader );
232 mMetalRoughGL3Technique->addRenderPass( mMetalRoughGL3RenderPass );
233 mMetalRoughEffect->addTechnique( mMetalRoughGL3Technique );
234
235 // Given parameters a parent
236 mBaseColorMapParameter->setParent( mMetalRoughEffect );
237 mMetalnessMapParameter->setParent( mMetalRoughEffect );
238 mRoughnessMapParameter->setParent( mMetalRoughEffect );
239
240 mMetalRoughEffect->addParameter( mBaseColorParameter );
241 mMetalRoughEffect->addParameter( mMetalnessParameter );
242 mMetalRoughEffect->addParameter( mRoughnessParameter );
243 mMetalRoughEffect->addParameter( mTextureScaleParameter );
244
245 setEffect( mMetalRoughEffect );
246}
247
248void QgsMetalRoughMaterial::updateFragmentShader()
249{
250 // pre-process fragment shader and add #defines based on whether using maps for some properties
251 QByteArray fragmentShaderCode = Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/metalrough.frag" ) ) );
252 QStringList defines;
253 if ( mUsingBaseColorMap )
254 defines += "BASE_COLOR_MAP";
255 if ( mUsingMetalnessMap )
256 defines += "METALNESS_MAP";
257 if ( mUsingRoughnessMap )
258 defines += "ROUGHNESS_MAP";
259 if ( mUsingAmbientOcclusionMap )
260 defines += "AMBIENT_OCCLUSION_MAP";
261 if ( mUsingNormalMap )
262 defines += "NORMAL_MAP";
263
264 if ( mFlatShading )
265 defines += "FLAT_SHADING";
266
267 QByteArray finalShaderCode = Qgs3DUtils::addDefinesToShaderCode( fragmentShaderCode, defines );
268 mMetalRoughGL3Shader->setFragmentShaderCode( finalShaderCode );
269}
270
271void QgsMetalRoughMaterial::handleTextureScaleChanged( const QVariant &var )
272{
273 emit textureScaleChanged( var.toFloat() );
274}
275
276bool QgsMetalRoughMaterial::flatShadingEnabled() const
277{
278 return mFlatShading;
279}
280
281void QgsMetalRoughMaterial::setFlatShadingEnabled( bool enabled )
282{
283 if ( enabled != mFlatShading )
284 {
285 mFlatShading = enabled;
286 updateFragmentShader();
287 }
288}
289
static QByteArray addDefinesToShaderCode(const QByteArray &shaderCode, const QStringList &defines)
Inserts some define macros into a shader source code.