27#include "qgsmesh3dentity_p.h"
45#include <QDiffuseSpecularMaterial>
47#include <QPhongMaterial>
48#include <QTextureMaterial>
49#include <QtConcurrentRun>
52#include "moc_qgsquantizedmeshterraingenerator.cpp"
56class QgsQuantizedMeshTerrainChunkLoader :
public QgsTerrainTileLoader
60 QgsQuantizedMeshTerrainChunkLoader(
61 QgsTerrainEntity *terrain, QgsChunkNode *node,
long long tileId, QgsTiledSceneIndex index,
const QgsCoordinateTransform &tileCrsToMapCrs
63 void start()
override;
64 Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent )
override;
67 void onTextureLoaded()
override;
70 QgsTerrainTileEntity *mEntity =
nullptr;
71 bool mMeshLoaded =
false;
72 bool mTextureLoaded =
false;
73 std::mutex mFinishedMutex;
75 QgsTiledSceneIndex mIndex;
76 QgsCoordinateTransform mTileCrsToMapCrs;
79QgsQuantizedMeshTerrainChunkLoader::QgsQuantizedMeshTerrainChunkLoader( QgsTerrainEntity *terrain_, QgsChunkNode *node,
long long tileId,
QgsTiledSceneIndex index,
const QgsCoordinateTransform &tileCrsToMapCrs )
80 : QgsTerrainTileLoader( terrain_, node )
82 , mIndex( std::move( index ) )
83 , mTileCrsToMapCrs( tileCrsToMapCrs )
87void QgsQuantizedMeshTerrainChunkLoader::start()
89 QgsChunkNode *node = chunk();
99 QThreadPool::globalInstance()->start( [
this, node, vertScale, chunkOrigin, shadingEnabled]() {
100 if ( mTileId == QgsQuantizedMeshIndex::ROOT_TILE_ID )
109 QString uri = tile.
resources().value( QStringLiteral(
"content" ) ).toString();
110 Q_ASSERT( !uri.isEmpty() );
112 uri = tile.
baseUrl().resolved( uri ).toString();
113 QByteArray content = mIndex.retrieveContent( uri );
115 QgsGltf3DUtils::EntityTransform entityTransform;
117 entityTransform.chunkOriginTargetCrs = chunkOrigin;
118 entityTransform.ecefToTargetCrs = &mTileCrsToMapCrs;
119 entityTransform.gltfUpAxis =
static_cast<Qgis::Axis>( tile.
metadata().value( QStringLiteral(
"gltfUpAxis" ),
static_cast<int>(
Qgis::Axis::Y ) ).toInt() );
125 qmTile.removeDegenerateTriangles();
128 box3D.
setZMinimum( qmTile.mHeader.MinimumHeight * vertScale );
129 box3D.
setZMaximum( qmTile.mHeader.MaximumHeight * vertScale );
130 node->setExactBox3D( box3D );
132 if ( shadingEnabled && qmTile.mNormalCoords.size() == 0 )
134 qmTile.generateNormals();
137 tinygltf::Model model = qmTile.toGltf(
true, 100,
true );
140 Qt3DCore::QEntity *gltfEntity = QgsGltf3DUtils::parsedGltfToEntity( model, entityTransform, uri, &errors );
141 if ( !errors.isEmpty() )
148 QgsTerrainTileEntity *terrainEntity =
new QgsTerrainTileEntity( node->tileId() );
150 Q_ASSERT( gltfEntity->children().size() == 1 );
151 gltfEntity->children()[0]->setParent( terrainEntity );
153 QgsGeoTransform *transform =
new QgsGeoTransform;
154 transform->setGeoTranslation( chunkOrigin );
155 terrainEntity->addComponent( transform );
158 mEntity = terrainEntity;
162 QgsDebugError( QStringLiteral(
"Failed to parse tile from '%1'" ).arg( uri ) );
168 std::lock_guard lock( mFinishedMutex );
169 if ( mTextureLoaded )
176Qt3DCore::QEntity *QgsQuantizedMeshTerrainChunkLoader::createEntity( Qt3DCore::QEntity *parent )
180 mEntity->setParent( parent );
181 Qt3DRender::QTexture2D *texture = createTexture( mEntity );
184 Qt3DRender::QMaterial *material =
nullptr;
189 Qt3DExtras::QDiffuseSpecularMaterial *diffuseMapMaterial =
new Qt3DExtras::QDiffuseSpecularMaterial;
190 diffuseMapMaterial->
setDiffuse( QVariant::fromValue( texture ) );
191 diffuseMapMaterial->setAmbient( shadingMaterial.
ambient() );
192 diffuseMapMaterial->setSpecular( shadingMaterial.
specular() );
193 diffuseMapMaterial->setShininess( shadingMaterial.
shininess() );
194 material = diffuseMapMaterial;
198 Qt3DExtras::QTextureMaterial *textureMaterial =
new Qt3DExtras::QTextureMaterial;
199 textureMaterial->setTexture( texture );
200 material = textureMaterial;
203 Qt3DCore::QEntity *gltfEntity = mEntity->findChild<Qt3DCore::QEntity *>();
205 auto oldMaterial = gltfEntity->componentsOfType<QgsMetalRoughMaterial>();
206 Q_ASSERT( oldMaterial.size() > 0 );
207 gltfEntity->removeComponent( oldMaterial[0] );
208 gltfEntity->addComponent( material );
213void QgsQuantizedMeshTerrainChunkLoader::onTextureLoaded()
215 std::lock_guard lock( mFinishedMutex );
218 mTextureLoaded =
true;
234 mTerrain->mapSettings()->transformContext()
244 clone->mLayer = mLayer;
260 return mMetadata->mBoundingVolume.bounds().toRectangle();
266 return mMetadata->geometricErrorAtZoom( -1 );
271 hMin = mMetadata->mBoundingVolume.bounds().zMinimum();
272 hMax = mMetadata->mBoundingVolume.bounds().xMaximum();
280 QgsTileXYZ tileXyz( floor( tileCoords.x() ), floor( tileCoords.y() ), mMetadata->mMaxZoom );
281 if ( !mMetadata->containsTile( tileXyz ) )
285 QgsDebugError( QStringLiteral(
"Quantized Mesh layer doesn't contain max-zoom tile for %1, %2" ).arg( x ).arg( y ) );
291 QString uri = sceneTile.
resources().value( QStringLiteral(
"content" ) ).toString();
292 Q_ASSERT( !uri.isEmpty() );
294 uri = sceneTile.
baseUrl().resolved( uri ).toString();
302 return QgsMeshLayerUtils::interpolateZForPoint( triMesh, point.
x(), point.
y() );
307 long long tileId = QgsQuantizedMeshIndex::encodeTileId( nodeIdToTile( node->tileId() ) );
308 return new QgsQuantizedMeshTerrainChunkLoader(
mTerrain, node, tileId, mIndex, mTileCrsToMapCrs );
313 return new QgsChunkNode(
316 mMetadata->geometricErrorAtZoom( -1 )
322 QVector<QgsChunkNode *> children;
324 for (
auto offset : std::vector<std::pair<int, int>> { { 0, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 } } )
326 QgsChunkNodeId childId(
327 node->tileId().d + 1,
328 node->tileId().x * 2 + offset.first,
329 node->tileId().y * 2 + offset.second
332 if ( !mMetadata->containsTile( tile ) )
340 QgsRectangle mapExtent2d = mTileCrsToMapCrs.transform( extent2d );
347 mMetadata->geometricErrorAtZoom( tile.
zoomLevel() ),
365 const QgsQuantizedMeshDataProvider *provider = qobject_cast<const QgsQuantizedMeshDataProvider *>(
layer->dataProvider() );
368 QgsDebugError(
"QgsQuantizedMeshTerrainGenerator provided with non-QM layer" );
371 mMetadata = provider->quantizedMeshMetadata();
372 mIndex = provider->index();
385QgsTileXYZ QgsQuantizedMeshTerrainGenerator::nodeIdToTile( QgsChunkNodeId nodeId )
const
392 mMetadata->mTileScheme == QStringLiteral(
"tms" )
393 ? ( 1 << ( nodeId.d - 1 ) ) - nodeId.y - 1
399#include "qgsquantizedmeshterraingenerator.moc"
const QgsAbstractTerrainSettings * terrainSettings() const
Returns the terrain settings.
bool isTerrainShadingEnabled() const
Returns whether terrain shading is enabled.
QgsPhongMaterialSettings terrainShadingMaterial() const
Returns terrain shading material.
Rendering context for preparation of 3D entities.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system used in the 3D scene.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
double verticalScale() const
Returns the vertical scale (exaggeration) for terrain.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
A 3-dimensional box composed of x, y, z coordinates.
void setZMinimum(double z)
Sets the minimum z value.
void setZMaximum(double z)
Sets the maximum z value.
A simple 4x4 matrix implementation useful for transformation in 3D space.
Basic shading material used for rendering based on the Phong shading model with three color component...
void setDiffuse(const QColor &diffuse)
Sets diffuse color component.
QColor specular() const
Returns specular color component.
QColor ambient() const
Returns ambient color component.
double shininess() const
Returns shininess of the surface.
Exception thrown on failure to parse Quantized Mesh tile (malformed data).
QgsChunkNode * createRootNode() const override
bool setLayer(QgsTiledSceneLayer *layer)
Set layer to take tiles from.
void setTerrain(QgsTerrainEntity *t) override
Sets terrain entity for the generator (does not transfer ownership).
QVector< QgsChunkNode * > createChildren(QgsChunkNode *node) const override
QgsTiledSceneLayer * layer() const
Returns the layer we take tiles from.
QgsRectangle rootChunkExtent() const override
extent of the terrain's root chunk in terrain's CRS
static QgsTerrainGenerator * create()
Creates a new instance of a QgsQuantizedMeshTerrainGenerator object.
void rootChunkHeightRange(float &hMin, float &hMax) const override
Returns height range of the root chunk in world coordinates.
QgsTerrainGenerator::Type type() const override
What texture generator implementation is this.
QgsTerrainGenerator * clone() const override
Makes a copy of the current instance.
float rootChunkError(const Qgs3DMapSettings &map) const override
Returns error of the root chunk in world coordinates.
QgsChunkLoader * createChunkLoader(QgsChunkNode *node) const override
QgsQuantizedMeshTerrainGenerator()
float heightAt(double x, double y, const Qgs3DRenderContext &context) const override
Returns height at (x,y) in map's CRS.
void setExtent(const QgsRectangle &extent) override
sets the extent of the terrain in terrain's CRS
A rectangle specified with double values.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Base class for generators of terrain.
Type
Enumeration of the available terrain generators.
@ QuantizedMesh
Terrain is built from quantized mesh tiles.
QgsTilingScheme mTerrainTilingScheme
Tiling scheme of the terrain.
QgsTerrainEntity * mTerrain
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
QgsRectangle tileExtent(QgsTileXYZ id) const
Returns extent of the given tile in this matrix.
QPointF mapToTileCoordinates(const QgsPointXY &mapPoint) const
Returns row/column coordinates (floating point number) from the given point in map coordinates.
static QgsTileMatrix fromTileMatrix(int zoomLevel, const QgsTileMatrix &tileMatrix)
Returns a tile matrix based on another one.
Stores coordinates of a tile in a tile matrix set.
int zoomLevel() const
Returns tile's zoom level (Z).
An index for tiled scene data providers.
QByteArray retrieveContent(const QString &uri, QgsFeedback *feedback=nullptr)
Retrieves index content for the specified uri.
QgsTiledSceneTile getTile(long long id)
Returns the tile with matching id, or an invalid tile if the matching tile is not available.
Represents a map layer supporting display of tiled scene objects.
Represents an individual tile from a tiled scene data source.
QVariantMap resources() const
Returns the resources attached to the tile.
QVariantMap metadata() const
Returns additional metadata attached to the tile.
const QgsMatrix4x4 * transform() const
Returns the tile's transform.
QUrl baseUrl() const
Returns the tile's base URL.
Encapsulates tiling schemes (just like with WMTS / TMS / XYZ layers).
A triangular/derived mesh with vertices in map coordinates.
bool update(QgsMesh *nativeMesh, const QgsCoordinateTransform &transform)
Constructs triangular mesh from layer's native mesh and transform to destination CRS.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
#define QgsDebugError(str)
Mesh - vertices, edges and faces.
void removeDegenerateTriangles()
QgsMesh toMesh(QgsRectangle tileBounds)