QGIS API Documentation 4.1.0-Master (0cdd3ae6384)
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 "qgs3dutils.h"
19#include "qgsapplication.h"
20#include "qgsenvironmentlight.h"
21#include "qgsimagecache.h"
22#include "qgsimagetexture.h"
23
24#include <QString>
25#include <QUrl>
26#include <Qt3DCore/QEntity>
27#include <Qt3DExtras/QCuboidMesh>
28#include <Qt3DRender/QCullFace>
29#include <Qt3DRender/QDepthTest>
30#include <Qt3DRender/QEffect>
31#include <Qt3DRender/QFilterKey>
32#include <Qt3DRender/QGraphicsApiFilter>
33#include <Qt3DRender/QMaterial>
34#include <Qt3DRender/QParameter>
35#include <Qt3DRender/QRenderPass>
36#include <Qt3DRender/QSeamlessCubemap>
37#include <Qt3DRender/QShaderProgram>
38#include <Qt3DRender/QTechnique>
39#include <Qt3DRender/QTextureImage>
40#include <QtConcurrent/QtConcurrentMap>
41
42#include "moc_qgsskyboxentity.cpp"
43
44using namespace Qt::StringLiterals;
45
47 : Qt3DCore::QEntity( parent )
48 , mEffect( new Qt3DRender::QEffect( this ) )
49 , mMaterial( new Qt3DRender::QMaterial( this ) )
50 , mGl3Technique( new Qt3DRender::QTechnique( this ) )
51 , mFilterKey( new Qt3DRender::QFilterKey( this ) )
52 , mGl3RenderPass( new Qt3DRender::QRenderPass( this ) )
53 , mMesh( new Qt3DExtras::QCuboidMesh( this ) )
54 , mGammaStrengthParameter( new Qt3DRender::QParameter( u"gammaStrength"_s, 0.0f ) )
55 , mTextureParameter( new Qt3DRender::QParameter( this ) )
56{
57 mGl3Technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
58 mGl3Technique->graphicsApiFilter()->setMajorVersion( 3 );
59 mGl3Technique->graphicsApiFilter()->setMinorVersion( 3 );
60 mGl3Technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
61
62 mFilterKey->setParent( mEffect );
63 mFilterKey->setName( u"renderingStyle"_s );
64 mFilterKey->setValue( u"forward"_s );
65
66 mGl3Technique->addFilterKey( mFilterKey );
67
68 Qt3DRender::QCullFace *cullFront = new Qt3DRender::QCullFace();
69 cullFront->setMode( Qt3DRender::QCullFace::Front );
70 Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest();
71 depthTest->setDepthFunction( Qt3DRender::QDepthTest::LessOrEqual );
72 Qt3DRender::QSeamlessCubemap *seamlessCubemap = new Qt3DRender::QSeamlessCubemap();
73
74 mGl3RenderPass->addRenderState( cullFront );
75 mGl3RenderPass->addRenderState( depthTest );
76 mGl3RenderPass->addRenderState( seamlessCubemap );
77
78 mGl3Technique->addRenderPass( mGl3RenderPass );
79
80 mEffect->addTechnique( mGl3Technique );
81
82 mMaterial->setEffect( mEffect );
83 mMaterial->addParameter( mGammaStrengthParameter );
84 mMaterial->addParameter( mTextureParameter );
85
86 mMesh->setXYMeshResolution( QSize( 2, 2 ) );
87 mMesh->setXZMeshResolution( QSize( 2, 2 ) );
88 mMesh->setYZMeshResolution( QSize( 2, 2 ) );
89
90 addComponent( mMesh );
91 addComponent( mMaterial );
92}
93
94#if ENABLE_PANORAMIC_SKYBOX
95// Panoramic skybox
96
97QgsPanoramicSkyboxEntity::QgsPanoramicSkyboxEntity( const QString &texturePath, QNode *parent )
98 : QgsSkyboxEntity( parent )
99 , mTexturePath( texturePath )
100 , mLoadedTexture( new Qt3DRender::QTextureLoader( parent ) )
101 , mGlShader( new Qt3DRender::QShaderProgram( this ) )
102{
103 mLoadedTexture->setGenerateMipMaps( false );
104 mGlShader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.vert"_s ) ) );
105 mGlShader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/hdr_skybox.frag"_s ) ) );
106 mGl3RenderPass->setShaderProgram( mGlShader );
107
108 mTextureParameter->setName( "skyboxTexture" );
109 mTextureParameter->setValue( QVariant::fromValue( mLoadedTexture ) );
110
111 reloadTexture();
112}
113
114void QgsPanoramicSkyboxEntity::reloadTexture()
115{
116 mLoadedTexture->setSource( QUrl::fromUserInput( mTexturePath ) );
117}
118
119#endif
120
121// 6 faces skybox
122
125 const QString &posX,
126 const QString &posY,
127 const QString &posZ,
128 const QString &negX,
129 const QString &negY,
130 const QString &negZ,
131 bool enableEnvironmentalLighting,
132 Qt3DCore::QNode *parent
133)
134 : QgsSkyboxEntity( parent )
135 , mMappingType( mapping )
136 , mSourcePosX( posX )
137 , mSourcePosY( posY )
138 , mSourcePosZ( posZ )
139 , mSourceNegX( negX )
140 , mSourceNegY( negY )
141 , mSourceNegZ( negZ )
142 , mEnableEnvironmentalLighting( enableEnvironmentalLighting )
143 , mGlShader( new Qt3DRender::QShaderProgram() )
144{
145 init();
146 reloadTexture();
147}
148
149namespace
150{
151 QVector3D getCubeMapDirection( int face, float u, float v )
152 {
153 switch ( face )
154 {
155 case Qt3DRender::QTextureCubeMap::CubeMapFace::CubeMapPositiveX:
156 return QVector3D( 1.0f, -v, -u );
157 case Qt3DRender::QTextureCubeMap::CubeMapFace::CubeMapNegativeX:
158 return QVector3D( -1.0f, -v, u );
159 case Qt3DRender::QTextureCubeMap::CubeMapFace::CubeMapPositiveY:
160 return QVector3D( u, 1.0f, v );
161 case Qt3DRender::QTextureCubeMap::CubeMapFace::CubeMapNegativeY:
162 return QVector3D( u, -1.0f, -v );
163 case Qt3DRender::QTextureCubeMap::CubeMapFace::CubeMapPositiveZ:
164 return QVector3D( u, -v, 1.0f );
165 case Qt3DRender::QTextureCubeMap::CubeMapFace::CubeMapNegativeZ:
166 return QVector3D( -u, -v, -1.0f );
167 default:
168 break;
169 }
170 return QVector3D();
171 }
172
173
174 struct FaceData
175 {
176 FaceData( Qt3DRender::QTextureCubeMap::CubeMapFace faceIndex, const QImage &image )
177 : faceIndex( faceIndex )
178 , image( image )
179 {}
180 Qt3DRender::QTextureCubeMap::CubeMapFace faceIndex;
181 QImage image;
182 };
183
184 struct SHFaceResult
185 {
186 QVector<QVector3D> coeffs = QVector<QVector3D>( 9, QVector3D( 0.0f, 0.0f, 0.0f ) );
187 float totalWeight = 0.0f;
188 };
189
190 SHFaceResult computeFaceSH( const FaceData &data )
191 {
192 SHFaceResult result;
193
194 constexpr int WIDTH = 32;
195 constexpr int HEIGHT = 32;
196
197 QImage img = data.image;
198 if ( img.isNull() )
199 return result;
200
201 bool isSrgb = true;
202 switch ( img.format() )
203 {
204 case QImage::Format_RGBA32FPx4:
205 case QImage::Format_RGBA32FPx4_Premultiplied:
206 case QImage::Format_RGBX32FPx4:
207 case QImage::Format_RGBA16FPx4:
208 case QImage::Format_RGBA16FPx4_Premultiplied:
209 case QImage::Format_RGBX16FPx4:
210 // float based image formats won't be in sRGB color space
211 isSrgb = false;
212 break;
213 default:
214 break;
215 }
216
217 if ( img.format() != QImage::Format_RGBA32FPx4 )
218 {
219 // convert image to float
220 img = img.convertToFormat( QImage::Format_RGBA32FPx4 );
221 }
222
223 QImage scaledImage = img.scaled( WIDTH, HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
224 for ( int y = 0; y < HEIGHT; ++y )
225 {
226 const float v = ( ( static_cast< float >( y ) + 0.5f ) / static_cast< float >( HEIGHT ) ) * 2.0f - 1.0f;
227 const float *line = reinterpret_cast<const float *>( scaledImage.constScanLine( y ) );
228 for ( int x = 0; x < WIDTH; ++x )
229 {
230 // map pixel coordinate to [-1, 1] range
231 const float u = ( ( static_cast< float >( x ) + 0.5f ) / static_cast< float >( WIDTH ) ) * 2.0f - 1.0f;
232 const QVector3D cubemapDir = getCubeMapDirection( data.faceIndex, u, v ).normalized();
233 const QVector3D dir( cubemapDir.x(), -cubemapDir.z(), cubemapDir.y() );
234
235 // solid angle weighting (pixels near the corners of the cube appear smaller)
236 float weight = 1.0f / std::pow( 1.0f + u * u + v * v, 1.5f );
237 result.totalWeight += weight;
238
239 QColor color = QColor::fromRgbF( line[x * 4 + 0], line[x * 4 + 1], line[x * 4 + 2], 1 );
240 if ( isSrgb )
241 {
242 color = Qgs3DUtils::srgbToLinear( color );
243 }
244 const QVector3D weightedColor( color.redF() * weight, color.greenF() * weight, color.blueF() * weight );
245
246 constexpr float Y00 = 0.282095f;
247 constexpr float Y11 = 0.488603f;
248 constexpr float Y22 = 1.092548f;
249 constexpr float Y20 = 0.315392f;
250 constexpr float Y22_2 = 0.546274f;
251
252 result.coeffs[0] += weightedColor * Y00;
253 result.coeffs[1] += weightedColor * ( Y11 * dir.y() );
254 result.coeffs[2] += weightedColor * ( Y11 * dir.z() );
255 result.coeffs[3] += weightedColor * ( Y11 * dir.x() );
256 result.coeffs[4] += weightedColor * ( Y22 * dir.x() * dir.y() );
257 result.coeffs[5] += weightedColor * ( Y22 * dir.y() * dir.z() );
258 result.coeffs[6] += weightedColor * ( Y20 * ( 3.0f * dir.z() * dir.z() - 1.0f ) );
259 result.coeffs[7] += weightedColor * ( Y22 * dir.x() * dir.z() );
260 result.coeffs[8] += weightedColor * ( Y22_2 * ( dir.x() * dir.x() - dir.y() * dir.y() ) );
261 }
262 }
263
264 return result;
265 }
266
267 void reduceSH( SHFaceResult &finalResult, const SHFaceResult &partialResult )
268 {
269 for ( int i = 0; i < 9; ++i )
270 {
271 finalResult.coeffs[i] += partialResult.coeffs[i];
272 }
273 finalResult.totalWeight += partialResult.totalWeight;
274 }
275
276 QVector<QVector3D> computeSphericalHarmonics( const QList<FaceData> &faceDataList )
277 {
278 // this isn't too expensive to calculate, but it's also TRIVIAL to calculate in parallel and WILL
279 // be done on the main thread, so let's do that...
280 QFuture<SHFaceResult> future = QtConcurrent::mappedReduced( faceDataList, computeFaceSH, reduceSH );
281 future.waitForFinished();
282 SHFaceResult combinedResult = future.result();
283
284 if ( combinedResult.totalWeight > 0 )
285 {
286 const float norm = static_cast< float >( 4.0 / combinedResult.totalWeight );
287 for ( int i = 0; i < 9; ++i )
288 {
289 combinedResult.coeffs[i] *= norm;
290 }
291 }
292
293 return combinedResult.coeffs;
294 }
295
296} //namespace
298{
299 if ( !mEnableEnvironmentalLighting )
300 {
302 return;
303 }
304
305 auto *lightCubeMap = new Qt3DRender::QTextureCubeMap( envLight );
306 lightCubeMap->setMagnificationFilter( Qt3DRender::QTextureCubeMap::Linear );
307 lightCubeMap->setMinificationFilter( Qt3DRender::QTextureCubeMap::LinearMipMapLinear );
308 lightCubeMap->setGenerateMipMaps( true );
309 lightCubeMap->setWrapMode( Qt3DRender::QTextureWrapMode( Qt3DRender::QTextureWrapMode::ClampToEdge ) );
310
311 int maxSize = 0;
312 for ( const QString &texturePath : { mSourcePosX, mSourcePosY, mSourcePosZ, mSourceNegX, mSourceNegY, mSourceNegZ } )
313 {
314 const QSize size = QgsApplication::imageCache()->originalSize( texturePath, true );
315 maxSize = std::max( maxSize, std::max( size.width(), size.height() ) );
316 }
317
318 const QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs = generateFaceTransformation();
319 const QSize faceSize( maxSize, maxSize );
320
321 QList<FaceData> faceDataList;
322 for ( auto it = faceConfigs.begin(); it != faceConfigs.end(); ++it )
323 {
324 const Qt3DRender::QTextureCubeMap::CubeMapFace face = it.key();
325 const FaceTransformation &config = it.value();
326
327 bool fitsInCache = false;
328 // TODO -- this force converts to Format_ARGB32_Premultiplied -- we need a flag to avoid that, as potentially these are HDR images...
329 const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( config.path, faceSize, true, 1.0, fitsInCache );
330 ( void ) fitsInCache;
331 QImage finalImage = textureSourceImage;
332 if ( finalImage.isNull() )
333 {
334 finalImage = QImage( faceSize.width(), faceSize.height(), QImage::Format_RGB32 );
335 finalImage.fill( Qt::white );
336 }
337 else if ( config.mirrorHorizontal || config.mirrorVertical )
338 {
339 finalImage = finalImage.mirrored( config.mirrorHorizontal, config.mirrorVertical );
340 }
341
342 bool requiresConversionToRgb = false;
343 Qt3DRender::QAbstractTexture::TextureFormat textureFormat = Qgs3DUtils::determineTextureFormat( finalImage.format(), true, requiresConversionToRgb );
344 lightCubeMap->setFormat( textureFormat );
345 if ( requiresConversionToRgb )
346 {
347 finalImage.convertTo( QImage::Format::Format_ARGB32_Premultiplied );
348 }
349
350 if ( finalImage.width() != finalImage.height() )
351 {
352 const int maxDimension = std::max( finalImage.width(), finalImage.height() );
353 finalImage = finalImage.scaled( maxDimension, maxDimension, Qt::AspectRatioMode::IgnoreAspectRatio, Qt::SmoothTransformation );
354 }
355
356 auto textureImage = new QgsImageTexture( finalImage, lightCubeMap );
357 textureImage->setFace( face );
358 lightCubeMap->addTextureImage( textureImage );
359
360 if ( !textureSourceImage.isNull() )
361 {
362 faceDataList.append( FaceData( face, finalImage ) );
363 }
364 }
365
366 const QVector<QVector3D> shCoeffs = faceDataList.isEmpty() ? QVector<QVector3D>( 9, QVector3D( 0, 0, 0 ) ) : computeSphericalHarmonics( faceDataList );
367
368 int mipLevels = 1;
369 if ( maxSize > 0 )
370 {
371 mipLevels = static_cast<int>( std::floor( std::log2( maxSize ) ) ) + 1;
372 }
373
374 envLight->setSpecularMap( lightCubeMap, mipLevels );
375 envLight->setSphericalHarmonics( shCoeffs );
377}
378
379void QgsCubeFacesSkyboxEntity::init()
380{
381 mGlShader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.vert"_s ) ) );
382 mGlShader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.frag"_s ) ) );
383 mGl3RenderPass->setShaderProgram( mGlShader );
384
385 mTextureParameter->setName( "skyboxTexture" );
386}
387
388void QgsCubeFacesSkyboxEntity::reloadTexture()
389{
390 auto *newCubeMap = new Qt3DRender::QTextureCubeMap( this );
391 newCubeMap->setMagnificationFilter( Qt3DRender::QTextureCubeMap::Linear );
392 newCubeMap->setMinificationFilter( Qt3DRender::QTextureCubeMap::Linear );
393 newCubeMap->setGenerateMipMaps( false );
394 newCubeMap->setWrapMode( Qt3DRender::QTextureWrapMode( Qt3DRender::QTextureWrapMode::ClampToEdge ) );
395
396 // all faces must have the SAME size, so take the maximum size from the input images
397 int maxSize = 0;
398 for ( const QString &texturePath : { mSourcePosX, mSourcePosY, mSourcePosZ, mSourceNegX, mSourceNegY, mSourceNegZ } )
399 {
400 const QSize size = QgsApplication::imageCache()->originalSize( texturePath, true );
401 maxSize = std::max( maxSize, std::max( size.width(), size.height() ) );
402 }
403
404 QList<Qt3DRender::QAbstractTextureImage *> newFaces;
405 const QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs = generateFaceTransformation();
406 const QSize faceSize( maxSize, maxSize );
407 for ( auto it = faceConfigs.begin(); it != faceConfigs.end(); ++it )
408 {
409 const Qt3DRender::QTextureCubeMap::CubeMapFace face = it.key();
410 const FaceTransformation &config = it.value();
411
412 bool fitsInCache = false;
413 const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( config.path, faceSize, true, 1.0, fitsInCache );
414 ( void ) fitsInCache;
415 QImage finalImage = textureSourceImage;
416 if ( finalImage.isNull() )
417 {
418 finalImage = QImage( faceSize.width(), faceSize.height(), QImage::Format_RGB32 );
419 finalImage.fill( Qt::white );
420 QPainter p;
421 p.begin( &finalImage );
422 //draw a checkerboard background for missing texture images
423 uchar pixDataRGB[] = { 150, 150, 150, 255, 100, 100, 100, 255, 100, 100, 100, 255, 150, 150, 150, 255 };
424 const QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
425 const QPixmap pix = QPixmap::fromImage( img.scaled( 8, 8 ) );
426 QBrush checkerBrush;
427 checkerBrush.setTexture( pix );
428 p.fillRect( finalImage.rect(), checkerBrush );
429 p.end();
430 }
431 else if ( config.mirrorHorizontal || config.mirrorVertical )
432 {
433 finalImage = finalImage.mirrored( config.mirrorHorizontal, config.mirrorVertical );
434 }
435
436 bool requiresConversionToRgb = false;
437 Qt3DRender::QAbstractTexture::TextureFormat textureFormat = Qgs3DUtils::determineTextureFormat( finalImage.format(), true, requiresConversionToRgb );
438 newCubeMap->setFormat( textureFormat );
439 if ( requiresConversionToRgb )
440 {
441 finalImage.convertTo( QImage::Format::Format_ARGB32_Premultiplied );
442 }
443
444 if ( finalImage.width() != finalImage.height() )
445 {
446 const int maxDimension = std::max( finalImage.width(), finalImage.height() );
447 finalImage = finalImage.scaled( maxDimension, maxDimension, Qt::AspectRatioMode::IgnoreAspectRatio, Qt::SmoothTransformation );
448 }
449
450 auto textureImage = new QgsImageTexture( finalImage, newCubeMap );
451 textureImage->setFace( face );
452 newCubeMap->addTextureImage( textureImage );
453 newFaces.push_back( textureImage );
454 }
455
456 mTextureParameter->setValue( QVariant::fromValue( newCubeMap ) );
457
458 if ( mCubeMap )
459 {
460 mCubeMap->deleteLater();
461 }
462 mCubeMap = newCubeMap;
463 mFacesTextureImages = newFaces;
464}
465
466QMap<Qt3DRender::QAbstractTexture::CubeMapFace, QgsCubeFacesSkyboxEntity::FaceTransformation> QgsCubeFacesSkyboxEntity::generateFaceTransformation() const
467{
468 QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs;
469 switch ( mMappingType )
470 {
472 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
473 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
474 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosY, false, false };
475 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegY, false, false };
476 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, false, false };
477 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, false, false };
478 break;
479
481 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
482 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
483 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, false };
484 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, false };
485 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, false };
486 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, false };
487 break;
488
490 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, true };
491 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, true };
492 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, true };
493 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, true };
494 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, true };
495 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, true };
496 break;
497
499 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosY, true, false };
500 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegY, true, false };
501 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosX, true, false };
502 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegX, true, false };
503 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, true, false };
504 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, true, false };
505 break;
506
508 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, true, false };
509 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, true, false };
510 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosZ, true, false };
511 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegZ, true, false };
512 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, true, false };
513 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, true, false };
514 break;
515 }
516
517 return faceConfigs;
518}
SkyboxCubeMapping
Skybox texture cube mapping for distinct texture skyboxes.
Definition qgis.h:4462
@ UnrealEngineZUp
Unreal engine standard (+X Forward, +Y Right, +Z Up, Left-handed).
Definition qgis.h:4466
@ NativeZUp
Textures exported for Z-up (+X Right, +Y Forward, +Z Up).
Definition qgis.h:4463
@ LeftHandedYUpMirrored
Left-Handed, Y-Up coordinate systems (e.g., Unity convention +X Right, +Y Top, +Z Forward,...
Definition qgis.h:4467
@ GodotYUp
Godot standard (+X Right, +Y Top, -Z Forward, with vertical flip).
Definition qgis.h:4465
@ OpenGLYUp
Standard OpenGL/WebGL standard (+X Right, +Y Top, -Z Forward).
Definition qgis.h:4464
static Qt3DRender::QAbstractTexture::TextureFormat determineTextureFormat(QImage::Format format, bool isSrgb, bool &requiresConversionToRgb)
Given a QImage format, returns the most appropriate corresponding texture format.
static QColor srgbToLinear(const QColor &color)
Converts a SRGB color to a linear color.
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, bool enableEnvironmentalLighting, Qt3DCore::QNode *parent=nullptr)
Constructs a skybox from 6 different images.
void updateEnvironmentLight(QgsEnvironmentLight *light) const override
Updates the specified environment light to match the skybox settings.
An environment light entity.
@ SpecularMapWithSphericalHarmonics
Specular map, using spherical harmonics for irradiance.
@ Disabled
No environment lighting.
void setMode(Mode mode)
Sets the environment light mode.
void setSpecularMap(Qt3DRender::QTextureCubeMap *specularTexture, int mipLevels)
Sets the specular map texture and available mip levels.
void setSphericalHarmonics(const QVector< QVector3D > &harmonics)
Sets the spherical harmonics for irradiant light.
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.
Holds an image that can be used as a texture in the 3D view.
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