1// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qdiffusespecularmaterial.h"
5#include "qdiffusespecularmaterial_p.h"
6
7#include <Qt3DRender/qfilterkey.h>
8#include <Qt3DRender/qmaterial.h>
9#include <Qt3DRender/qeffect.h>
10#include <Qt3DRender/qtechnique.h>
11#include <Qt3DRender/qtexture.h>
12#include <Qt3DRender/qshaderprogram.h>
13#include <Qt3DRender/qshaderprogrambuilder.h>
14#include <Qt3DRender/qparameter.h>
15#include <Qt3DRender/qrenderpass.h>
16#include <Qt3DRender/qgraphicsapifilter.h>
17#include <Qt3DRender/qblendequation.h>
18#include <Qt3DRender/qblendequationarguments.h>
19#include <Qt3DRender/qnodepthmask.h>
20#include <QtCore/QUrl>
21#include <QtGui/QVector3D>
22#include <QtGui/QVector4D>
23
24
25QT_BEGIN_NAMESPACE
26
27using namespace Qt3DRender;
28
29namespace Qt3DExtras {
30
31QDiffuseSpecularMaterialPrivate::QDiffuseSpecularMaterialPrivate()
32 : QMaterialPrivate()
33 , m_effect(new QEffect())
34 , m_ambientParameter(new QParameter(QStringLiteral("ka"), QColor::fromRgbF(r: 0.05f, g: 0.05f, b: 0.05f, a: 1.0f)))
35 , m_diffuseParameter(new QParameter(QStringLiteral("kd"), QColor::fromRgbF(r: 0.7f, g: 0.7f, b: 0.7f, a: 1.0f)))
36 , m_specularParameter(new QParameter(QStringLiteral("ks"), QColor::fromRgbF(r: 0.01f, g: 0.01f, b: 0.01f, a: 1.0f)))
37 , m_diffuseTextureParameter(new QParameter(QStringLiteral("diffuseTexture"), QVariant()))
38 , m_specularTextureParameter(new QParameter(QStringLiteral("specularTexture"), QVariant()))
39 , m_shininessParameter(new QParameter(QStringLiteral("shininess"), 150.0f))
40 , m_normalTextureParameter(new QParameter(QStringLiteral("normalTexture"), QVariant()))
41 , m_textureScaleParameter(new QParameter(QStringLiteral("texCoordScale"), 1.0f))
42 , m_gl3Technique(new QTechnique())
43 , m_gl2Technique(new QTechnique())
44 , m_es2Technique(new QTechnique())
45 , m_rhiTechnique(new QTechnique())
46 , m_gl3RenderPass(new QRenderPass())
47 , m_gl2RenderPass(new QRenderPass())
48 , m_es2RenderPass(new QRenderPass())
49 , m_rhiRenderPass(new QRenderPass())
50 , m_gl3Shader(new QShaderProgram())
51 , m_gl3ShaderBuilder(new QShaderProgramBuilder())
52 , m_gl2es2Shader(new QShaderProgram())
53 , m_gl2es2ShaderBuilder(new QShaderProgramBuilder())
54 , m_rhiShader(new QShaderProgram())
55 , m_rhiShaderBuilder(new QShaderProgramBuilder())
56 , m_noDepthMask(new QNoDepthMask())
57 , m_blendState(new QBlendEquationArguments())
58 , m_blendEquation(new QBlendEquation())
59 , m_filterKey(new QFilterKey)
60{
61}
62
63void QDiffuseSpecularMaterialPrivate::init()
64{
65 Q_Q(QDiffuseSpecularMaterial);
66
67 connect(sender: m_ambientParameter, signal: &Qt3DRender::QParameter::valueChanged,
68 receiverPrivate: this, slot: &QDiffuseSpecularMaterialPrivate::handleAmbientChanged);
69 QObject::connect(sender: m_diffuseParameter, signal: &Qt3DRender::QParameter::valueChanged,
70 context: q, slot: &QDiffuseSpecularMaterial::diffuseChanged);
71 QObject::connect(sender: m_specularParameter, signal: &Qt3DRender::QParameter::valueChanged,
72 context: q, slot: &QDiffuseSpecularMaterial::specularChanged);
73 connect(sender: m_shininessParameter, signal: &Qt3DRender::QParameter::valueChanged,
74 receiverPrivate: this, slot: &QDiffuseSpecularMaterialPrivate::handleShininessChanged);
75 QObject::connect(sender: m_normalTextureParameter, signal: &Qt3DRender::QParameter::valueChanged,
76 context: q, slot: &QDiffuseSpecularMaterial::normalChanged);
77 connect(sender: m_textureScaleParameter, signal: &Qt3DRender::QParameter::valueChanged,
78 receiverPrivate: this, slot: &QDiffuseSpecularMaterialPrivate::handleTextureScaleChanged);
79 QObject::connect(sender: m_noDepthMask, signal: &QNoDepthMask::enabledChanged,
80 context: q, slot: &QDiffuseSpecularMaterial::alphaBlendingEnabledChanged);
81
82 m_gl3Shader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
83 m_gl3ShaderBuilder->setParent(q);
84 m_gl3ShaderBuilder->setShaderProgram(m_gl3Shader);
85 m_gl3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
86 m_gl3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
87 QStringLiteral("specular"),
88 QStringLiteral("normal")});
89
90 m_gl2es2Shader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
91 m_gl2es2ShaderBuilder->setParent(q);
92 m_gl2es2ShaderBuilder->setShaderProgram(m_gl2es2Shader);
93 m_gl2es2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
94 m_gl2es2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
95 QStringLiteral("specular"),
96 QStringLiteral("normal")});
97
98 m_rhiShader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/rhi/default_pos_norm.vert"))));
99 m_rhiShaderBuilder->setParent(q);
100 m_rhiShaderBuilder->setShaderProgram(m_rhiShader);
101 m_rhiShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
102 m_rhiShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
103 QStringLiteral("specular"),
104 QStringLiteral("normal")});
105
106
107 m_gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
108 m_gl3Technique->graphicsApiFilter()->setMajorVersion(3);
109 m_gl3Technique->graphicsApiFilter()->setMinorVersion(1);
110 m_gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
111
112 m_gl2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
113 m_gl2Technique->graphicsApiFilter()->setMajorVersion(2);
114 m_gl2Technique->graphicsApiFilter()->setMinorVersion(0);
115 m_gl2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
116
117 m_es2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES);
118 m_es2Technique->graphicsApiFilter()->setMajorVersion(2);
119 m_es2Technique->graphicsApiFilter()->setMinorVersion(0);
120 m_es2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
121
122 m_rhiTechnique->graphicsApiFilter()->setApi(QGraphicsApiFilter::RHI);
123 m_rhiTechnique->graphicsApiFilter()->setMajorVersion(1);
124 m_rhiTechnique->graphicsApiFilter()->setMinorVersion(0);
125
126 m_noDepthMask->setEnabled(false);
127 m_blendState->setEnabled(false);
128 m_blendState->setSourceRgb(QBlendEquationArguments::SourceAlpha);
129 m_blendState->setDestinationRgb(QBlendEquationArguments::OneMinusSourceAlpha);
130 m_blendEquation->setEnabled(false);
131 m_blendEquation->setBlendFunction(QBlendEquation::Add);
132
133 m_gl3RenderPass->setShaderProgram(m_gl3Shader);
134 m_gl2RenderPass->setShaderProgram(m_gl2es2Shader);
135 m_es2RenderPass->setShaderProgram(m_gl2es2Shader);
136 m_rhiRenderPass->setShaderProgram(m_rhiShader);
137
138 m_gl3RenderPass->addRenderState(state: m_noDepthMask);
139 m_gl3RenderPass->addRenderState(state: m_blendState);
140 m_gl3RenderPass->addRenderState(state: m_blendEquation);
141
142 m_gl2RenderPass->addRenderState(state: m_noDepthMask);
143 m_gl2RenderPass->addRenderState(state: m_blendState);
144 m_gl2RenderPass->addRenderState(state: m_blendEquation);
145
146 m_es2RenderPass->addRenderState(state: m_noDepthMask);
147 m_es2RenderPass->addRenderState(state: m_blendState);
148 m_es2RenderPass->addRenderState(state: m_blendEquation);
149
150 m_rhiRenderPass->addRenderState(state: m_noDepthMask);
151 m_rhiRenderPass->addRenderState(state: m_blendState);
152 m_rhiRenderPass->addRenderState(state: m_blendEquation);
153
154 m_gl3Technique->addRenderPass(pass: m_gl3RenderPass);
155 m_gl2Technique->addRenderPass(pass: m_gl2RenderPass);
156 m_es2Technique->addRenderPass(pass: m_es2RenderPass);
157 m_rhiTechnique->addRenderPass(pass: m_rhiRenderPass);
158
159 m_filterKey->setParent(q);
160 m_filterKey->setName(QStringLiteral("renderingStyle"));
161 m_filterKey->setValue(QStringLiteral("forward"));
162
163 m_gl3Technique->addFilterKey(filterKey: m_filterKey);
164 m_gl2Technique->addFilterKey(filterKey: m_filterKey);
165 m_es2Technique->addFilterKey(filterKey: m_filterKey);
166 m_rhiTechnique->addFilterKey(filterKey: m_filterKey);
167
168 m_effect->addTechnique(t: m_gl3Technique);
169 m_effect->addTechnique(t: m_gl2Technique);
170 m_effect->addTechnique(t: m_es2Technique);
171 m_effect->addTechnique(t: m_rhiTechnique);
172
173 m_effect->addParameter(parameter: m_ambientParameter);
174 m_effect->addParameter(parameter: m_diffuseParameter);
175 m_effect->addParameter(parameter: m_specularParameter);
176 m_effect->addParameter(parameter: m_shininessParameter);
177 m_effect->addParameter(parameter: m_textureScaleParameter);
178
179 q->setEffect(m_effect);
180}
181
182void QDiffuseSpecularMaterialPrivate::handleAmbientChanged(const QVariant &var)
183{
184 Q_Q(QDiffuseSpecularMaterial);
185 emit q->ambientChanged(ambient: var.value<QColor>());
186}
187
188void QDiffuseSpecularMaterialPrivate::handleShininessChanged(const QVariant &var)
189{
190 Q_Q(QDiffuseSpecularMaterial);
191 emit q->shininessChanged(shininess: var.toFloat());
192}
193
194void QDiffuseSpecularMaterialPrivate::handleTextureScaleChanged(const QVariant &var)
195{
196 Q_Q(QDiffuseSpecularMaterial);
197 emit q->textureScaleChanged(textureScale: var.toFloat());
198}
199
200/*!
201 \class Qt3DExtras::QDiffuseSpecularMaterial
202 \ingroup qt3d-extras-materials
203 \brief The QDiffuseSpecularMaterial class provides a default implementation
204 of the phong lighting effect.
205 \inmodule Qt3DExtras
206 \since 5.10
207 \inherits Qt3DRender::QMaterial
208
209 The phong lighting effect is based on the combination of 3 lighting
210 components ambient, diffuse and specular. The relative strengths of these
211 components are controlled by means of their reflectivity coefficients which
212 are modelled as RGB triplets:
213
214 \list
215 \li Ambient is the color that is emitted by an object without any other
216 light source.
217 \li Diffuse is the color that is emitted for rought surface reflections
218 with the lights.
219 \li Specular is the color emitted for shiny surface reflections with the
220 lights.
221 \li The shininess of a surface is controlled by a float property.
222 \endlist
223
224 This material uses an effect with a single render pass approach and
225 performs per fragment lighting. Techniques are provided for OpenGL 2,
226 OpenGL 3 or above as well as OpenGL ES 2.
227*/
228/*!
229 \qmltype DiffuseSpecularMaterial
230 \brief The DiffuseSpecularMaterial class provides a default implementation
231 of the phong lighting effect.
232 \since 5.10
233 \inqmlmodule Qt3D.Extras
234 \instantiates Qt3DExtras::QDiffuseSpecularMaterial
235
236 The phong lighting effect is based on the combination of 3 lighting
237 components ambient, diffuse and specular. The relative strengths of these
238 components are controlled by means of their reflectivity coefficients which
239 are modelled as RGB triplets:
240
241 \list
242 \li Ambient is the color that is emitted by an object without any other
243 light source.
244 \li Diffuse is the color that is emitted for rough surface reflections
245 with the lights.
246 \li Specular is the color emitted for shiny surface reflections with the
247 lights.
248 \li The shininess of a surface is controlled by a float property.
249 \endlist
250
251 This material uses an effect with a single render pass approach and
252 performs per fragment lighting. Techniques are provided for OpenGL 2,
253 OpenGL 3 or above as well as OpenGL ES 2.
254 */
255
256/*!
257 Constructs a new QDiffuseSpecularMaterial instance with parent object \a parent.
258*/
259QDiffuseSpecularMaterial::QDiffuseSpecularMaterial(QNode *parent)
260 : QMaterial(*new QDiffuseSpecularMaterialPrivate, parent)
261{
262 Q_D(QDiffuseSpecularMaterial);
263 d->init();
264}
265
266/*!
267 Destroys the QDiffuseSpecularMaterial.
268*/
269QDiffuseSpecularMaterial::~QDiffuseSpecularMaterial()
270{
271}
272
273/*!
274 \property QDiffuseSpecularMaterial::ambient
275
276 Holds the ambient color that is emitted by an object without any other
277 light source.
278*/
279/*!
280 \qmlproperty color DiffuseSpecularMaterial::ambient
281
282 Holds the ambient color that is emitted by an object without any other
283 light source.
284*/
285QColor QDiffuseSpecularMaterial::ambient() const
286{
287 Q_D(const QDiffuseSpecularMaterial);
288 return d->m_ambientParameter->value().value<QColor>();
289}
290
291/*!
292 \property QDiffuseSpecularMaterial::diffuse
293
294 Holds the diffuse color of the material that is emitted for rough surface
295 reflections with the lights. This can be either a plain color value or a
296 texture.
297*/
298/*!
299 \qmlproperty var DiffuseSpecularMaterial::diffuse
300
301 Holds the diffuse color of the material that is emitted for rough surface
302 reflections with the lights. This can be either a plain color value or a
303 texture.
304*/
305QVariant QDiffuseSpecularMaterial::diffuse() const
306{
307 Q_D(const QDiffuseSpecularMaterial);
308 return d->m_diffuseParameter->value();
309}
310
311/*!
312 \property QDiffuseSpecularMaterial::specular
313
314 Holds the specular color of the material that is emitted for shiny surface
315 reflections with the lights. This can be either a plain color value or a
316 texture.
317*/
318/*!
319 \qmlproperty var DiffuseSpecularMaterial::specular
320
321 Holds the specular color of the material that is emitted for shiny surface
322 reflections with the lights. This can be either a plain color value or a
323 texture.
324*/
325QVariant QDiffuseSpecularMaterial::specular() const
326{
327 Q_D(const QDiffuseSpecularMaterial);
328 return d->m_specularParameter->value();
329}
330
331/*!
332 \property QDiffuseSpecularMaterial::shininess
333
334 Holds the shininess exponent. Higher values of shininess result in
335 a smaller and brighter highlight.
336
337 Defaults to 150.0.
338*/
339/*!
340 \qmlproperty real DiffuseSpecularMaterial::shininess
341
342 Holds the shininess exponent. Higher values of shininess result in
343 a smaller and brighter highlight.
344
345 Defaults to 150.0.
346*/
347float QDiffuseSpecularMaterial::shininess() const
348{
349 Q_D(const QDiffuseSpecularMaterial);
350 return d->m_shininessParameter->value().toFloat();
351}
352
353/*!
354 \property QDiffuseSpecularMaterial::normal
355
356 Holds the current normal map texture of the material. This can only be a
357 texture, otherwise it is ignored. By default this map is not set.
358*/
359/*!
360 \qmlproperty var DiffuseSpecularMaterial::normal
361
362 Holds the current normal map texture of the material. This can only be a
363 texture, otherwise it is ignored. By default this map is not set.
364*/
365QVariant QDiffuseSpecularMaterial::normal() const
366{
367 Q_D(const QDiffuseSpecularMaterial);
368 return d->m_normalTextureParameter->value();
369}
370
371/*!
372 \property QDiffuseSpecularMaterial::textureScale
373
374 Holds the current texture scale. It is applied as a multiplier to texture
375 coordinates at render time. Defaults to 1.0.
376
377 When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple
378 way to tile a texture across a surface. For example, a texture scale of \c 4.0
379 would result in 16 (4x4) tiles.
380*/
381/*!
382 \qmlproperty real DiffuseSpecularMaterial::textureScale
383
384 Holds the current texture scale. It is applied as a multiplier to texture
385 coordinates at render time. Defaults to 1.0.
386
387 When used in conjunction with WrapMode.Repeat, textureScale provides a simple
388 way to tile a texture across a surface. For example, a texture scale of \c 4.0
389 would result in 16 (4x4) tiles.
390*/
391float QDiffuseSpecularMaterial::textureScale() const
392{
393 Q_D(const QDiffuseSpecularMaterial);
394 return d->m_textureScaleParameter->value().toFloat();
395}
396
397/*!
398 \property QDiffuseSpecularMaterial::alphaBlending
399
400 Indicates if the alpha information coming from the diffuse property will
401 be taken into account during rendering. Defaults to false.
402*/
403/*!
404 \qmlproperty bool DiffuseSpecularMaterial::alphaBlending
405
406 Indicates if the alpha information coming from the diffuse property will
407 be taken into account during rendering. Defaults to false.
408*/
409bool QDiffuseSpecularMaterial::isAlphaBlendingEnabled() const
410{
411 Q_D(const QDiffuseSpecularMaterial);
412 return d->m_noDepthMask->isEnabled();
413}
414
415void QDiffuseSpecularMaterial::setAmbient(const QColor &ambient)
416{
417 Q_D(QDiffuseSpecularMaterial);
418 d->m_ambientParameter->setValue(ambient);
419}
420
421void QDiffuseSpecularMaterial::setDiffuse(const QVariant &diffuse)
422{
423 Q_D(QDiffuseSpecularMaterial);
424 d->m_diffuseParameter->setValue(diffuse);
425 d->m_diffuseTextureParameter->setValue(diffuse);
426
427 auto layers = d->m_gl3ShaderBuilder->enabledLayers();
428 if (diffuse.value<QAbstractTexture *>()) {
429 layers.removeAll(QStringLiteral("diffuse"));
430 layers.append(QStringLiteral("diffuseTexture"));
431 d->m_effect->addParameter(parameter: d->m_diffuseTextureParameter);
432 d->m_effect->removeParameter(parameter: d->m_diffuseParameter);
433 } else {
434 layers.removeAll(QStringLiteral("diffuseTexture"));
435 layers.append(QStringLiteral("diffuse"));
436 d->m_effect->removeParameter(parameter: d->m_diffuseTextureParameter);
437 d->m_effect->addParameter(parameter: d->m_diffuseParameter);
438 }
439 d->m_gl3ShaderBuilder->setEnabledLayers(layers);
440 d->m_gl2es2ShaderBuilder->setEnabledLayers(layers);
441}
442
443void QDiffuseSpecularMaterial::setSpecular(const QVariant &specular)
444{
445 Q_D(QDiffuseSpecularMaterial);
446 d->m_specularParameter->setValue(specular);
447 d->m_specularTextureParameter->setValue(specular);
448
449 auto layers = d->m_gl3ShaderBuilder->enabledLayers();
450 if (specular.value<QAbstractTexture *>()) {
451 layers.removeAll(QStringLiteral("specular"));
452 layers.append(QStringLiteral("specularTexture"));
453 d->m_effect->addParameter(parameter: d->m_specularTextureParameter);
454 d->m_effect->removeParameter(parameter: d->m_specularParameter);
455 } else {
456 layers.removeAll(QStringLiteral("specularTexture"));
457 layers.append(QStringLiteral("specular"));
458 d->m_effect->removeParameter(parameter: d->m_specularTextureParameter);
459 d->m_effect->addParameter(parameter: d->m_specularParameter);
460 }
461 d->m_gl3ShaderBuilder->setEnabledLayers(layers);
462 d->m_gl2es2ShaderBuilder->setEnabledLayers(layers);
463}
464
465void QDiffuseSpecularMaterial::setShininess(float shininess)
466{
467 Q_D(QDiffuseSpecularMaterial);
468 d->m_shininessParameter->setValue(shininess);
469}
470
471void QDiffuseSpecularMaterial::setNormal(const QVariant &normal)
472{
473 Q_D(QDiffuseSpecularMaterial);
474 d->m_normalTextureParameter->setValue(normal);
475
476 auto layers = d->m_gl3ShaderBuilder->enabledLayers();
477 if (normal.value<QAbstractTexture *>()) {
478 layers.removeAll(QStringLiteral("normal"));
479 layers.append(QStringLiteral("normalTexture"));
480 d->m_effect->addParameter(parameter: d->m_normalTextureParameter);
481 } else {
482 layers.removeAll(QStringLiteral("normalTexture"));
483 layers.append(QStringLiteral("normal"));
484 d->m_effect->removeParameter(parameter: d->m_normalTextureParameter);
485 }
486 d->m_gl3ShaderBuilder->setEnabledLayers(layers);
487}
488
489void QDiffuseSpecularMaterial::setTextureScale(float textureScale)
490{
491 Q_D(QDiffuseSpecularMaterial);
492 d->m_textureScaleParameter->setValue(textureScale);
493}
494
495void QDiffuseSpecularMaterial::setAlphaBlendingEnabled(bool enabled)
496{
497 Q_D(QDiffuseSpecularMaterial);
498 d->m_noDepthMask->setEnabled(enabled);
499 d->m_blendState->setEnabled(enabled);
500 d->m_blendEquation->setEnabled(enabled);
501}
502
503} // namespace Qt3DExtras
504
505QT_END_NAMESPACE
506
507#include "moc_qdiffusespecularmaterial.cpp"
508

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