QGIS API Documentation 4.1.0-Master (ca2ac17535b)
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 const QImage img = data.image;
198 if ( img.isNull() )
199 return result;
200
201 QImage scaledImage = img.scaled( WIDTH, HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
202 if ( scaledImage.format() != QImage::Format_RGB32 )
203 {
204 // do we need to consider transparency here? probably not, if someone specifies a skybox texture
205 // with semi-transparent pixels then they get what they deserve...
206 scaledImage = scaledImage.convertToFormat( QImage::Format_RGB32 );
207 }
208 for ( int y = 0; y < HEIGHT; ++y )
209 {
210 const float v = ( ( static_cast< float >( y ) + 0.5f ) / static_cast< float >( HEIGHT ) ) * 2.0f - 1.0f;
211 const QRgb *line = reinterpret_cast<const QRgb *>( scaledImage.constScanLine( y ) );
212 for ( int x = 0; x < WIDTH; ++x )
213 {
214 // map pixel coordinate to [-1, 1] range
215 const float u = ( ( static_cast< float >( x ) + 0.5f ) / static_cast< float >( WIDTH ) ) * 2.0f - 1.0f;
216 const QVector3D cubemapDir = getCubeMapDirection( data.faceIndex, u, v ).normalized();
217 const QVector3D dir( cubemapDir.x(), -cubemapDir.z(), cubemapDir.y() );
218
219 // solid angle weighting (pixels near the corners of the cube appear smaller)
220 float weight = 1.0f / std::pow( 1.0f + u * u + v * v, 1.5f );
221 result.totalWeight += weight;
222
223 const QColor color = Qgs3DUtils::srgbToLinear( line[x] );
224 const QVector3D weightedColor( color.redF() * weight, color.greenF() * weight, color.blueF() * weight );
225
226 constexpr float Y00 = 0.282095f;
227 constexpr float Y11 = 0.488603f;
228 constexpr float Y22 = 1.092548f;
229 constexpr float Y20 = 0.315392f;
230 constexpr float Y22_2 = 0.546274f;
231
232 result.coeffs[0] += weightedColor * Y00;
233 result.coeffs[1] += weightedColor * ( Y11 * dir.y() );
234 result.coeffs[2] += weightedColor * ( Y11 * dir.z() );
235 result.coeffs[3] += weightedColor * ( Y11 * dir.x() );
236 result.coeffs[4] += weightedColor * ( Y22 * dir.x() * dir.y() );
237 result.coeffs[5] += weightedColor * ( Y22 * dir.y() * dir.z() );
238 result.coeffs[6] += weightedColor * ( Y20 * ( 3.0f * dir.z() * dir.z() - 1.0f ) );
239 result.coeffs[7] += weightedColor * ( Y22 * dir.x() * dir.z() );
240 result.coeffs[8] += weightedColor * ( Y22_2 * ( dir.x() * dir.x() - dir.y() * dir.y() ) );
241 }
242 }
243
244 return result;
245 }
246
247 void reduceSH( SHFaceResult &finalResult, const SHFaceResult &partialResult )
248 {
249 for ( int i = 0; i < 9; ++i )
250 {
251 finalResult.coeffs[i] += partialResult.coeffs[i];
252 }
253 finalResult.totalWeight += partialResult.totalWeight;
254 }
255
256 QVector<QVector3D> computeSphericalHarmonics( const QList<FaceData> &faceDataList )
257 {
258 // this isn't too expensive to calculate, but it's also TRIVIAL to calculate in parallel and WILL
259 // be done on the main thread, so let's do that...
260 QFuture<SHFaceResult> future = QtConcurrent::mappedReduced( faceDataList, computeFaceSH, reduceSH );
261 future.waitForFinished();
262 SHFaceResult combinedResult = future.result();
263
264 if ( combinedResult.totalWeight > 0 )
265 {
266 const float norm = static_cast< float >( 4.0 / combinedResult.totalWeight );
267 for ( int i = 0; i < 9; ++i )
268 {
269 combinedResult.coeffs[i] *= norm;
270 }
271 }
272
273 return combinedResult.coeffs;
274 }
275
276} //namespace
278{
279 if ( !mEnableEnvironmentalLighting )
280 {
282 return;
283 }
284
285 auto *lightCubeMap = new Qt3DRender::QTextureCubeMap( envLight );
286 lightCubeMap->setMagnificationFilter( Qt3DRender::QTextureCubeMap::Linear );
287 lightCubeMap->setMinificationFilter( Qt3DRender::QTextureCubeMap::LinearMipMapLinear );
288 lightCubeMap->setGenerateMipMaps( true );
289 lightCubeMap->setWrapMode( Qt3DRender::QTextureWrapMode( Qt3DRender::QTextureWrapMode::ClampToEdge ) );
290 lightCubeMap->setFormat( Qt3DRender::QAbstractTexture::SRGB8_Alpha8 );
291
292 int maxSize = 0;
293 for ( const QString &texturePath : { mSourcePosX, mSourcePosY, mSourcePosZ, mSourceNegX, mSourceNegY, mSourceNegZ } )
294 {
295 const QSize size = QgsApplication::imageCache()->originalSize( texturePath, true );
296 maxSize = std::max( maxSize, std::max( size.width(), size.height() ) );
297 }
298
299 const QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs = generateFaceTransformation();
300 const QSize faceSize( maxSize, maxSize );
301
302 QList<FaceData> faceDataList;
303 for ( auto it = faceConfigs.begin(); it != faceConfigs.end(); ++it )
304 {
305 const Qt3DRender::QTextureCubeMap::CubeMapFace face = it.key();
306 const FaceTransformation &config = it.value();
307
308 bool fitsInCache = false;
309 // TODO -- this force converts to Format_ARGB32_Premultiplied -- we need a flag to avoid that, as potentially these are HDR images...
310 const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( config.path, faceSize, true, 1.0, fitsInCache );
311 ( void ) fitsInCache;
312 QImage finalImage = textureSourceImage;
313 if ( finalImage.isNull() )
314 {
315 finalImage = QImage( faceSize.width(), faceSize.height(), QImage::Format_RGB32 );
316 finalImage.fill( Qt::white );
317 }
318 else if ( config.mirrorHorizontal || config.mirrorVertical )
319 {
320 finalImage = finalImage.mirrored( config.mirrorHorizontal, config.mirrorVertical );
321 }
322
323 auto textureImage = new QgsImageTexture( finalImage, lightCubeMap );
324 textureImage->setFace( face );
325 lightCubeMap->addTextureImage( textureImage );
326
327 if ( !textureSourceImage.isNull() )
328 {
329 faceDataList.append( FaceData( face, finalImage ) );
330 }
331 }
332
333 const QVector<QVector3D> shCoeffs = faceDataList.isEmpty() ? QVector<QVector3D>( 9, QVector3D( 0, 0, 0 ) ) : computeSphericalHarmonics( faceDataList );
334
335 int mipLevels = 1;
336 if ( maxSize > 0 )
337 {
338 mipLevels = static_cast<int>( std::floor( std::log2( maxSize ) ) ) + 1;
339 }
340
341 envLight->setSpecularMap( lightCubeMap, mipLevels );
342 envLight->setSphericalHarmonics( shCoeffs );
344}
345
346void QgsCubeFacesSkyboxEntity::init()
347{
348 mGlShader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.vert"_s ) ) );
349 mGlShader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/skybox.frag"_s ) ) );
350 mGl3RenderPass->setShaderProgram( mGlShader );
351
352 mTextureParameter->setName( "skyboxTexture" );
353}
354
355void QgsCubeFacesSkyboxEntity::reloadTexture()
356{
357 auto *newCubeMap = new Qt3DRender::QTextureCubeMap( this );
358 newCubeMap->setMagnificationFilter( Qt3DRender::QTextureCubeMap::Linear );
359 newCubeMap->setMinificationFilter( Qt3DRender::QTextureCubeMap::Linear );
360 newCubeMap->setGenerateMipMaps( false );
361 newCubeMap->setWrapMode( Qt3DRender::QTextureWrapMode( Qt3DRender::QTextureWrapMode::ClampToEdge ) );
362 newCubeMap->setFormat( Qt3DRender::QAbstractTexture::SRGB8_Alpha8 );
363
364 // all faces must have the SAME size, so take the maximum size from the input images
365 int maxSize = 0;
366 for ( const QString &texturePath : { mSourcePosX, mSourcePosY, mSourcePosZ, mSourceNegX, mSourceNegY, mSourceNegZ } )
367 {
368 const QSize size = QgsApplication::imageCache()->originalSize( texturePath, true );
369 maxSize = std::max( maxSize, std::max( size.width(), size.height() ) );
370 }
371
372 QList<Qt3DRender::QAbstractTextureImage *> newFaces;
373 const QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs = generateFaceTransformation();
374 const QSize faceSize( maxSize, maxSize );
375 for ( auto it = faceConfigs.begin(); it != faceConfigs.end(); ++it )
376 {
377 const Qt3DRender::QTextureCubeMap::CubeMapFace face = it.key();
378 const FaceTransformation &config = it.value();
379
380 bool fitsInCache = false;
381 const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( config.path, faceSize, true, 1.0, fitsInCache );
382 ( void ) fitsInCache;
383 QImage finalImage = textureSourceImage;
384 if ( finalImage.isNull() )
385 {
386 finalImage = QImage( faceSize.width(), faceSize.height(), QImage::Format_RGB32 );
387 finalImage.fill( Qt::white );
388 QPainter p;
389 p.begin( &finalImage );
390 //draw a checkerboard background for missing texture images
391 uchar pixDataRGB[] = { 150, 150, 150, 255, 100, 100, 100, 255, 100, 100, 100, 255, 150, 150, 150, 255 };
392 const QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
393 const QPixmap pix = QPixmap::fromImage( img.scaled( 8, 8 ) );
394 QBrush checkerBrush;
395 checkerBrush.setTexture( pix );
396 p.fillRect( finalImage.rect(), checkerBrush );
397 p.end();
398 }
399 else if ( config.mirrorHorizontal || config.mirrorVertical )
400 {
401 finalImage = finalImage.mirrored( config.mirrorHorizontal, config.mirrorVertical );
402 }
403
404 auto textureImage = new QgsImageTexture( finalImage, newCubeMap );
405 textureImage->setFace( face );
406 newCubeMap->addTextureImage( textureImage );
407 newFaces.push_back( textureImage );
408 }
409
410 mTextureParameter->setValue( QVariant::fromValue( newCubeMap ) );
411
412 if ( mCubeMap )
413 {
414 mCubeMap->deleteLater();
415 }
416 mCubeMap = newCubeMap;
417 mFacesTextureImages = newFaces;
418}
419
420QMap<Qt3DRender::QAbstractTexture::CubeMapFace, QgsCubeFacesSkyboxEntity::FaceTransformation> QgsCubeFacesSkyboxEntity::generateFaceTransformation() const
421{
422 QMap<Qt3DRender::QTextureCubeMap::CubeMapFace, FaceTransformation> faceConfigs;
423 switch ( mMappingType )
424 {
426 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
427 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
428 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosY, false, false };
429 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegY, false, false };
430 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, false, false };
431 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, false, false };
432 break;
433
435 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, false };
436 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, false };
437 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, false };
438 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, false };
439 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, false };
440 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, false };
441 break;
442
444 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, false, true };
445 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, false, true };
446 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourceNegZ, false, true };
447 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourcePosZ, false, true };
448 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, false, true };
449 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, false, true };
450 break;
451
453 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosY, true, false };
454 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegY, true, false };
455 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosX, true, false };
456 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegX, true, false };
457 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosZ, true, false };
458 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegZ, true, false };
459 break;
460
462 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveX] = { mSourcePosX, true, false };
463 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeX] = { mSourceNegX, true, false };
464 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveY] = { mSourcePosZ, true, false };
465 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeY] = { mSourceNegZ, true, false };
466 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapPositiveZ] = { mSourcePosY, true, false };
467 faceConfigs[Qt3DRender::QTextureCubeMap::CubeMapNegativeZ] = { mSourceNegY, true, false };
468 break;
469 }
470
471 return faceConfigs;
472}
SkyboxCubeMapping
Skybox texture cube mapping for distinct texture skyboxes.
Definition qgis.h:4429
@ UnrealEngineZUp
Unreal engine standard (+X Forward, +Y Right, +Z Up, Left-handed).
Definition qgis.h:4433
@ NativeZUp
Textures exported for Z-up (+X Right, +Y Forward, +Z Up).
Definition qgis.h:4430
@ LeftHandedYUpMirrored
Left-Handed, Y-Up coordinate systems (e.g., Unity convention +X Right, +Y Top, +Z Forward,...
Definition qgis.h:4434
@ GodotYUp
Godot standard (+X Right, +Y Top, -Z Forward, with vertical flip).
Definition qgis.h:4432
@ OpenGLYUp
Standard OpenGL/WebGL standard (+X Right, +Y Top, -Z Forward).
Definition qgis.h:4431
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