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 "qenvironmentlight.h"
5#include "qenvironmentlight_p.h"
6#include "qabstracttexture.h"
7#include <QVector3D>
8
9#include <cmath>
10
11QT_BEGIN_NAMESPACE
12
13namespace Qt3DRender
14{
15
16/*!
17 * \qmltype EnvironmentLight
18 * \inqmlmodule Qt3D.Render
19 * \instantiates Qt3DRender::QEnvironmentLight
20 * \brief Encapsulate an environment light object in a Qt 3D scene.
21 * \since 5.9
22 *
23 * EnvironmentLight uses cubemaps to implement image-based lighting (IBL), a technique
24 * often used in conjunction with physically-based rendering (PBR). The cubemaps are
25 * typically expected be based on high dynamic range (HDR) images, with a suitable
26 * OpenGL format (such as RGBA16F) that can handle the increased range of values.
27 *
28 * There are a variety of tools that can be used to produce the cubemaps needed by
29 * EnvironmentLight. Some examples include
30 *
31 * \list
32 * \li \l {https://github.com/dariomanesku/cmftStudio}{cmftStudio}
33 * \li \l {https://github.com/derkreature/IBLBaker}{IBLBaker}
34 * \li \l {https://www.knaldtech.com/lys/}{Lys}
35 * \endlist
36 *
37 * \l {https://hdrihaven.com/hdris/}{HDRI Haven} provides many CC0-licensed HDR images
38 * that can be used as source material for the above tools.
39 */
40
41QEnvironmentLightPrivate::QEnvironmentLightPrivate()
42 : m_shaderData(new QShaderData)
43 , m_irradiance(nullptr)
44 , m_specular(nullptr)
45{
46}
47
48QEnvironmentLightPrivate::~QEnvironmentLightPrivate()
49{
50}
51
52void QEnvironmentLightPrivate::_q_updateEnvMapsSize()
53{
54 QVector3D irradianceSize;
55 if (m_irradiance != nullptr)
56 irradianceSize = QVector3D(m_irradiance->width(),
57 m_irradiance->height(),
58 m_irradiance->depth());
59 m_shaderData->setProperty(name: "irradianceSize", value: QVariant::fromValue(value: irradianceSize));
60
61 QVector3D specularSize;
62 if (m_specular != nullptr)
63 specularSize = QVector3D(m_specular->width(),
64 m_specular->height(),
65 m_specular->depth());
66 m_shaderData->setProperty(name: "specularSize", value: QVariant::fromValue(value: specularSize));
67
68 const int levels = int(std::log2(x: specularSize.x() > 0.0f ? specularSize.x() : 1.0f)) + 1;
69 m_shaderData->setProperty(name: "specularMipLevels", value: QVariant::fromValue(value: levels));
70}
71
72/*!
73 \class Qt3DRender::QEnvironmentLight
74 \inmodule Qt3DRender
75 \brief Encapsulate an environment light object in a Qt 3D scene.
76 \since 5.9
77
78 QEnvironmentLight uses cubemaps to implement image-based lighting (IBL), a technique
79 often used in conjunction with physically-based rendering (PBR). The cubemaps are
80 typically expected be based on high dynamic range (HDR) images, with a suitable
81 OpenGL format (such as RGBA16F) that can handle the increased range of values.
82
83 There are a variety of tools that can be used to produce the cubemaps needed by
84 QEnvironmentLight. Some examples include
85
86 \list
87 \li \l {https://github.com/dariomanesku/cmftStudio}{cmftStudio}
88 \li \l {https://github.com/derkreature/IBLBaker}{IBLBaker}
89 \li \l {https://www.knaldtech.com/lys/}{Lys}
90 \endlist
91
92 \l {https://hdrihaven.com/hdris/}{HDRI Haven} provides many CC0-licensed HDR images
93 that can be used as source material for the above tools.
94*/
95
96QEnvironmentLight::QEnvironmentLight(Qt3DCore::QNode *parent)
97 : QComponent(*new QEnvironmentLightPrivate, parent)
98{
99 Q_D(QEnvironmentLight);
100 d->m_shaderData->setParent(this);
101}
102
103/*! \internal */
104QEnvironmentLight::QEnvironmentLight(QEnvironmentLightPrivate &dd, QNode *parent)
105 : QComponent(dd, parent)
106{
107 Q_D(QEnvironmentLight);
108 d->m_shaderData->setParent(this);
109}
110
111QEnvironmentLight::~QEnvironmentLight()
112{
113}
114
115/*!
116 \qmlproperty Texture EnvironmentLight::irradiance
117
118 Holds the current environment irradiance map texture.
119
120 By default, the environment irradiance texture is null.
121
122 \note The exact meaning and use of this property is up to the
123 material implementation.
124*/
125
126/*!
127 \property QEnvironmentLight::irradiance
128
129 Holds the current environment irradiance map texture.
130
131 By default, the environment irradiance texture is null.
132
133 \note The exact meaning and use of this property is up to the
134 material implementation.
135*/
136QAbstractTexture *QEnvironmentLight::irradiance() const
137{
138 Q_D(const QEnvironmentLight);
139 return d->m_irradiance;
140}
141
142/*!
143 \qmlproperty Texture EnvironmentLight::specular
144
145 Holds the current environment specular map texture.
146
147 By default, the environment specular texture is null.
148
149 \note The exact meaning and use of this property is up to the
150 material implementation.
151*/
152
153/*!
154 \property QEnvironmentLight::specular
155
156 Holds the current environment specular map texture.
157
158 By default, the environment specular texture is null.
159
160 \note The exact meaning and use of this property is up to the
161 material implementation.
162*/
163QAbstractTexture *QEnvironmentLight::specular() const
164{
165 Q_D(const QEnvironmentLight);
166 return d->m_specular;
167}
168
169void QEnvironmentLight::setIrradiance(QAbstractTexture *i)
170{
171 Q_D(QEnvironmentLight);
172 if (irradiance() == i)
173 return;
174
175 if (irradiance()) {
176 d->unregisterDestructionHelper(node: d->m_irradiance);
177 QObject::disconnect(sender: d->m_irradiance, SIGNAL(widthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
178 QObject::disconnect(sender: d->m_irradiance, SIGNAL(heightChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
179 QObject::disconnect(sender: d->m_irradiance, SIGNAL(depthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
180 }
181
182 if (i && !i->parent())
183 i->setParent(this);
184
185 d->m_irradiance = i;
186 d->m_shaderData->setProperty(name: "irradiance", value: QVariant::fromValue(value: i));
187 d->_q_updateEnvMapsSize();
188
189 if (i) {
190 d->registerDestructionHelper(node: i, func: &QEnvironmentLight::setIrradiance, i);
191 QObject::connect(sender: d->m_irradiance, SIGNAL(widthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
192 QObject::connect(sender: d->m_irradiance, SIGNAL(heightChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
193 QObject::connect(sender: d->m_irradiance, SIGNAL(depthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
194 }
195
196 emit irradianceChanged(environmentIrradiance: i);
197}
198
199void QEnvironmentLight::setSpecular(QAbstractTexture *s)
200{
201 Q_D(QEnvironmentLight);
202 if (specular() == s)
203 return;
204
205 if (specular()) {
206 d->unregisterDestructionHelper(node: d->m_specular);
207 QObject::disconnect(sender: d->m_specular, SIGNAL(widthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
208 QObject::disconnect(sender: d->m_specular, SIGNAL(heightChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
209 QObject::disconnect(sender: d->m_specular, SIGNAL(depthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
210 }
211
212 if (s && !s->parent())
213 s->setParent(this);
214
215 d->m_specular = s;
216 d->m_shaderData->setProperty(name: "specular", value: QVariant::fromValue(value: s));
217 d->_q_updateEnvMapsSize();
218
219 if (s) {
220 d->registerDestructionHelper(node: s, func: &QEnvironmentLight::setSpecular, s);
221 QObject::connect(sender: d->m_specular, SIGNAL(widthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
222 QObject::connect(sender: d->m_specular, SIGNAL(heightChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
223 QObject::connect(sender: d->m_specular, SIGNAL(depthChanged(int)), receiver: this, SLOT(_q_updateEnvMapsSize()));
224 }
225
226 emit specularChanged(environmentSpecular: s);
227}
228
229} // namespace Qt3DRender
230
231QT_END_NAMESPACE
232
233#include "moc_qenvironmentlight.cpp"
234

source code of qt3d/src/render/lights/qenvironmentlight.cpp