1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Quick 3D.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
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 General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include "qquick3ddefaultmaterial_p.h"
31 #include "qquick3dobject_p.h"
32 
33 #include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h>
34 
35 QT_BEGIN_NAMESPACE
36 
37 
38 /*!
39     \qmltype DefaultMaterial
40     \inherits Material
41     \inqmlmodule QtQuick3D
42     \brief Defines a Material generated depending on which properties are set.
43 
44     Before a Model can be rendered in a scene, it must have at least one
45     material to define how the mesh is shaded. The DefaultMaterial is the
46     easiest way to define such a material. Even if you define a
47     DefaultMaterial with no properties set, a valid mesh will be rendered,
48     because the mesh defines some sensible defaults.
49 
50     As you change the properties of the DefaultMaterial, behind the scenes
51     new shaders are generated, and the property values are bound. The
52     complexity of a shader depends on a combination of the properties that
53     are set on it, and the context of the scene itself.
54 */
55 
56 /*!
57     \qmlproperty enumeration DefaultMaterial::lighting
58 
59     This property defines which lighting method is used when generating this
60     material.
61 
62     The default value is \c DefaultMaterial.FragmentLighting
63 
64     When using \c DefaultMaterial.FragmentLighting, diffuse and specular lighting are
65     calculated for each rendered pixel. Certain effects (such as a Fresnel or bump map) require
66     \c DefaultMaterial.FragmentLighting to work.
67 
68     When using \c DefaultMaterial.NoLighting no lighting is calculated. This
69     mode is (predictably) very fast, and quite effective when image maps are
70     used that do not need to be shaded by lighting.
71 
72     \value DefaultMaterial.NoLighting No lighting is calculated.
73     \value DefaultMaterial.FragmentLighting Per-fragment lighting is calculated.
74 */
75 
76 /*!
77     \qmlproperty enumeration DefaultMaterial::blendMode
78 
79     This property determines how the colors of the model rendered blend with
80     those behind it.
81 
82     \value DefaultMaterial.SourceOver Default blend mode. Opaque objects occlude
83         objects behind them.
84     \value DefaultMaterial.Screen Colors are blended using an inverted multiply,
85         producing a lighter result. This blend mode is order-independent; if you are
86         using semi-opaque objects and experiencing \e popping as faces or models sort
87         differently, using Screen blending is one way to produce results without
88         popping.
89     \value DefaultMaterial.Multiply Colors are blended using a multiply,
90         producing a darker result. This blend mode is also order-independent.
91     \value DefaultMaterial.Overlay A mix of Multiply and Screen modes, producing
92         a result with higher contrast.
93     \value DefaultMaterial.ColorBurn Colors are blended by inverted division where
94         the result also is inverted, producing a darker result. Darker than Multiply.
95     \value DefaultMaterial.ColorDodge Colors are blended by inverted division,
96         producing a lighter result. Lighter than Screen.
97 
98 */
99 
100 /*!
101     \qmlproperty color DefaultMaterial::diffuseColor
102 
103     This property determines the base color for the material. Set to black to
104     create a purely-specular material (e.g. metals or mirrors).
105  */
106 
107 /*!
108     \qmlproperty Texture DefaultMaterial::diffuseMap
109 
110     This property defines a Texture to apply to the material. Using Texture
111     with transparency will also apply the alpha channel as an opacity map.
112  */
113 
114 /*!
115     \qmlproperty real DefaultMaterial::emissiveFactor
116 
117     This property determines the amount of self-illumination from the material.
118     In a scene with black ambient lighting, a material with an emissive factor of 0
119     will appear black wherever the light does not shine on it. Turning the emissive
120     factor to 1 will cause the material to appear in its diffuse color instead.
121 
122     \note When you want a material to not be affected by lighting, instead of
123     using 100% emissiveFactor consider setting the lightingMode to
124     /c DefaultMaterial.NoLighting for a performance benefit.
125 */
126 
127 /*!
128     \qmlproperty Texture DefaultMaterial::emissiveMap
129 
130     This property sets a Texture to be used to set the emissive factor for
131     different parts of the material. Using a grayscale image will not affect the
132     color of the result, while using a color image will produce glowing regions
133     with the color affected by the emissive map.
134 */
135 
136 /*!
137     \qmlproperty color DefaultMaterial::emissiveColor
138 
139     This property determines the color of self-illumination for this material.
140 */
141 
142 /*!
143     \qmlproperty Texture DefaultMaterial::specularReflectionMap
144 
145     This property sets a Texture used for specular highlights on the material.
146     By default the Texture is applied using environmental mapping (not UV
147     mapping): as you rotate the model the map will appear as though it is
148     reflecting from the environment. Specular Reflection maps are an easy way to
149     add a high-quality look with relatively low cost.
150 
151     \note Using a Light Probe in your SceneEnvironment for image-based lighting
152     will automatically use that image as the specular reflection.
153 
154     \note Crisp images cause your material to look very glossy. The more you
155     blur your image, the softer your material will appear.
156 */
157 
158 /*!
159     \qmlproperty Texture DefaultMaterial::specularMap
160 
161     This property defines a RGB Texture to modulate the amount and the color of
162     specularity across the surface of the material. These values are multiplied
163     by the specularAmount.
164 */
165 
166 /*!
167     \qmlproperty enumeration DefaultMaterial::specularModel
168 
169     This property determines which functions are used to calculate specular
170     highlights for lights in the scene.
171 
172     \value DefaultMaterial.Default Specular lighting uses default lighting model.
173     \value DefaultMaterial.KGGX Specular lighting uses GGX lighting model.
174     \value DefaultMaterial.KWard Specular lighting uses Ward lighting model.
175 */
176 
177 /*!
178     \qmlproperty real DefaultMaterial::specularTint
179 
180     This property defines a color used to adjust the specular reflections.
181     Use white for no effect
182 */
183 
184 /*!
185     \qmlproperty real DefaultMaterial::indexOfRefraction
186 
187     This property controls what angles of reflections are affected by the
188     fresnelPower. The default is \c 1.45. The value must be greater or equal to \c 1.0.
189     \note No known material in the world have ior much greater than \c 3.0.
190 */
191 
192 /*!
193     \qmlproperty real DefaultMaterial::fresnelPower
194 
195     This property decreases head-on reflections (looking directly at the
196     surface) while maintaining reflections seen at grazing angles.
197     The default value is \c 0 disabling the fresnel effect.
198 */
199 
200 /*!
201     \qmlproperty real DefaultMaterial::specularAmount
202 
203     This property controls the strength of specularity (highlights and
204     reflections). The default value is \c 0 disabling the specularity. The range is [0.0, 1.0].
205 
206     \note This property does not affect the \l specularReflectionMap, but does
207     affect the amount of reflections from a scene's SceneEnvironment::lightProbe.
208 
209     \note Unless your mesh is high resolution, you may need to use
210     \c DefaultMaterial.FragmentLighting to get good specular highlights from scene
211     lights.
212 */
213 
214 /*!
215     \qmlproperty real DefaultMaterial::specularRoughness
216 
217     This property controls the size of the specular highlight generated from
218     lights, and the clarity of reflections in general. Larger values increase
219     the roughness, softening specular highlights and blurring reflections.
220 */
221 
222 /*!
223     \qmlproperty Texture DefaultMaterial::roughnessMap
224 
225     This property defines a Texture to control the specular roughness of the
226     material. If the texture contains multiple channels(RGBA), then the correct channel
227     can be set using the roughnessChannel property.
228 */
229 
230 /*!
231     \qmlproperty enumeration DefaultMaterial::roughnessChannel
232 
233     This property defines the texture channel used to read the roughness value from roughnessMap.
234     The default value is \c Material.R.
235 
236     \value Material.R Read value from texture R channel.
237     \value Material.G Read value from texture G channel.
238     \value Material.B Read value from texture B channel.
239     \value Material.A Read value from texture A channel.
240 */
241 
242 /*!
243     \qmlproperty real DefaultMaterial::opacity
244 
245     This property drops the opacity of just this material, separate from the model.
246     The default is \c 1.0. The range is [0.0, 1.0].
247 */
248 
249 /*!
250     \qmlproperty Texture DefaultMaterial::opacityMap
251 
252     This property defines a Texture used to control the opacity differently for
253     different parts of the material.
254 */
255 
256 /*!
257     \qmlproperty enumeration DefaultMaterial::opacityChannel
258 
259     This property defines the texture channel used to read the opacity value from opacityMap.
260     The default value is \c Material.A.
261 
262     \value Material.R Read value from texture R channel.
263     \value Material.G Read value from texture G channel.
264     \value Material.B Read value from texture B channel.
265     \value Material.A Read value from texture A channel.
266 */
267 
268 /*!
269     \qmlproperty Texture DefaultMaterial::bumpMap
270 
271     This property defines a grayscale Texture to simulate fine geometry
272     displacement across the surface of the material. Brighter pixels indicate
273     raised regions. The amount of the effect is controlled by the
274     \l bumpAmount property.
275 
276     \note bump maps will not affect the silhouette of a model. Use a
277     displacementMap if this is required.
278 
279 */
280 
281 /*!
282     \qmlproperty real DefaultMaterial::bumpAmount
283 
284     This property controls the amount of simulated displacement for the
285     \l bumpMap or \l normalMap. The default value is \c 0 disabling the bump effect.
286     The range is [0, 1].
287 
288 */
289 
290 /*!
291     \qmlproperty Texture DefaultMaterial::normalMap
292 
293     This property defines a RGB image used to simulate fine geometry
294     displacement across the surface of the material. The RGB channels indicate
295     XYZ normal deviations. The amount of the effect is controlled by the
296     \l bumpAmount property.
297 
298     \note Normal maps will not affect the silhouette of a model. Use a
299     displacementMap if this is required.
300 */
301 
302 /*!
303     \qmlproperty Texture DefaultMaterial::translucencyMap
304 
305     This property defines a grayscale Texture controlling how much light can
306     pass through the material from behind.
307 */
308 
309 /*!
310     \qmlproperty enumeration DefaultMaterial::translucencyChannel
311 
312     This property defines the texture channel used to read the translucency value from translucencyMap.
313     The default value is \c Material.A.
314 
315     \value Material.R Read value from texture R channel.
316     \value Material.G Read value from texture G channel.
317     \value Material.B Read value from texture B channel.
318     \value Material.A Read value from texture A channel.
319 */
320 
321 /*!
322     \qmlproperty real DefaultMaterial::translucentFalloff
323 
324     This property defines the amount of falloff for the translucency based on the
325     angle of the normals of the object to the light source.
326 */
327 
328 /*!
329     \qmlproperty real DefaultMaterial::diffuseLightWrap
330 
331     This property determines the amount of light wrap for the translucency map.
332     A value of 0 will not wrap the light at all, while a value of 1 will wrap
333     the light all around the object.
334 */
335 
336 /*!
337     \qmlproperty bool DefaultMaterial::vertexColorsEnabled
338 
339     When this property is enabled, the material will use vertex colors from the
340     mesh. These will be multiplied by any other colors specified for the
341     material.
342 */
343 
QQuick3DDefaultMaterial(QQuick3DObject * parent)344 QQuick3DDefaultMaterial::QQuick3DDefaultMaterial(QQuick3DObject *parent)
345     : QQuick3DMaterial(*(new QQuick3DObjectPrivate(QQuick3DObjectPrivate::Type::DefaultMaterial)), parent)
346     , m_diffuseColor(Qt::white)
347     , m_emissiveColor(Qt::white)
348     , m_specularTint(Qt::white)
349 {}
350 
~QQuick3DDefaultMaterial()351 QQuick3DDefaultMaterial::~QQuick3DDefaultMaterial()
352 {
353     for (const auto &connection : m_connections.values())
354         disconnect(connection);
355 }
356 
lighting() const357 QQuick3DDefaultMaterial::Lighting QQuick3DDefaultMaterial::lighting() const
358 {
359     return m_lighting;
360 }
361 
blendMode() const362 QQuick3DDefaultMaterial::BlendMode QQuick3DDefaultMaterial::blendMode() const
363 {
364     return m_blendMode;
365 }
366 
diffuseColor() const367 QColor QQuick3DDefaultMaterial::diffuseColor() const
368 {
369     return m_diffuseColor;
370 }
371 
diffuseMap() const372 QQuick3DTexture *QQuick3DDefaultMaterial::diffuseMap() const
373 {
374     return m_diffuseMap;
375 }
376 
emissiveFactor() const377 float QQuick3DDefaultMaterial::emissiveFactor() const
378 {
379     return m_emissiveFactor;
380 }
381 
emissiveMap() const382 QQuick3DTexture *QQuick3DDefaultMaterial::emissiveMap() const
383 {
384     return m_emissiveMap;
385 }
386 
emissiveColor() const387 QColor QQuick3DDefaultMaterial::emissiveColor() const
388 {
389     return m_emissiveColor;
390 }
391 
specularReflectionMap() const392 QQuick3DTexture *QQuick3DDefaultMaterial::specularReflectionMap() const
393 {
394     return m_specularReflectionMap;
395 }
396 
specularMap() const397 QQuick3DTexture *QQuick3DDefaultMaterial::specularMap() const
398 {
399     return m_specularMap;
400 }
401 
specularModel() const402 QQuick3DDefaultMaterial::SpecularModel QQuick3DDefaultMaterial::specularModel() const
403 {
404     return m_specularModel;
405 }
406 
specularTint() const407 QColor QQuick3DDefaultMaterial::specularTint() const
408 {
409     return m_specularTint;
410 }
411 
indexOfRefraction() const412 float QQuick3DDefaultMaterial::indexOfRefraction() const
413 {
414     return m_indexOfRefraction;
415 }
416 
fresnelPower() const417 float QQuick3DDefaultMaterial::fresnelPower() const
418 {
419     return m_fresnelPower;
420 }
421 
specularAmount() const422 float QQuick3DDefaultMaterial::specularAmount() const
423 {
424     return m_specularAmount;
425 }
426 
specularRoughness() const427 float QQuick3DDefaultMaterial::specularRoughness() const
428 {
429     return m_specularRoughness;
430 }
431 
roughnessMap() const432 QQuick3DTexture *QQuick3DDefaultMaterial::roughnessMap() const
433 {
434     return m_roughnessMap;
435 }
436 
opacity() const437 float QQuick3DDefaultMaterial::opacity() const
438 {
439     return m_opacity;
440 }
441 
opacityMap() const442 QQuick3DTexture *QQuick3DDefaultMaterial::opacityMap() const
443 {
444     return m_opacityMap;
445 }
446 
bumpMap() const447 QQuick3DTexture *QQuick3DDefaultMaterial::bumpMap() const
448 {
449     return m_bumpMap;
450 }
451 
bumpAmount() const452 float QQuick3DDefaultMaterial::bumpAmount() const
453 {
454     return m_bumpAmount;
455 }
456 
normalMap() const457 QQuick3DTexture *QQuick3DDefaultMaterial::normalMap() const
458 {
459     return m_normalMap;
460 }
461 
translucencyMap() const462 QQuick3DTexture *QQuick3DDefaultMaterial::translucencyMap() const
463 {
464     return m_translucencyMap;
465 }
466 
translucentFalloff() const467 float QQuick3DDefaultMaterial::translucentFalloff() const
468 {
469     return m_translucentFalloff;
470 }
471 
diffuseLightWrap() const472 float QQuick3DDefaultMaterial::diffuseLightWrap() const
473 {
474     return m_diffuseLightWrap;
475 }
476 
vertexColorsEnabled() const477 bool QQuick3DDefaultMaterial::vertexColorsEnabled() const
478 {
479     return m_vertexColorsEnabled;
480 }
481 
roughnessChannel() const482 QQuick3DMaterial::TextureChannelMapping QQuick3DDefaultMaterial::roughnessChannel() const
483 {
484     return m_roughnessChannel;
485 }
486 
opacityChannel() const487 QQuick3DMaterial::TextureChannelMapping QQuick3DDefaultMaterial::opacityChannel() const
488 {
489     return m_opacityChannel;
490 }
491 
translucencyChannel() const492 QQuick3DMaterial::TextureChannelMapping QQuick3DDefaultMaterial::translucencyChannel() const
493 {
494     return m_translucencyChannel;
495 }
496 
markAllDirty()497 void QQuick3DDefaultMaterial::markAllDirty()
498 {
499     m_dirtyAttributes = 0xffffffff;
500     QQuick3DMaterial::markAllDirty();
501 }
502 
503 
setLighting(QQuick3DDefaultMaterial::Lighting lighting)504 void QQuick3DDefaultMaterial::setLighting(QQuick3DDefaultMaterial::Lighting lighting)
505 {
506     if (m_lighting == lighting)
507         return;
508 
509     m_lighting = lighting;
510     emit lightingChanged(m_lighting);
511     markDirty(LightingModeDirty);
512 }
513 
setBlendMode(QQuick3DDefaultMaterial::BlendMode blendMode)514 void QQuick3DDefaultMaterial::setBlendMode(QQuick3DDefaultMaterial::BlendMode blendMode)
515 {
516     if (m_blendMode == blendMode)
517         return;
518 
519     m_blendMode = blendMode;
520     emit blendModeChanged(m_blendMode);
521     markDirty(BlendModeDirty);
522 }
523 
setDiffuseColor(QColor diffuseColor)524 void QQuick3DDefaultMaterial::setDiffuseColor(QColor diffuseColor)
525 {
526     if (m_diffuseColor == diffuseColor)
527         return;
528 
529     m_diffuseColor = diffuseColor;
530     emit diffuseColorChanged(m_diffuseColor);
531     markDirty(DiffuseDirty);
532 }
533 
setDiffuseMap(QQuick3DTexture * diffuseMap)534 void QQuick3DDefaultMaterial::setDiffuseMap(QQuick3DTexture *diffuseMap)
535 {
536     if (m_diffuseMap == diffuseMap)
537         return;
538 
539     updatePropertyListener(diffuseMap, m_diffuseMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("diffuseMap"), m_connections, [this](QQuick3DObject *n) {
540         setDiffuseMap(qobject_cast<QQuick3DTexture *>(n));
541     });
542 
543     m_diffuseMap = diffuseMap;
544     emit diffuseMapChanged(m_diffuseMap);
545     markDirty(DiffuseDirty);
546 }
547 
setEmissiveFactor(float emissiveFactor)548 void QQuick3DDefaultMaterial::setEmissiveFactor(float emissiveFactor)
549 {
550     emissiveFactor = qBound(0.0f, emissiveFactor, 1.0f);
551     if (qFuzzyCompare(m_emissiveFactor, emissiveFactor))
552         return;
553 
554     m_emissiveFactor = emissiveFactor;
555     emit emissiveFactorChanged(m_emissiveFactor);
556     markDirty(EmissiveDirty);
557 }
558 
setEmissiveMap(QQuick3DTexture * emissiveMap)559 void QQuick3DDefaultMaterial::setEmissiveMap(QQuick3DTexture *emissiveMap)
560 {
561     if (m_emissiveMap == emissiveMap)
562         return;
563 
564     updatePropertyListener(emissiveMap, m_emissiveMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("emissiveMap"), m_connections, [this](QQuick3DObject *n) {
565         setEmissiveMap(qobject_cast<QQuick3DTexture *>(n));
566     });
567 
568     m_emissiveMap = emissiveMap;
569     emit emissiveMapChanged(m_emissiveMap);
570     markDirty(EmissiveDirty);
571 }
572 
setEmissiveColor(QColor emissiveColor)573 void QQuick3DDefaultMaterial::setEmissiveColor(QColor emissiveColor)
574 {
575     if (m_emissiveColor == emissiveColor)
576         return;
577 
578     m_emissiveColor = emissiveColor;
579     emit emissiveColorChanged(m_emissiveColor);
580     markDirty(EmissiveDirty);
581 }
582 
setSpecularReflectionMap(QQuick3DTexture * specularReflectionMap)583 void QQuick3DDefaultMaterial::setSpecularReflectionMap(QQuick3DTexture *specularReflectionMap)
584 {
585     if (m_specularReflectionMap == specularReflectionMap)
586         return;
587 
588     updatePropertyListener(specularReflectionMap, m_specularReflectionMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("specularReflectionMap"), m_connections, [this](QQuick3DObject *n) {
589         setSpecularReflectionMap(qobject_cast<QQuick3DTexture *>(n));
590     });
591 
592     m_specularReflectionMap = specularReflectionMap;
593     emit specularReflectionMapChanged(m_specularReflectionMap);
594     markDirty(SpecularDirty);
595 }
596 
setSpecularMap(QQuick3DTexture * specularMap)597 void QQuick3DDefaultMaterial::setSpecularMap(QQuick3DTexture *specularMap)
598 {
599     if (m_specularMap == specularMap)
600         return;
601 
602     updatePropertyListener(specularMap, m_specularMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("specularMap"), m_connections, [this](QQuick3DObject *n) {
603         setSpecularMap(qobject_cast<QQuick3DTexture *>(n));
604     });
605 
606     m_specularMap = specularMap;
607     emit specularMapChanged(m_specularMap);
608     markDirty(SpecularDirty);
609 }
610 
setSpecularModel(QQuick3DDefaultMaterial::SpecularModel specularModel)611 void QQuick3DDefaultMaterial::setSpecularModel(QQuick3DDefaultMaterial::SpecularModel specularModel)
612 {
613     if (m_specularModel == specularModel)
614         return;
615 
616     m_specularModel = specularModel;
617     emit specularModelChanged(m_specularModel);
618     markDirty(SpecularDirty);
619 }
620 
setSpecularTint(QColor specularTint)621 void QQuick3DDefaultMaterial::setSpecularTint(QColor specularTint)
622 {
623     if (m_specularTint == specularTint)
624         return;
625 
626     m_specularTint = specularTint;
627     emit specularTintChanged(m_specularTint);
628     markDirty(SpecularDirty);
629 }
630 
setIndexOfRefraction(float indexOfRefraction)631 void QQuick3DDefaultMaterial::setIndexOfRefraction(float indexOfRefraction)
632 {
633     if (qFuzzyCompare(m_indexOfRefraction, indexOfRefraction))
634         return;
635 
636     m_indexOfRefraction = indexOfRefraction;
637     emit indexOfRefractionChanged(m_indexOfRefraction);
638     markDirty(SpecularDirty);
639 }
640 
setFresnelPower(float fresnelPower)641 void QQuick3DDefaultMaterial::setFresnelPower(float fresnelPower)
642 {
643     if (qFuzzyCompare(m_fresnelPower, fresnelPower))
644         return;
645 
646     m_fresnelPower = fresnelPower;
647     emit fresnelPowerChanged(m_fresnelPower);
648     markDirty(SpecularDirty);
649 }
650 
setSpecularAmount(float specularAmount)651 void QQuick3DDefaultMaterial::setSpecularAmount(float specularAmount)
652 {
653     if (qFuzzyCompare(m_specularAmount, specularAmount))
654         return;
655 
656     m_specularAmount = specularAmount;
657     emit specularAmountChanged(m_specularAmount);
658     markDirty(SpecularDirty);
659 }
660 
setSpecularRoughness(float specularRoughness)661 void QQuick3DDefaultMaterial::setSpecularRoughness(float specularRoughness)
662 {
663     if (qFuzzyCompare(m_specularRoughness, specularRoughness))
664         return;
665 
666     m_specularRoughness = specularRoughness;
667     emit specularRoughnessChanged(m_specularRoughness);
668     markDirty(SpecularDirty);
669 }
670 
setRoughnessMap(QQuick3DTexture * roughnessMap)671 void QQuick3DDefaultMaterial::setRoughnessMap(QQuick3DTexture *roughnessMap)
672 {
673     if (m_roughnessMap == roughnessMap)
674         return;
675 
676     updatePropertyListener(roughnessMap, m_roughnessMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("roughnessMap"),  m_connections, [this](QQuick3DObject *n) {
677         setRoughnessMap(qobject_cast<QQuick3DTexture *>(n));
678     });
679 
680 
681     m_roughnessMap = roughnessMap;
682     emit roughnessMapChanged(m_roughnessMap);
683     markDirty(SpecularDirty);
684 }
685 
setOpacity(float opacity)686 void QQuick3DDefaultMaterial::setOpacity(float opacity)
687 {
688     if (qFuzzyCompare(m_opacity, opacity))
689         return;
690 
691     if (opacity > 1.0f)
692         opacity = 1.0f;
693 
694     if (opacity < 0.0f)
695         opacity = 0.0f;
696 
697     m_opacity = opacity;
698     emit opacityChanged(m_opacity);
699     markDirty(OpacityDirty);
700 }
701 
setOpacityMap(QQuick3DTexture * opacityMap)702 void QQuick3DDefaultMaterial::setOpacityMap(QQuick3DTexture *opacityMap)
703 {
704     if (m_opacityMap == opacityMap)
705         return;
706 
707     updatePropertyListener(opacityMap, m_opacityMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("opacityMap"), m_connections, [this](QQuick3DObject *n) {
708         setOpacityMap(qobject_cast<QQuick3DTexture *>(n));
709     });
710 
711     m_opacityMap = opacityMap;
712     emit opacityMapChanged(m_opacityMap);
713     markDirty(OpacityDirty);
714 }
715 
setBumpMap(QQuick3DTexture * bumpMap)716 void QQuick3DDefaultMaterial::setBumpMap(QQuick3DTexture *bumpMap)
717 {
718     if (m_bumpMap == bumpMap)
719         return;
720 
721     updatePropertyListener(bumpMap, m_bumpMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("bumpMap"), m_connections, [this](QQuick3DObject *n) {
722         setBumpMap(qobject_cast<QQuick3DTexture *>(n));
723     });
724 
725     m_bumpMap = bumpMap;
726     emit bumpMapChanged(m_bumpMap);
727     markDirty(BumpDirty);
728 }
729 
setBumpAmount(float bumpAmount)730 void QQuick3DDefaultMaterial::setBumpAmount(float bumpAmount)
731 {
732     if (qFuzzyCompare(m_bumpAmount, bumpAmount))
733         return;
734 
735     m_bumpAmount = bumpAmount;
736     emit bumpAmountChanged(m_bumpAmount);
737     markDirty(BumpDirty);
738 }
739 
setNormalMap(QQuick3DTexture * normalMap)740 void QQuick3DDefaultMaterial::setNormalMap(QQuick3DTexture *normalMap)
741 {
742     if (m_normalMap == normalMap)
743         return;
744 
745     updatePropertyListener(normalMap, m_normalMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("normalMap"), m_connections, [this](QQuick3DObject *n) {
746         setNormalMap(qobject_cast<QQuick3DTexture *>(n));
747     });
748 
749     m_normalMap = normalMap;
750     emit normalMapChanged(m_normalMap);
751     markDirty(NormalDirty);
752 }
753 
setTranslucencyMap(QQuick3DTexture * translucencyMap)754 void QQuick3DDefaultMaterial::setTranslucencyMap(QQuick3DTexture *translucencyMap)
755 {
756     if (m_translucencyMap == translucencyMap)
757         return;
758 
759     updatePropertyListener(translucencyMap, m_translucencyMap, QQuick3DObjectPrivate::get(this)->sceneManager, QByteArrayLiteral("translucencyMap"), m_connections, [this](QQuick3DObject *n) {
760         setTranslucencyMap(qobject_cast<QQuick3DTexture *>(n));
761     });
762 
763     m_translucencyMap = translucencyMap;
764     emit translucencyMapChanged(m_translucencyMap);
765     markDirty(TranslucencyDirty);
766 }
767 
setTranslucentFalloff(float translucentFalloff)768 void QQuick3DDefaultMaterial::setTranslucentFalloff(float translucentFalloff)
769 {
770     if (qFuzzyCompare(m_translucentFalloff, translucentFalloff))
771         return;
772 
773     m_translucentFalloff = translucentFalloff;
774     emit translucentFalloffChanged(m_translucentFalloff);
775     markDirty(TranslucencyDirty);
776 }
777 
setDiffuseLightWrap(float diffuseLightWrap)778 void QQuick3DDefaultMaterial::setDiffuseLightWrap(float diffuseLightWrap)
779 {
780     if (qFuzzyCompare(m_diffuseLightWrap, diffuseLightWrap))
781         return;
782 
783     m_diffuseLightWrap = diffuseLightWrap;
784     emit diffuseLightWrapChanged(m_diffuseLightWrap);
785     markDirty(DiffuseDirty);
786 }
787 
setVertexColorsEnabled(bool vertexColors)788 void QQuick3DDefaultMaterial::setVertexColorsEnabled(bool vertexColors)
789 {
790     if (m_vertexColorsEnabled == vertexColors)
791         return;
792 
793     m_vertexColorsEnabled = vertexColors;
794     emit vertexColorsEnabledChanged(m_vertexColorsEnabled);
795     markDirty(VertexColorsDirty);
796 }
797 
setRoughnessChannel(TextureChannelMapping channel)798 void QQuick3DDefaultMaterial::setRoughnessChannel(TextureChannelMapping channel)
799 {
800     if (m_roughnessChannel == channel)
801         return;
802     m_roughnessChannel = channel;
803     emit roughnessChannelChanged(channel);
804     markDirty(SpecularDirty);
805 }
806 
setOpacityChannel(TextureChannelMapping channel)807 void QQuick3DDefaultMaterial::setOpacityChannel(TextureChannelMapping channel)
808 {
809     if (m_opacityChannel == channel)
810         return;
811     m_opacityChannel = channel;
812     emit opacityChannelChanged(channel);
813     markDirty(OpacityDirty);
814 }
815 
setTranslucencyChannel(TextureChannelMapping channel)816 void QQuick3DDefaultMaterial::setTranslucencyChannel(TextureChannelMapping channel)
817 {
818     if (m_translucencyChannel == channel)
819         return;
820     m_translucencyChannel = channel;
821     emit translucencyChannelChanged(channel);
822     markDirty(TranslucencyDirty);
823 }
824 
825 
updateSpatialNode(QSSGRenderGraphObject * node)826 QSSGRenderGraphObject *QQuick3DDefaultMaterial::updateSpatialNode(QSSGRenderGraphObject *node)
827 {
828     if (!node) {
829         markAllDirty();
830         node = new QSSGRenderDefaultMaterial(QSSGRenderGraphObject::Type::DefaultMaterial);
831     }
832 
833     static const auto channelMapping = [](TextureChannelMapping mapping) {
834         return QSSGRenderDefaultMaterial::TextureChannelMapping(mapping);
835     };
836 
837     // Set common material properties
838     QQuick3DMaterial::updateSpatialNode(node);
839 
840     QSSGRenderDefaultMaterial *material = static_cast<QSSGRenderDefaultMaterial *>(node);
841 
842     if (m_dirtyAttributes & LightingModeDirty) {
843         material->lighting = QSSGRenderDefaultMaterial::MaterialLighting(m_lighting);
844         // If the lighthing mode changes it affects the emissive property
845         m_dirtyAttributes |= EmissiveDirty;
846     }
847 
848     if (m_dirtyAttributes & BlendModeDirty)
849         material->blendMode = QSSGRenderDefaultMaterial::MaterialBlendMode(m_blendMode);
850 
851     if (m_dirtyAttributes & DiffuseDirty) {
852         material->color = QVector4D(m_diffuseColor.redF(), m_diffuseColor.greenF(), m_diffuseColor.blueF(), m_diffuseColor.alphaF());
853         if (!m_diffuseMap)
854             material->colorMap = nullptr;
855         else
856             material->colorMap = m_diffuseMap->getRenderImage();
857 
858         material->diffuseLightWrap = m_diffuseLightWrap;
859     }
860 
861     if (m_dirtyAttributes & EmissiveDirty) {
862         if (!m_emissiveMap)
863             material->emissiveMap = nullptr;
864         else
865             material->emissiveMap = m_emissiveMap->getRenderImage();
866 
867         const float emissiveFactor = (m_lighting == NoLighting) ? 1.0f : m_emissiveFactor;
868         material->emissiveColor = QVector3D(m_emissiveColor.redF(), m_emissiveColor.greenF(), m_emissiveColor.blueF()) * emissiveFactor;
869     }
870 
871     if (m_dirtyAttributes & SpecularDirty) {
872         if (!m_specularReflectionMap)
873             material->specularReflection = nullptr;
874         else
875             material->specularReflection = m_specularReflectionMap->getRenderImage();
876 
877         if (!m_specularMap)
878             material->specularMap = nullptr;
879         else
880             material->specularMap = m_specularMap->getRenderImage();
881 
882         material->specularModel = QSSGRenderDefaultMaterial::MaterialSpecularModel(m_specularModel);
883         material->specularTint = QVector3D(m_specularTint.redF(), m_specularTint.greenF(), m_specularTint.blueF());
884         material->ior = m_indexOfRefraction;
885         material->fresnelPower = m_fresnelPower;
886         material->specularAmount = m_specularAmount;
887         material->specularRoughness = m_specularRoughness;
888         material->roughnessChannel = channelMapping(m_roughnessChannel);
889 
890         if (!m_roughnessMap)
891             material->roughnessMap = nullptr;
892         else
893             material->roughnessMap = m_roughnessMap->getRenderImage();
894     }
895 
896     if (m_dirtyAttributes & OpacityDirty) {
897         material->opacity = m_opacity;
898         material->opacityChannel = channelMapping(m_opacityChannel);
899         if (!m_opacityMap)
900             material->opacityMap = nullptr;
901         else
902             material->opacityMap = m_opacityMap->getRenderImage();
903     }
904 
905     if (m_dirtyAttributes & BumpDirty) {
906         if (!m_bumpMap)
907             material->bumpMap = nullptr;
908         else
909             material->bumpMap = m_bumpMap->getRenderImage();
910         material->bumpAmount = m_bumpAmount;
911     }
912 
913     if (m_dirtyAttributes & NormalDirty) {
914         if (!m_normalMap)
915             material->normalMap = nullptr;
916         else
917             material->normalMap = m_normalMap->getRenderImage();
918     }
919 
920     if (m_dirtyAttributes & TranslucencyDirty) {
921         if (!m_translucencyMap)
922             material->translucencyMap = nullptr;
923         else
924             material->translucencyMap = m_translucencyMap->getRenderImage();
925         material->translucentFalloff = m_translucentFalloff;
926         material->translucencyChannel = channelMapping(m_translucencyChannel);
927     }
928 
929     if (m_dirtyAttributes & VertexColorsDirty)
930         material->vertexColorsEnabled = m_vertexColorsEnabled;
931 
932     m_dirtyAttributes = 0;
933 
934     return node;
935 }
936 
itemChange(QQuick3DObject::ItemChange change,const QQuick3DObject::ItemChangeData & value)937 void QQuick3DDefaultMaterial::itemChange(QQuick3DObject::ItemChange change, const QQuick3DObject::ItemChangeData &value)
938 {
939     if (change == QQuick3DObject::ItemSceneChange)
940         updateSceneManager(value.sceneManager);
941 }
942 
updateSceneManager(const QSharedPointer<QQuick3DSceneManager> & sceneManager)943 void QQuick3DDefaultMaterial::updateSceneManager(const QSharedPointer<QQuick3DSceneManager> &sceneManager)
944 {
945     // Check all the resource value's windows, and update as necessary
946     if (sceneManager) {
947         QQuick3DObjectPrivate::refSceneManager(m_diffuseMap, sceneManager);
948         QQuick3DObjectPrivate::refSceneManager(m_emissiveMap, sceneManager);
949         QQuick3DObjectPrivate::refSceneManager(m_specularReflectionMap, sceneManager);
950         QQuick3DObjectPrivate::refSceneManager(m_specularMap, sceneManager);
951         QQuick3DObjectPrivate::refSceneManager(m_roughnessMap, sceneManager);
952         QQuick3DObjectPrivate::refSceneManager(m_opacityMap, sceneManager);
953         QQuick3DObjectPrivate::refSceneManager(m_bumpMap, sceneManager);
954         QQuick3DObjectPrivate::refSceneManager(m_normalMap, sceneManager);
955         QQuick3DObjectPrivate::refSceneManager(m_translucencyMap, sceneManager);
956     } else {
957         QQuick3DObjectPrivate::derefSceneManager(m_diffuseMap);
958         QQuick3DObjectPrivate::derefSceneManager(m_emissiveMap);
959         QQuick3DObjectPrivate::derefSceneManager(m_specularReflectionMap);
960         QQuick3DObjectPrivate::derefSceneManager(m_specularMap);
961         QQuick3DObjectPrivate::derefSceneManager(m_roughnessMap);
962         QQuick3DObjectPrivate::derefSceneManager(m_opacityMap);
963         QQuick3DObjectPrivate::derefSceneManager(m_bumpMap);
964         QQuick3DObjectPrivate::derefSceneManager(m_normalMap);
965         QQuick3DObjectPrivate::derefSceneManager(m_translucencyMap);
966     }
967 }
968 
markDirty(QQuick3DDefaultMaterial::DirtyType type)969 void QQuick3DDefaultMaterial::markDirty(QQuick3DDefaultMaterial::DirtyType type)
970 {
971     if (!(m_dirtyAttributes & quint32(type))) {
972         m_dirtyAttributes |= quint32(type);
973         update();
974     }
975 }
976 
977 QT_END_NAMESPACE
978