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 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | namespace 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 | |
41 | QEnvironmentLightPrivate::QEnvironmentLightPrivate() |
42 | : m_shaderData(new QShaderData) |
43 | , m_irradiance(nullptr) |
44 | , m_specular(nullptr) |
45 | { |
46 | } |
47 | |
48 | QEnvironmentLightPrivate::~QEnvironmentLightPrivate() |
49 | { |
50 | } |
51 | |
52 | void 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 | |
96 | QEnvironmentLight::QEnvironmentLight(Qt3DCore::QNode *parent) |
97 | : QComponent(*new QEnvironmentLightPrivate, parent) |
98 | { |
99 | Q_D(QEnvironmentLight); |
100 | d->m_shaderData->setParent(this); |
101 | } |
102 | |
103 | /*! \internal */ |
104 | QEnvironmentLight::QEnvironmentLight(QEnvironmentLightPrivate &dd, QNode *parent) |
105 | : QComponent(dd, parent) |
106 | { |
107 | Q_D(QEnvironmentLight); |
108 | d->m_shaderData->setParent(this); |
109 | } |
110 | |
111 | QEnvironmentLight::~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 | */ |
136 | QAbstractTexture *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 | */ |
163 | QAbstractTexture *QEnvironmentLight::specular() const |
164 | { |
165 | Q_D(const QEnvironmentLight); |
166 | return d->m_specular; |
167 | } |
168 | |
169 | void 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 | |
199 | void 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 | |
231 | QT_END_NAMESPACE |
232 | |
233 | #include "moc_qenvironmentlight.cpp" |
234 | |