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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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