1/****************************************************************************
2**
3** Copyright (C) 2015 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 "qskyboxentity.h"
41#include "qskyboxentity_p.h"
42
43#include <QtCore/qtimer.h>
44#include <Qt3DRender/qfilterkey.h>
45#include <Qt3DRender/qeffect.h>
46#include <Qt3DRender/qtexture.h>
47#include <Qt3DRender/qmaterial.h>
48#include <Qt3DRender/qcullface.h>
49#include <Qt3DRender/qdepthtest.h>
50#include <Qt3DRender/qparameter.h>
51#include <Qt3DRender/qtechnique.h>
52#include <Qt3DExtras/qcuboidmesh.h>
53#include <Qt3DRender/qrenderpass.h>
54#include <Qt3DRender/qgraphicsapifilter.h>
55#include <Qt3DRender/qseamlesscubemap.h>
56#include <Qt3DRender/qshaderprogram.h>
57
58QT_BEGIN_NAMESPACE
59
60using namespace Qt3DCore;
61using namespace Qt3DRender;
62
63namespace Qt3DExtras {
64
65QSkyboxEntityPrivate::QSkyboxEntityPrivate()
66 : QEntityPrivate()
67 , m_effect(new QEffect())
68 , m_material(new QMaterial())
69 , m_skyboxTexture(new QTextureCubeMap())
70 , m_loadedTexture(new QTextureLoader())
71 , m_gl3Shader(new QShaderProgram())
72 , m_gl2es2Shader(new QShaderProgram())
73 , m_gl2Technique(new QTechnique())
74 , m_es2Technique(new QTechnique())
75 , m_gl3Technique(new QTechnique())
76 , m_filterKey(new QFilterKey)
77 , m_gl2RenderPass(new QRenderPass())
78 , m_es2RenderPass(new QRenderPass())
79 , m_gl3RenderPass(new QRenderPass())
80 , m_mesh(new QCuboidMesh())
81 , m_gammaStrengthParameter(new QParameter(QStringLiteral("gammaStrength"), 0.0f))
82 , m_textureParameter(new QParameter(QStringLiteral("skyboxTexture"), m_skyboxTexture))
83 , m_posXImage(new QTextureImage())
84 , m_posYImage(new QTextureImage())
85 , m_posZImage(new QTextureImage())
86 , m_negXImage(new QTextureImage())
87 , m_negYImage(new QTextureImage())
88 , m_negZImage(new QTextureImage())
89 , m_extension(QStringLiteral(".png"))
90 , m_hasPendingReloadTextureCall(false)
91{
92 m_loadedTexture->setGenerateMipMaps(false);
93}
94
95/*!
96 * \internal
97 */
98void QSkyboxEntityPrivate::init()
99{
100 m_gl3Shader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/gl3/skybox.vert"))));
101 m_gl3Shader->setFragmentShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/gl3/skybox.frag"))));
102 m_gl2es2Shader->setVertexShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/es2/skybox.vert"))));
103 m_gl2es2Shader->setFragmentShaderCode(QShaderProgram::loadSource(sourceUrl: QUrl(QStringLiteral("qrc:/shaders/es2/skybox.frag"))));
104
105 m_gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
106 m_gl3Technique->graphicsApiFilter()->setMajorVersion(3);
107 m_gl3Technique->graphicsApiFilter()->setMinorVersion(3);
108 m_gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
109
110 m_gl2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
111 m_gl2Technique->graphicsApiFilter()->setMajorVersion(2);
112 m_gl2Technique->graphicsApiFilter()->setMinorVersion(0);
113 m_gl2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
114
115 m_es2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES);
116 m_es2Technique->graphicsApiFilter()->setMajorVersion(2);
117 m_es2Technique->graphicsApiFilter()->setMinorVersion(0);
118 m_es2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
119
120 m_filterKey->setParent(m_effect);
121 m_filterKey->setName(QStringLiteral("renderingStyle"));
122 m_filterKey->setValue(QStringLiteral("forward"));
123
124 m_gl3Technique->addFilterKey(filterKey: m_filterKey);
125 m_gl2Technique->addFilterKey(filterKey: m_filterKey);
126 m_es2Technique->addFilterKey(filterKey: m_filterKey);
127
128 m_gl3RenderPass->setShaderProgram(m_gl3Shader);
129 m_gl2RenderPass->setShaderProgram(m_gl2es2Shader);
130 m_es2RenderPass->setShaderProgram(m_gl2es2Shader);
131
132 QCullFace *cullFront = new QCullFace();
133 cullFront->setMode(QCullFace::Front);
134 QDepthTest *depthTest = new QDepthTest();
135 depthTest->setDepthFunction(QDepthTest::LessOrEqual);
136 QSeamlessCubemap *seamlessCubemap = new QSeamlessCubemap();
137
138 m_gl3RenderPass->addRenderState(state: cullFront);
139 m_gl3RenderPass->addRenderState(state: depthTest);
140 m_gl3RenderPass->addRenderState(state: seamlessCubemap);
141 m_gl2RenderPass->addRenderState(state: cullFront);
142 m_gl2RenderPass->addRenderState(state: depthTest);
143 m_es2RenderPass->addRenderState(state: cullFront);
144 m_es2RenderPass->addRenderState(state: depthTest);
145
146 m_gl3Technique->addRenderPass(pass: m_gl3RenderPass);
147 m_gl2Technique->addRenderPass(pass: m_gl2RenderPass);
148 m_es2Technique->addRenderPass(pass: m_es2RenderPass);
149
150 m_effect->addTechnique(t: m_gl3Technique);
151 m_effect->addTechnique(t: m_gl2Technique);
152 m_effect->addTechnique(t: m_es2Technique);
153
154 m_material->setEffect(m_effect);
155 m_material->addParameter(parameter: m_gammaStrengthParameter);
156 m_material->addParameter(parameter: m_textureParameter);
157
158 m_mesh->setXYMeshResolution(QSize(2, 2));
159 m_mesh->setXZMeshResolution(QSize(2, 2));
160 m_mesh->setYZMeshResolution(QSize(2, 2));
161
162 m_posXImage->setFace(QTextureCubeMap::CubeMapPositiveX);
163 m_posXImage->setMirrored(false);
164 m_posYImage->setFace(QTextureCubeMap::CubeMapPositiveY);
165 m_posYImage->setMirrored(false);
166 m_posZImage->setFace(QTextureCubeMap::CubeMapPositiveZ);
167 m_posZImage->setMirrored(false);
168 m_negXImage->setFace(QTextureCubeMap::CubeMapNegativeX);
169 m_negXImage->setMirrored(false);
170 m_negYImage->setFace(QTextureCubeMap::CubeMapNegativeY);
171 m_negYImage->setMirrored(false);
172 m_negZImage->setFace(QTextureCubeMap::CubeMapNegativeZ);
173 m_negZImage->setMirrored(false);
174
175 m_skyboxTexture->setMagnificationFilter(QTextureCubeMap::Linear);
176 m_skyboxTexture->setMinificationFilter(QTextureCubeMap::Linear);
177 m_skyboxTexture->setGenerateMipMaps(false);
178 m_skyboxTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::ClampToEdge));
179
180 m_skyboxTexture->addTextureImage(textureImage: m_posXImage);
181 m_skyboxTexture->addTextureImage(textureImage: m_posYImage);
182 m_skyboxTexture->addTextureImage(textureImage: m_posZImage);
183 m_skyboxTexture->addTextureImage(textureImage: m_negXImage);
184 m_skyboxTexture->addTextureImage(textureImage: m_negYImage);
185 m_skyboxTexture->addTextureImage(textureImage: m_negZImage);
186
187 q_func()->addComponent(comp: m_mesh);
188 q_func()->addComponent(comp: m_material);
189}
190
191/*!
192 * \internal
193 */
194void QSkyboxEntityPrivate::reloadTexture()
195{
196 if (!m_hasPendingReloadTextureCall) {
197 m_hasPendingReloadTextureCall = true;
198 QTimer::singleShot(interval: 0, slot: [this] {
199 if (m_extension == QStringLiteral(".dds")) {
200 m_loadedTexture->setSource(QUrl(m_baseName + m_extension));
201 m_textureParameter->setValue(QVariant::fromValue(value: m_loadedTexture));
202 } else {
203 m_posXImage->setSource(QUrl(m_baseName + QStringLiteral("_posx") + m_extension));
204 m_posYImage->setSource(QUrl(m_baseName + QStringLiteral("_posy") + m_extension));
205 m_posZImage->setSource(QUrl(m_baseName + QStringLiteral("_posz") + m_extension));
206 m_negXImage->setSource(QUrl(m_baseName + QStringLiteral("_negx") + m_extension));
207 m_negYImage->setSource(QUrl(m_baseName + QStringLiteral("_negy") + m_extension));
208 m_negZImage->setSource(QUrl(m_baseName + QStringLiteral("_negz") + m_extension));
209 m_textureParameter->setValue(QVariant::fromValue(value: m_skyboxTexture));
210 }
211 m_hasPendingReloadTextureCall = false;
212 });
213 }
214}
215
216/*!
217 * \class Qt3DExtras::QSkyboxEntity
218 * \inheaderfile Qt3DExtras/QSkyboxEntity
219 * \inmodule Qt3DExtras
220 *
221 * \brief Qt3DExtras::QSkyboxEntity is a convenience Qt3DCore::QEntity subclass that can
222 * be used to insert a skybox in a 3D scene.
223 *
224 * By specifying a base name and an extension, Qt3DExtras::QSkyboxEntity
225 * will take care of building a TextureCubeMap to be rendered at runtime. The
226 * images in the source directory should match the pattern:
227 * \b base name + * "_posx|_posy|_posz|_negx|_negy|_negz" + extension
228 *
229 * By default the extension defaults to .png.
230 *
231 * Be sure to disable frustum culling in the FrameGraph through which the
232 * skybox rendering happens.
233 *
234 * \note Please note that you shouldn't try to render a skybox with an
235 * orthographic projection.
236 *
237 * \since 5.5
238 */
239
240/*!
241 * \qmltype SkyboxEntity
242 * \instantiates Qt3DExtras::QSkyboxEntity
243 * \inqmlmodule Qt3D.Extras
244 *
245 * \brief SkyboxEntity is a convenience Entity subclass that can be used to
246 * insert a skybox in a 3D scene.
247 *
248 * By specifying a base name and an extension, SkyboxEntity will take care of
249 * building a TextureCubeMap to be rendered at runtime. The images in the
250 * source directory should match the pattern: \b base name + *
251 * "_posx|_posy|_posz|_negx|_negy|_negz" + extension
252 *
253 * By default the extension defaults to .png.
254 *
255 * Be sure to disable frustum culling in the FrameGraph through which the
256 * skybox rendering happens.
257 *
258 * \note Please note that you shouldn't try to render a skybox with an
259 * orthographic projection.
260 *
261 * \since 5.5
262 */
263
264/*!
265 * Constructs a new Qt3DExtras::QSkyboxEntity object with \a parent as parent.
266 */
267QSkyboxEntity::QSkyboxEntity(QNode *parent)
268 : QEntity(*new QSkyboxEntityPrivate, parent)
269{
270 d_func()->init();
271}
272
273/*! \internal */
274QSkyboxEntity::~QSkyboxEntity()
275{
276}
277
278/*!
279 * Sets the base name to \a baseName.
280 */
281void QSkyboxEntity::setBaseName(const QString &baseName)
282{
283 Q_D(QSkyboxEntity);
284 if (baseName != d->m_baseName) {
285 d->m_baseName = baseName;
286 emit baseNameChanged(path: baseName);
287 d->reloadTexture();
288 }
289}
290/*!
291 \property QSkyboxEntity::baseName
292
293 Contains the base name of the Skybox.
294*/
295/*!
296 \qmlproperty string QSkyboxEntity::baseName
297
298 Contains the base name of the Skybox.
299*/
300/*!
301 * Returns the base name of the Skybox.
302 */
303QString QSkyboxEntity::baseName() const
304{
305 Q_D(const QSkyboxEntity);
306 return d->m_baseName;
307}
308
309/*!
310 * Sets the extension to \a extension.
311 */
312void QSkyboxEntity::setExtension(const QString &extension)
313{
314 Q_D(QSkyboxEntity);
315 if (extension != d->m_extension) {
316 d->m_extension = extension;
317 emit extensionChanged(extension);
318 d->reloadTexture();
319 }
320}
321
322/*!
323 \property QSkyboxEntity::extension
324
325 Contains the extension of the filename for the skybox image, including the
326 leading '.'.
327
328 The default value is: .png
329*/
330
331/*!
332 \qmlproperty string QSkyboxEntity::extension
333
334 Contains the extension of the filename for the skybox image, including the
335 leading '.'.
336
337 The default value is: .png
338*/
339/*!
340 * Returns the extension
341 */
342QString QSkyboxEntity::extension() const
343{
344 Q_D(const QSkyboxEntity);
345 return d->m_extension;
346}
347
348/*!
349 * Sets the gamma correction enable state to \a enabled.
350 * \since 5.9
351 */
352void QSkyboxEntity::setGammaCorrectEnabled(bool enabled)
353{
354 Q_D(QSkyboxEntity);
355 if (enabled != isGammaCorrectEnabled()) {
356 d->m_gammaStrengthParameter->setValue(enabled ? 1.0f : 0.0f);
357 emit gammaCorrectEnabledChanged(enabled);
358 }
359}
360
361/*!
362 * Returns true if gamma correction is enabled for this skybox.
363 * \since 5.9
364 */
365bool QSkyboxEntity::isGammaCorrectEnabled() const
366{
367 Q_D(const QSkyboxEntity);
368 return !qFuzzyIsNull(f: d->m_gammaStrengthParameter->value().toFloat());
369}
370
371} // namespace Qt3DExtras
372
373/*!
374 \property QSkyboxEntity::gammaCorrect
375
376 A boolean indicating whether gamma correction is enabled.
377 \since 5.9
378*/
379/*!
380 \qmlproperty bool QSkyboxEntity::gammaCorrect
381
382 A boolean indicating whether gamma correction is enabled.
383 \since 5.9
384*/
385QT_END_NAMESPACE
386

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