1/****************************************************************************
2**
3** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qmetalroughmaterial.h"
41#include "qmetalroughmaterial_p.h"
42#include <Qt3DRender/qfilterkey.h>
43#include <Qt3DRender/qmaterial.h>
44#include <Qt3DRender/qeffect.h>
45#include <Qt3DRender/qtexture.h>
46#include <Qt3DRender/qtechnique.h>
47#include <Qt3DRender/qshaderprogram.h>
48#include <Qt3DRender/qshaderprogrambuilder.h>
49#include <Qt3DRender/qparameter.h>
50#include <Qt3DRender/qrenderpass.h>
51#include <Qt3DRender/qgraphicsapifilter.h>
52#include <QUrl>
53#include <QVector3D>
54#include <QVector4D>
55
56QT_BEGIN_NAMESPACE
57
58using namespace Qt3DRender;
59
60namespace Qt3DExtras {
61
62QMetalRoughMaterialPrivate::QMetalRoughMaterialPrivate()
63 : QMaterialPrivate()
64 , m_baseColorParameter(new QParameter(QStringLiteral("baseColor"), QColor("grey")))
65 , m_metalnessParameter(new QParameter(QStringLiteral("metalness"), 0.0f))
66 , m_roughnessParameter(new QParameter(QStringLiteral("roughness"), 0.0f))
67 , m_baseColorMapParameter(new QParameter(QStringLiteral("baseColorMap"), QVariant()))
68 , m_metalnessMapParameter(new QParameter(QStringLiteral("metalnessMap"), QVariant()))
69 , m_roughnessMapParameter(new QParameter(QStringLiteral("roughnessMap"), QVariant()))
70 , m_ambientOcclusionMapParameter(new QParameter(QStringLiteral("ambientOcclusionMap"), QVariant()))
71 , m_normalMapParameter(new QParameter(QStringLiteral("normalMap"), QVariant()))
72 , m_textureScaleParameter(new QParameter(QStringLiteral("texCoordScale"), 1.0f))
73 , m_metalRoughEffect(new QEffect())
74 , m_metalRoughGL3Technique(new QTechnique())
75 , m_metalRoughGL3RenderPass(new QRenderPass())
76 , m_metalRoughGL3Shader(new QShaderProgram())
77 , m_metalRoughGL3ShaderBuilder(new QShaderProgramBuilder())
78 , m_metalRoughES3Technique(new QTechnique())
79 , m_metalRoughES3RenderPass(new QRenderPass())
80 , m_metalRoughES3Shader(new QShaderProgram())
81 , m_metalRoughES3ShaderBuilder(new QShaderProgramBuilder())
82 , m_metalRoughRHITechnique(new QTechnique())
83 , m_metalRoughRHIRenderPass(new QRenderPass())
84 , m_metalRoughRHIShader(new QShaderProgram())
85 , m_metalRoughRHIShaderBuilder(new QShaderProgramBuilder())
86 , m_filterKey(new QFilterKey)
87{
88}
89
90void QMetalRoughMaterialPrivate::init()
91{
92 Q_Q(QMetalRoughMaterial);
93
94 QObject::connect(sender: m_baseColorParameter, signal: &Qt3DRender::QParameter::valueChanged,
95 receiver: q, slot: &QMetalRoughMaterial::baseColorChanged);
96 QObject::connect(sender: m_metalnessParameter, signal: &Qt3DRender::QParameter::valueChanged,
97 receiver: q, slot: &QMetalRoughMaterial::metalnessChanged);
98 QObject::connect(sender: m_roughnessParameter, signal: &Qt3DRender::QParameter::valueChanged,
99 receiver: q, slot: &QMetalRoughMaterial::roughnessChanged);
100 QObject::connect(sender: m_ambientOcclusionMapParameter, signal: &Qt3DRender::QParameter::valueChanged,
101 receiver: q, slot: &QMetalRoughMaterial::roughnessChanged);
102 QObject::connect(sender: m_normalMapParameter, signal: &Qt3DRender::QParameter::valueChanged,
103 receiver: q, slot: &QMetalRoughMaterial::normalChanged);
104 connect(sender: m_textureScaleParameter, signal: &Qt3DRender::QParameter::valueChanged,
105 receiverPrivate: this, slot: &QMetalRoughMaterialPrivate::handleTextureScaleChanged);
106
107 m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
108 m_metalRoughGL3ShaderBuilder->setParent(q);
109 m_metalRoughGL3ShaderBuilder->setShaderProgram(m_metalRoughGL3Shader);
110 m_metalRoughGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/metalrough.frag.json")));
111 m_metalRoughGL3ShaderBuilder->setEnabledLayers({QStringLiteral("baseColor"),
112 QStringLiteral("metalness"),
113 QStringLiteral("roughness"),
114 QStringLiteral("ambientOcclusion"),
115 QStringLiteral("normal")});
116
117 m_metalRoughES3Shader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/es3/default.vert"))));
118 m_metalRoughES3ShaderBuilder->setParent(q);
119 m_metalRoughES3ShaderBuilder->setShaderProgram(m_metalRoughES3Shader);
120 m_metalRoughES3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/metalrough.frag.json")));
121 m_metalRoughES3ShaderBuilder->setEnabledLayers({QStringLiteral("baseColor"),
122 QStringLiteral("metalness"),
123 QStringLiteral("roughness"),
124 QStringLiteral("ambientOcclusion"),
125 QStringLiteral("normal")});
126
127 m_metalRoughRHIShader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/rhi/default.vert"))));
128 m_metalRoughRHIShaderBuilder->setParent(q);
129 m_metalRoughRHIShaderBuilder->setShaderProgram(m_metalRoughRHIShader);
130 m_metalRoughRHIShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/metalrough.frag.json")));
131 m_metalRoughRHIShaderBuilder->setEnabledLayers({QStringLiteral("baseColor"),
132 QStringLiteral("metalness"),
133 QStringLiteral("roughness"),
134 QStringLiteral("ambientOcclusion"),
135 QStringLiteral("normal")});
136
137 m_metalRoughGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
138 m_metalRoughGL3Technique->graphicsApiFilter()->setMajorVersion(3);
139 m_metalRoughGL3Technique->graphicsApiFilter()->setMinorVersion(1);
140 m_metalRoughGL3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
141
142 m_metalRoughES3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES);
143 m_metalRoughES3Technique->graphicsApiFilter()->setMajorVersion(3);
144 m_metalRoughES3Technique->graphicsApiFilter()->setMinorVersion(0);
145
146 m_metalRoughRHITechnique->graphicsApiFilter()->setApi(QGraphicsApiFilter::RHI);
147 m_metalRoughRHITechnique->graphicsApiFilter()->setMajorVersion(1);
148 m_metalRoughRHITechnique->graphicsApiFilter()->setMinorVersion(0);
149
150 m_filterKey->setParent(q);
151 m_filterKey->setName(QStringLiteral("renderingStyle"));
152 m_filterKey->setValue(QStringLiteral("forward"));
153
154 m_metalRoughGL3Technique->addFilterKey(filterKey: m_filterKey);
155 m_metalRoughGL3RenderPass->setShaderProgram(m_metalRoughGL3Shader);
156 m_metalRoughGL3Technique->addRenderPass(pass: m_metalRoughGL3RenderPass);
157 m_metalRoughEffect->addTechnique(t: m_metalRoughGL3Technique);
158
159 m_metalRoughES3Technique->addFilterKey(filterKey: m_filterKey);
160 m_metalRoughES3RenderPass->setShaderProgram(m_metalRoughES3Shader);
161 m_metalRoughES3Technique->addRenderPass(pass: m_metalRoughES3RenderPass);
162 m_metalRoughEffect->addTechnique(t: m_metalRoughES3Technique);
163
164 m_metalRoughRHITechnique->addFilterKey(filterKey: m_filterKey);
165 m_metalRoughRHIRenderPass->setShaderProgram(m_metalRoughRHIShader);
166 m_metalRoughRHITechnique->addRenderPass(pass: m_metalRoughRHIRenderPass);
167 m_metalRoughEffect->addTechnique(t: m_metalRoughRHITechnique);
168
169 // Given parameters a parent
170 m_baseColorMapParameter->setParent(m_metalRoughEffect);
171 m_metalnessMapParameter->setParent(m_metalRoughEffect);
172 m_roughnessMapParameter->setParent(m_metalRoughEffect);
173
174 m_metalRoughEffect->addParameter(parameter: m_baseColorParameter);
175 m_metalRoughEffect->addParameter(parameter: m_metalnessParameter);
176 m_metalRoughEffect->addParameter(parameter: m_roughnessParameter);
177 m_metalRoughEffect->addParameter(parameter: m_textureScaleParameter);
178
179 q->setEffect(m_metalRoughEffect);
180}
181
182void QMetalRoughMaterialPrivate::handleTextureScaleChanged(const QVariant &var)
183{
184 Q_Q(QMetalRoughMaterial);
185 emit q->textureScaleChanged(textureScale: var.toFloat());
186}
187
188/*!
189 \class Qt3DExtras::QMetalRoughMaterial
190 \ingroup qt3d-extras-materials
191 \brief The QMetalRoughMaterial provides a default implementation of PBR
192 lighting.
193 \inmodule Qt3DExtras
194 \since 5.9
195 \inherits Qt3DRender::QMaterial
196
197 This material uses an effect with a single render pass approach and performs per fragment
198 lighting. Techniques are provided for OpenGL 3 and OpenGL ES 3.
199*/
200
201/*!
202 \qmltype MetalRoughMaterial
203 \instantiates Qt3DExtras::QMetalRoughMaterial
204 \inqmlmodule Qt3D.Extras
205
206 \brief This material uses an effect with a single render pass approach and
207 performs per fragment lighting. Techniques are provided for OpenGL 3
208 and OpenGL ES 3.
209*/
210
211/*!
212 Constructs a new QMetalRoughMaterial instance with parent object \a parent.
213*/
214QMetalRoughMaterial::QMetalRoughMaterial(QNode *parent)
215 : QMaterial(*new QMetalRoughMaterialPrivate, parent)
216{
217 Q_D(QMetalRoughMaterial);
218 d->init();
219}
220
221/*! \internal */
222QMetalRoughMaterial::QMetalRoughMaterial(QMetalRoughMaterialPrivate &dd, QNode *parent)
223 : QMaterial(dd, parent)
224{
225 Q_D(QMetalRoughMaterial);
226 d->init();
227}
228
229/*!
230 Destroys the QMetalRoughMaterial instance.
231*/
232QMetalRoughMaterial::~QMetalRoughMaterial()
233{
234}
235
236/*!
237 \property QMetalRoughMaterial::baseColor
238
239 Holds the current base color of the material. This can be either a plain
240 color value or a texture. By default the value of this property is "grey".
241*/
242/*!
243 \qmlproperty variant Qt3D.Extras::MetalRoughMaterial::baseColor
244
245 Holds the current base color of the material. This can be either a plain
246 color value or a texture. By default the value of this property is "grey".
247*/
248QVariant QMetalRoughMaterial::baseColor() const
249{
250 Q_D(const QMetalRoughMaterial);
251 return d->m_baseColorParameter->value();
252}
253
254/*!
255 \property QMetalRoughMaterial::metalness
256
257 Holds the current metalness level of the material, as a value between
258 0 (purely dielectric, the default) and 1 (purely metallic). This can be
259 either a plain uniform value or a texture. By default the value of this
260 property is 0.
261*/
262/*!
263 \qmlproperty variant Qt3D.Extras::MetalRoughMaterial::metalness
264
265 Holds the current metalness level of the material, as a value between
266 0 (purely dielectric, the default) and 1 (purely metallic). This can be
267 either a plain uniform value or a texture. By default the value of this
268 property is 0.
269*/
270QVariant QMetalRoughMaterial::metalness() const
271{
272 Q_D(const QMetalRoughMaterial);
273 return d->m_metalnessParameter->value();
274}
275
276/*!
277 \property QMetalRoughMaterial::roughness
278
279 Holds the current roughness level of the material. This can be either a
280 plain uniform value or a texture. By default the value of this property is
281 0.
282*/
283/*!
284 \qmlproperty variant Qt3D.Extras::MetalRoughMaterial::roughness
285
286 Holds the current roughness level of the material. This can be either a
287 plain uniform value or a texture. By default the value of this property is
288 0.
289*/
290QVariant QMetalRoughMaterial::roughness() const
291{
292 Q_D(const QMetalRoughMaterial);
293 return d->m_roughnessParameter->value();
294}
295
296/*!
297 \property QMetalRoughMaterial::ambientOcclusion
298
299 Holds the current ambient occlusion map texture of the material. This can
300 only be a texture, otherwise it is ignored. By default this map is not set.
301*/
302/*!
303 \qmlproperty Texture Qt3D.Extras::MetalRoughMaterial::ambientOcclusion
304
305 Holds the current ambient occlusion map texture of the material. This can
306 only be a texture, otherwise it is ignored. By default this map is not set.
307*/
308QVariant QMetalRoughMaterial::ambientOcclusion() const
309{
310 Q_D(const QMetalRoughMaterial);
311 return d->m_ambientOcclusionMapParameter->value();
312}
313
314/*!
315 \property QMetalRoughMaterial::normal
316
317 Holds the current normal map texture of the material. This can only be a
318 texture, otherwise it is ignored. By default this map is not set.
319*/
320/*!
321 \qmlproperty Texture Qt3D.Extras::MetalRoughMaterial::normal
322
323 Holds the current normal map texture of the material. This can only be a
324 texture, otherwise it is ignored. By default this map is not set.
325*/
326QVariant QMetalRoughMaterial::normal() const
327{
328 Q_D(const QMetalRoughMaterial);
329 return d->m_normalMapParameter->value();
330}
331
332/*!
333 \property QMetalRoughMaterial::textureScale
334
335 Holds the current texture scale. It is applied as a multiplier to texture
336 coordinates at render time. Defaults to 1.0.
337
338 When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple
339 way to tile a texture across a surface. For example, a texture scale of \c 4.0
340 would result in 16 (4x4) tiles.
341*/
342/*!
343 \qmlproperty real Qt3D.Extras::MetalRoughMaterial::textureScale
344
345 Holds the current texture scale. It is applied as a multiplier to texture
346 coordinates at render time. Defaults to 1.0.
347
348 When used in conjunction with WrapMode.Repeat, textureScale provides a simple
349 way to tile a texture across a surface. For example, a texture scale of \c 4.0
350 would result in 16 (4x4) tiles.
351*/
352float QMetalRoughMaterial::textureScale() const
353{
354 Q_D(const QMetalRoughMaterial);
355 return d->m_textureScaleParameter->value().toFloat();
356}
357
358void QMetalRoughMaterial::setBaseColor(const QVariant &baseColor)
359{
360 Q_D(QMetalRoughMaterial);
361 d->m_baseColorParameter->setValue(baseColor);
362 d->m_baseColorMapParameter->setValue(baseColor);
363
364 auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
365 if (baseColor.value<QAbstractTexture *>()) {
366 layers.removeAll(QStringLiteral("baseColor"));
367 layers.append(QStringLiteral("baseColorMap"));
368 d->m_metalRoughEffect->addParameter(parameter: d->m_baseColorMapParameter);
369 if (d->m_metalRoughEffect->parameters().contains(t: d->m_baseColorParameter))
370 d->m_metalRoughEffect->removeParameter(parameter: d->m_baseColorParameter);
371 } else {
372 layers.removeAll(QStringLiteral("baseColorMap"));
373 layers.append(QStringLiteral("baseColor"));
374 if (d->m_metalRoughEffect->parameters().contains(t: d->m_baseColorMapParameter))
375 d->m_metalRoughEffect->removeParameter(parameter: d->m_baseColorMapParameter);
376 d->m_metalRoughEffect->addParameter(parameter: d->m_baseColorParameter);
377 }
378 d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
379 d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
380 d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
381}
382
383void QMetalRoughMaterial::setMetalness(const QVariant &metalness)
384{
385 Q_D(QMetalRoughMaterial);
386 d->m_metalnessParameter->setValue(metalness);
387 d->m_metalnessMapParameter->setValue(metalness);
388
389 auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
390 if (metalness.value<QAbstractTexture *>()) {
391 layers.removeAll(QStringLiteral("metalness"));
392 layers.append(QStringLiteral("metalnessMap"));
393 d->m_metalRoughEffect->addParameter(parameter: d->m_metalnessMapParameter);
394 if (d->m_metalRoughEffect->parameters().contains(t: d->m_metalnessParameter))
395 d->m_metalRoughEffect->removeParameter(parameter: d->m_metalnessParameter);
396 } else {
397 layers.removeAll(QStringLiteral("metalnessMap"));
398 layers.append(QStringLiteral("metalness"));
399 if (d->m_metalRoughEffect->parameters().contains(t: d->m_metalnessMapParameter))
400 d->m_metalRoughEffect->removeParameter(parameter: d->m_metalnessMapParameter);
401 d->m_metalRoughEffect->addParameter(parameter: d->m_metalnessParameter);
402 }
403 d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
404 d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
405 d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
406}
407
408void QMetalRoughMaterial::setRoughness(const QVariant &roughness)
409{
410 Q_D(QMetalRoughMaterial);
411 d->m_roughnessParameter->setValue(roughness);
412 d->m_roughnessMapParameter->setValue(roughness);
413
414 auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
415 if (roughness.value<QAbstractTexture *>()) {
416 layers.removeAll(QStringLiteral("roughness"));
417 layers.append(QStringLiteral("roughnessMap"));
418 d->m_metalRoughEffect->addParameter(parameter: d->m_roughnessMapParameter);
419 if (d->m_metalRoughEffect->parameters().contains(t: d->m_roughnessParameter))
420 d->m_metalRoughEffect->removeParameter(parameter: d->m_roughnessParameter);
421 } else {
422 layers.removeAll(QStringLiteral("roughnessMap"));
423 layers.append(QStringLiteral("roughness"));
424 if (d->m_metalRoughEffect->parameters().contains(t: d->m_roughnessMapParameter))
425 d->m_metalRoughEffect->removeParameter(parameter: d->m_roughnessMapParameter);
426 d->m_metalRoughEffect->addParameter(parameter: d->m_roughnessParameter);
427 }
428 d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
429 d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
430 d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
431}
432
433void QMetalRoughMaterial::setAmbientOcclusion(const QVariant &ambientOcclusion)
434{
435 Q_D(QMetalRoughMaterial);
436 d->m_ambientOcclusionMapParameter->setValue(ambientOcclusion);
437
438 auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
439 if (ambientOcclusion.value<QAbstractTexture *>()) {
440 layers.removeAll(QStringLiteral("ambientOcclusion"));
441 layers.append(QStringLiteral("ambientOcclusionMap"));
442 d->m_metalRoughEffect->addParameter(parameter: d->m_ambientOcclusionMapParameter);
443 } else {
444 layers.removeAll(QStringLiteral("ambientOcclusionMap"));
445 layers.append(QStringLiteral("ambientOcclusion"));
446 if (d->m_metalRoughEffect->parameters().contains(t: d->m_ambientOcclusionMapParameter))
447 d->m_metalRoughEffect->removeParameter(parameter: d->m_ambientOcclusionMapParameter);
448 }
449 d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
450 d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
451 d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
452}
453
454void QMetalRoughMaterial::setNormal(const QVariant &normal)
455{
456 Q_D(QMetalRoughMaterial);
457 d->m_normalMapParameter->setValue(normal);
458
459 auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
460 if (normal.value<QAbstractTexture *>()) {
461 layers.removeAll(QStringLiteral("normal"));
462 layers.append(QStringLiteral("normalMap"));
463 d->m_metalRoughEffect->addParameter(parameter: d->m_normalMapParameter);
464 } else {
465 layers.removeAll(QStringLiteral("normalMap"));
466 layers.append(QStringLiteral("normal"));
467 if (d->m_metalRoughEffect->parameters().contains(t: d->m_normalMapParameter))
468 d->m_metalRoughEffect->removeParameter(parameter: d->m_normalMapParameter);
469 }
470 d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
471 d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
472 d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
473}
474
475void QMetalRoughMaterial::setTextureScale(float textureScale)
476{
477 Q_D(QMetalRoughMaterial);
478 d->m_textureScaleParameter->setValue(textureScale);
479}
480
481} // namespace Qt3DExtras
482
483QT_END_NAMESPACE
484

source code of qt3d/src/extras/defaults/qmetalroughmaterial.cpp