QGIS API Documentation 4.1.0-Master (01362494303)
Loading...
Searching...
No Matches
qgsskyboxentity.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsskyboxentity.cpp
3 --------------------------------------
4 Date : August 2020
5 Copyright : (C) 2020 by Belgacem Nedjima
6 Email : gb uderscore nedjima at esi dot dz
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsskyboxentity.h"
17
18#include "qgsapplication.h"
19#include "qgsimagecache.h"
20#include "qgsimagetexture.h"
21
22#include <QString>
23#include <QUrl>
24#include <Qt3DCore/QEntity>
25#include <Qt3DExtras/QCuboidMesh>
26#include <Qt3DRender/QCullFace>
27#include <Qt3DRender/QDepthTest>
28#include <Qt3DRender/QEffect>
29#include <Qt3DRender/QFilterKey>
30#include <Qt3DRender/QGraphicsApiFilter>
31#include <Qt3DRender/QMaterial>
32#include <Qt3DRender/QParameter>
33#include <Qt3DRender/QRenderPass>
34#include <Qt3DRender/QSeamlessCubemap>
35#include <Qt3DRender/QShaderProgram>
36#include <Qt3DRender/QTechnique>
37#include <Qt3DRender/QTextureImage>
38
39#include "moc_qgsskyboxentity.cpp"
40
41using namespace Qt::StringLiterals;
42
44 : Qt3DCore::QEntity( parent )
45 , mEffect( new Qt3DRender::QEffect( this ) )
46 , mMaterial( new Qt3DRender::QMaterial( this ) )
47 , mGl3Technique( new Qt3DRender::QTechnique( this ) )
48 , mFilterKey( new Qt3DRender::QFilterKey( this ) )
49 , mGl3RenderPass( new Qt3DRender::QRenderPass( this ) )
50 , mMesh( new Qt3DExtras::QCuboidMesh( this ) )
51 , mGammaStrengthParameter( new Qt3DRender::QParameter( u"gammaStrength"_s, 0.0f ) )
52 , mTextureParameter( new Qt3DRender::QParameter( this ) )
53{
54 mGl3Technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
55 mGl3Technique->graphicsApiFilter()->setMajorVersion( 3 );
56 mGl3Technique->graphicsApiFilter()->setMinorVersion( 3 );
57 mGl3Technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
58
59 mFilterKey->setParent( mEffect );
60 mFilterKey->setName( u"renderingStyle"_s );
61 mFilterKey->setValue( u"forward"_s );
62
63 mGl3Technique->addFilterKey( mFilterKey );
64
65 Qt3DRender::QCullFace *cullFront = new Qt3DRender::QCullFace();
66 cullFront->setMode( Qt3DRender::QCullFace::Front );
67 Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest();
68 depthTest->setDepthFunction( Qt3DRender::QDepthTest::LessOrEqual );
69 Qt3DRender::QSeamlessCubemap *seamlessCubemap = new Qt3DRender::QSeamlessCubemap();
70
71 mGl3RenderPass->addRenderState( cullFront );
72 mGl3RenderPass->addRenderState( depthTest );
73 mGl3RenderPass->addRenderState( seamlessCubemap );
74
75 mGl3Technique->addRenderPass( mGl3RenderPass );
76
77 mEffect->addTechnique( mGl3Technique );
78
79 mMaterial->setEffect( mEffect );
80 mMaterial->addParameter( mGammaStrengthParameter );
81 mMaterial->addParameter( mTextureParameter );
82
83 mMesh->setXYMeshResolution( QSize( 2, 2 ) );
84 mMesh->setXZMeshResolution( QSize( 2, 2 ) );
85 mMesh->setYZMeshResolution( QSize( 2, 2 ) );
86
87 addComponent( mMesh );
88 addComponent( mMaterial );
89}
90
91#if ENABLE_PANORAMIC_SKYBOX
92// Panoramic skybox
93
94QgsPanoramicSkyboxEntity::QgsPanoramicSkyboxEntity( const QString &texturePath, QNode *parent )
95 : QgsSkyboxEntity( parent )
96 , mTexturePath( texturePath )
97 , mLoadedTexture( new Qt3DRender::QTextureLoader( parent ) )
98 , mGlShader( new Qt3DRender::QShaderProgram( this ) )
99{
100 mLoadedTexture->setGenerateMipMaps( false );
101 mGlShader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.vert"_s ) ) );
102 mGlShader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/hdr_skybox.frag"_s ) ) );
103 mGl3RenderPass->setShaderProgram( mGlShader );
104
105 mTextureParameter->setName( "skyboxTexture" );
106 mTextureParameter->setValue( QVariant::fromValue( mLoadedTexture ) );
107
108 reloadTexture();
109}
110
111void QgsPanoramicSkyboxEntity::reloadTexture()
112{
113 mLoadedTexture->setSource( QUrl::fromUserInput( mTexturePath ) );
114}
115
116#endif
117
118// 6 faces skybox
119
121 Qgis::SkyboxCubeMapping mapping, const QString &posX, const QString &posY, const QString &posZ, const QString &negX, const QString &negY, const QString &negZ, Qt3DCore::QNode *parent
122)
123 : QgsSkyboxEntity( parent )
124 , mMappingType( mapping )
125 , mSourcePosX( posX )
126 , mSourcePosY( posY )
127 , mSourcePosZ( posZ )
128 , mSourceNegX( negX )
129 , mSourceNegY( negY )
130 , mSourceNegZ( negZ )
131 , mGlShader( new Qt3DRender::QShaderProgram() )
132{
133 init();
134 reloadTexture();
135}
136
141
142void QgsCubeFacesSkyboxEntity::init()
143{
144 mGlShader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.vert"_s ) ) );
145 mGlShader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.frag"_s ) ) );
146 mGl3RenderPass->setShaderProgram( mGlShader );
147
148 mTextureParameter->setName( "skyboxTexture" );
149}
150
151void QgsCubeFacesSkyboxEntity::reloadTexture()
152{
153 auto *newCubeMap = new Qt3DRender::QTextureCubeMap( this );
154 newCubeMap->setMagnificationFilter( Qt3DRender::QTextureCubeMap::Linear );
155 newCubeMap->setMinificationFilter( Qt3DRender::QTextureCubeMap::Linear );
156 newCubeMap->setGenerateMipMaps( false );
157 newCubeMap->setWrapMode( Qt3DRender::QTextureWrapMode( Qt3DRender::QTextureWrapMode::Repeat ) );
158 newCubeMap->setFormat( Qt3DRender::QAbstractTexture::SRGB8_Alpha8 );
159
160 // all faces must have the SAME size, so take the maximum size from the input images
161 int maxSize = 0;
162 for ( const QString &texturePath : { mSourcePosX, mSourcePosY, mSourcePosZ, mSourceNegX, mSourceNegY, mSourceNegZ } )
163 {
164 const QSize size = QgsApplication::imageCache()->originalSize( texturePath, true );
165 maxSize = std::max( maxSize, std::max( size.width(), size.height() ) );
166 }
167
168 QList<Qt3DRender::QAbstractTextureImage *> newFaces;
169 const QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs = generateFaceTransformation();
170 const QSize faceSize( maxSize, maxSize );
171 for ( auto it = faceConfigs.begin(); it != faceConfigs.end(); ++it )
172 {
173 const Qt3DRender::QTextureCubeMap::CubeMapFace face = it.key();
174 const FaceTransformation &config = it.value();
175
176 bool fitsInCache = false;
177 const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( config.path, faceSize, true, 1.0, fitsInCache );
178 ( void ) fitsInCache;
179 QImage finalImage = textureSourceImage;
180 if ( finalImage.isNull() )
181 {
182 finalImage = QImage( faceSize.width(), faceSize.height(), QImage::Format_RGB32 );
183 finalImage.fill( Qt::white );
184 QPainter p;
185 p.begin( &finalImage );
186 //draw a checkerboard background for missing texture images
187 uchar pixDataRGB[] = { 150, 150, 150, 255, 100, 100, 100, 255, 100, 100, 100, 255, 150, 150, 150, 255 };
188 const QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
189 const QPixmap pix = QPixmap::fromImage( img.scaled( 8, 8 ) );
190 QBrush checkerBrush;
191 checkerBrush.setTexture( pix );
192 p.fillRect( finalImage.rect(), checkerBrush );
193 p.end();
194 }
195 else if ( config.mirrorHorizontal || config.mirrorVertical )
196 {
197 finalImage = finalImage.mirrored( config.mirrorHorizontal, config.mirrorVertical );
198 }
199
200 auto textureImage = new QgsImageTexture( finalImage, newCubeMap );
201 textureImage->setFace( face );
202 newCubeMap->addTextureImage( textureImage );
203 newFaces.push_back( textureImage );
204 }
205
206 mTextureParameter->setValue( QVariant::fromValue( newCubeMap ) );
207
208 if ( mCubeMap )
209 {
210 mCubeMap->deleteLater();
211 }
212 mCubeMap = newCubeMap;
213 mFacesTextureImages = newFaces;
214}
215
216QMap<Qt3DRender::QAbstractTexture::CubeMapFace, QgsCubeFacesSkyboxEntity::FaceTransformation> QgsCubeFacesSkyboxEntity::generateFaceTransformation() const
217{
218 QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs;
219 switch ( mMappingType )
220 {
222 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
223 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
224 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosY, false, false };
225 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegY, false, false };
226 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, false, false };
227 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, false, false };
228 break;
229
231 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
232 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
233 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, false };
234 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, false };
235 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, false };
236 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, false };
237 break;
238
240 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, true };
241 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, true };
242 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, true };
243 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, true };
244 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, true };
245 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, true };
246 break;
247
249 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosY, true, false };
250 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegY, true, false };
251 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosX, true, false };
252 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegX, true, false };
253 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, true, false };
254 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, true, false };
255 break;
256
258 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, true, false };
259 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, true, false };
260 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosZ, true, false };
261 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegZ, true, false };
262 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, true, false };
263 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, true, false };
264 break;
265 }
266
267 return faceConfigs;
268}
SkyboxCubeMapping
Skybox texture cube mapping for distinct texture skyboxes.
Definition qgis.h:4385
@ UnrealEngineZUp
Unreal engine standard (+X Forward, +Y Right, +Z Up, Left-handed).
Definition qgis.h:4389
@ NativeZUp
Textures exported for Z-up (+X Right, +Y Forward, +Z Up).
Definition qgis.h:4386
@ LeftHandedYUpMirrored
Left-Handed, Y-Up coordinate systems (e.g., Unity convention +X Right, +Y Top, +Z Forward,...
Definition qgis.h:4390
@ GodotYUp
Godot standard (+X Right, +Y Top, -Z Forward, with vertical flip).
Definition qgis.h:4388
@ OpenGLYUp
Standard OpenGL/WebGL standard (+X Right, +Y Top, -Z Forward).
Definition qgis.h:4387
SkyboxType
Skybox types for 3D scenes.
Definition qgis.h:4372
@ DistinctTextures
Cube map built from distinct textures.
Definition qgis.h:4373
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
Qgis::SkyboxType type() const override
Returns the type of the skybox.
QgsCubeFacesSkyboxEntity(Qgis::SkyboxCubeMapping mapping, const QString &posX, const QString &posY, const QString &posZ, const QString &negX, const QString &negY, const QString &negZ, Qt3DCore::QNode *parent=nullptr)
Constructs a skybox from 6 different images.
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
Base class for all skybox types.
QgsSkyboxEntity(QNode *parent=nullptr)
Constructor.
Qt3DRender::QRenderPass * mGl3RenderPass
Qt3DRender::QParameter * mGammaStrengthParameter
Qt3DRender::QFilterKey * mFilterKey
Qt3DRender::QEffect * mEffect
Qt3DExtras::QCuboidMesh * mMesh
Qt3DRender::QParameter * mTextureParameter
Qt3DRender::QMaterial * mMaterial
Qt3DRender::QTechnique * mGl3Technique