QGIS API Documentation 4.1.0-Master (9af12b5a203)
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
137
138void QgsCubeFacesSkyboxEntity::init()
139{
140 mGlShader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.vert"_s ) ) );
141 mGlShader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.frag"_s ) ) );
142 mGl3RenderPass->setShaderProgram( mGlShader );
143
144 mTextureParameter->setName( "skyboxTexture" );
145}
146
147void QgsCubeFacesSkyboxEntity::reloadTexture()
148{
149 auto *newCubeMap = new Qt3DRender::QTextureCubeMap( this );
150 newCubeMap->setMagnificationFilter( Qt3DRender::QTextureCubeMap::Linear );
151 newCubeMap->setMinificationFilter( Qt3DRender::QTextureCubeMap::Linear );
152 newCubeMap->setGenerateMipMaps( false );
153 newCubeMap->setWrapMode( Qt3DRender::QTextureWrapMode( Qt3DRender::QTextureWrapMode::ClampToEdge ) );
154 newCubeMap->setFormat( Qt3DRender::QAbstractTexture::SRGB8_Alpha8 );
155
156 // all faces must have the SAME size, so take the maximum size from the input images
157 int maxSize = 0;
158 for ( const QString &texturePath : { mSourcePosX, mSourcePosY, mSourcePosZ, mSourceNegX, mSourceNegY, mSourceNegZ } )
159 {
160 const QSize size = QgsApplication::imageCache()->originalSize( texturePath, true );
161 maxSize = std::max( maxSize, std::max( size.width(), size.height() ) );
162 }
163
164 QList<Qt3DRender::QAbstractTextureImage *> newFaces;
165 const QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs = generateFaceTransformation();
166 const QSize faceSize( maxSize, maxSize );
167 for ( auto it = faceConfigs.begin(); it != faceConfigs.end(); ++it )
168 {
169 const Qt3DRender::QTextureCubeMap::CubeMapFace face = it.key();
170 const FaceTransformation &config = it.value();
171
172 bool fitsInCache = false;
173 const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( config.path, faceSize, true, 1.0, fitsInCache );
174 ( void ) fitsInCache;
175 QImage finalImage = textureSourceImage;
176 if ( finalImage.isNull() )
177 {
178 finalImage = QImage( faceSize.width(), faceSize.height(), QImage::Format_RGB32 );
179 finalImage.fill( Qt::white );
180 QPainter p;
181 p.begin( &finalImage );
182 //draw a checkerboard background for missing texture images
183 uchar pixDataRGB[] = { 150, 150, 150, 255, 100, 100, 100, 255, 100, 100, 100, 255, 150, 150, 150, 255 };
184 const QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
185 const QPixmap pix = QPixmap::fromImage( img.scaled( 8, 8 ) );
186 QBrush checkerBrush;
187 checkerBrush.setTexture( pix );
188 p.fillRect( finalImage.rect(), checkerBrush );
189 p.end();
190 }
191 else if ( config.mirrorHorizontal || config.mirrorVertical )
192 {
193 finalImage = finalImage.mirrored( config.mirrorHorizontal, config.mirrorVertical );
194 }
195
196 auto textureImage = new QgsImageTexture( finalImage, newCubeMap );
197 textureImage->setFace( face );
198 newCubeMap->addTextureImage( textureImage );
199 newFaces.push_back( textureImage );
200 }
201
202 mTextureParameter->setValue( QVariant::fromValue( newCubeMap ) );
203
204 if ( mCubeMap )
205 {
206 mCubeMap->deleteLater();
207 }
208 mCubeMap = newCubeMap;
209 mFacesTextureImages = newFaces;
210}
211
212QMap<Qt3DRender::QAbstractTexture::CubeMapFace, QgsCubeFacesSkyboxEntity::FaceTransformation> QgsCubeFacesSkyboxEntity::generateFaceTransformation() const
213{
214 QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs;
215 switch ( mMappingType )
216 {
218 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
219 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
220 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosY, false, false };
221 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegY, false, false };
222 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, false, false };
223 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, false, false };
224 break;
225
227 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
228 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
229 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, false };
230 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, false };
231 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, false };
232 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, false };
233 break;
234
236 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, true };
237 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, true };
238 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, true };
239 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, true };
240 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, true };
241 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, true };
242 break;
243
245 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosY, true, false };
246 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegY, true, false };
247 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosX, true, false };
248 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegX, true, false };
249 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, true, false };
250 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, true, false };
251 break;
252
254 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, true, false };
255 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, true, false };
256 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosZ, true, false };
257 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegZ, true, false };
258 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, true, false };
259 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, true, false };
260 break;
261 }
262
263 return faceConfigs;
264}
SkyboxCubeMapping
Skybox texture cube mapping for distinct texture skyboxes.
Definition qgis.h:4428
@ UnrealEngineZUp
Unreal engine standard (+X Forward, +Y Right, +Z Up, Left-handed).
Definition qgis.h:4432
@ NativeZUp
Textures exported for Z-up (+X Right, +Y Forward, +Z Up).
Definition qgis.h:4429
@ LeftHandedYUpMirrored
Left-Handed, Y-Up coordinate systems (e.g., Unity convention +X Right, +Y Top, +Z Forward,...
Definition qgis.h:4433
@ GodotYUp
Godot standard (+X Right, +Y Top, -Z Forward, with vertical flip).
Definition qgis.h:4431
@ OpenGLYUp
Standard OpenGL/WebGL standard (+X Right, +Y Top, -Z Forward).
Definition qgis.h:4430
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
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