21#include "qgsmesh3dentity_p.h"
40#include <qcomponent.h>
41#include <qdiffusespecularmaterial.h>
44#include <qnamespace.h>
45#include <qphongmaterial.h>
46#include <qtconcurrentrun.h>
47#include <qtexturematerial.h>
51class QgsQuantizedMeshTerrainChunkLoader :
public QgsTerrainTileLoader
55 QgsQuantizedMeshTerrainChunkLoader(
57 virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent )
override;
60 virtual void onTextureLoaded()
override;
63 QgsTerrainTileEntity *mEntity =
nullptr;
64 bool mMeshLoaded =
false;
65 bool mTextureLoaded =
false;
66 std::mutex mFinishedMutex;
69QgsQuantizedMeshTerrainChunkLoader::QgsQuantizedMeshTerrainChunkLoader( QgsTerrainEntity *terrain_, QgsChunkNode *node,
long long tileId,
QgsTiledSceneIndex index,
const QgsCoordinateTransform &tileCrsToMapCrs )
70 : QgsTerrainTileLoader( terrain_, node )
80 QThreadPool::globalInstance()->start( [
this, node, tileId, index, tileCrsToMapCrs, vertScale, mapOrigin, shadingEnabled ]()
82 if ( tileId == QgsQuantizedMeshIndex::ROOT_TILE_ID )
93 QString uri = tile.
resources().value( QStringLiteral(
"content" ) ).toString();
94 Q_ASSERT( !uri.isEmpty() );
96 uri = tile.
baseUrl().resolved( uri ).toString();
99 QgsGltf3DUtils::EntityTransform entityTransform;
101 entityTransform.sceneOriginTargetCrs = mapOrigin;
102 entityTransform.ecefToTargetCrs = &tileCrsToMapCrs;
103 entityTransform.gltfUpAxis =
static_cast< Qgis::Axis >( tile.
metadata().value( QStringLiteral(
"gltfUpAxis" ),
static_cast< int >(
Qgis::Axis::Y ) ).toInt() );
109 qmTile.removeDegenerateTriangles();
115 bbox.
xMin, qmTile.mHeader.MinimumHeight * vertScale, bbox.
zMin,
116 bbox.
xMax, qmTile.mHeader.MaximumHeight * vertScale, bbox.
zMax ) );
118 if ( shadingEnabled && qmTile.mNormalCoords.size() == 0 )
120 qmTile.generateNormals();
123 tinygltf::Model model = qmTile.toGltf(
true, 100,
true );
126 Qt3DCore::QEntity *gltfEntity = QgsGltf3DUtils::parsedGltfToEntity( model, entityTransform, uri, &errors );
127 if ( !errors.isEmpty() )
134 QgsTerrainTileEntity *terrainEntity =
new QgsTerrainTileEntity( node->tileId() );
136 Q_ASSERT( gltfEntity->children().size() == 1 );
137 gltfEntity->children()[0]->setParent( terrainEntity );
139 mEntity = terrainEntity;
143 QgsDebugError( QStringLiteral(
"Failed to parse tile from '%1'" ).arg( uri ) );
149 std::lock_guard lock( mFinishedMutex );
150 if ( mTextureLoaded )
157Qt3DCore::QEntity *QgsQuantizedMeshTerrainChunkLoader::createEntity( Qt3DCore::QEntity *parent )
161 mEntity->setParent( parent );
162 Qt3DRender::QTexture2D *texture = createTexture( mEntity );
165 Qt3DRender::QMaterial *material =
nullptr;
170 Qt3DExtras::QDiffuseSpecularMaterial *diffuseMapMaterial =
new Qt3DExtras::QDiffuseSpecularMaterial;
171 diffuseMapMaterial->
setDiffuse( QVariant::fromValue( texture ) );
172 diffuseMapMaterial->setAmbient( shadingMaterial.
ambient() );
173 diffuseMapMaterial->setSpecular( shadingMaterial.
specular() );
174 diffuseMapMaterial->setShininess( shadingMaterial.
shininess() );
175 material = diffuseMapMaterial;
179 Qt3DExtras::QTextureMaterial *textureMaterial =
new Qt3DExtras::QTextureMaterial;
180 textureMaterial->setTexture( texture );
181 material = textureMaterial;
184 Qt3DCore::QEntity *gltfEntity = mEntity->findChild<Qt3DCore::QEntity *>();
186 auto oldMaterial = gltfEntity->componentsOfType<QgsMetalRoughMaterial>();
187 Q_ASSERT( oldMaterial.size() > 0 );
188 gltfEntity->removeComponent( oldMaterial[0] );
189 gltfEntity->addComponent( material );
194void QgsQuantizedMeshTerrainChunkLoader::onTextureLoaded()
196 std::lock_guard lock( mFinishedMutex );
199 mTextureLoaded =
true;
211 mTerrain->mapSettings()->transformContext() );
220 clone->mLayerRef = mLayerRef;
236 return mMetadata->mBoundingVolume.bounds().toRectangle();
242 return mMetadata->geometricErrorAtZoom( -1 );
247 hMin = mMetadata->mBoundingVolume.bounds().zMinimum();
248 hMax = mMetadata->mBoundingVolume.bounds().xMaximum();
256 QgsTileXYZ tileXyz( floor( tileCoords.x() ), floor( tileCoords.y() ), mMetadata->mMaxZoom );
257 if ( !mMetadata->containsTile( tileXyz ) )
261 QgsDebugError( QStringLiteral(
"Quantized Mesh layer doesn't contain max-zoom tile for %1, %2" ).arg( x ).arg( y ) );
267 QString uri = sceneTile.
resources().value( QStringLiteral(
"content" ) ).toString();
268 Q_ASSERT( !uri.isEmpty() );
270 uri = sceneTile.
baseUrl().resolved( uri ).toString();
278 return QgsMeshLayerUtils::interpolateZForPoint( triMesh, point.
x(), point.
y() );
283 QDomDocument doc = elem.ownerDocument();
285 elem.setAttribute( QStringLiteral(
"layer" ), mLayerRef.
layerId );
292 mLayerRef = layerRef;
303 long long tileId = QgsQuantizedMeshIndex::encodeTileId( nodeIdToTile( node->tileId() ) );
304 return new QgsQuantizedMeshTerrainChunkLoader(
mTerrain, node, tileId, mIndex, mTileCrsToMapCrs );
309 return new QgsChunkNode(
312 mMetadata->geometricErrorAtZoom( -1 ) );
317 QVector<QgsChunkNode *> children;
319 for (
auto offset : std::vector<std::pair<int, int>> {{0, 0}, {0, 1}, {1, 0}, {1, 1}} )
321 QgsChunkNodeId childId(
322 node->tileId().d + 1,
323 node->tileId().x * 2 + offset.first,
324 node->tileId().y * 2 + offset.second
327 if ( !mMetadata->containsTile( tile ) )
337 {mapExtent2d.
xMinimum(), mapExtent2d.
yMinimum(), mMetadata->dummyZRange.lower()} );
339 {mapExtent2d.
xMaximum(), mapExtent2d.
yMaximum(), mMetadata->dummyZRange.upper()} );
344 corner1.
x(), corner1.
y(), corner1.
z(),
345 corner2.
x(), corner2.
y(), corner2.
z() ),
346 mMetadata->geometricErrorAtZoom( tile.
zoomLevel() ),
362 const QgsQuantizedMeshDataProvider *provider = qobject_cast<const QgsQuantizedMeshDataProvider *>(
layer->
dataProvider() );
365 QgsDebugError(
"QgsQuantizedMeshTerrainGenerator provided with non-QM layer" );
368 mMetadata = provider->quantizedMeshMetadata();
369 mIndex = provider->index();
379 return qobject_cast<QgsTiledSceneLayer *>( mLayerRef.
get() );
383 : mLayerRef( layerRef )
384 , mMetadata( metadata )
388QgsTileXYZ QgsQuantizedMeshTerrainGenerator::nodeIdToTile( QgsChunkNodeId nodeId )
const
396 mMetadata->mTileScheme == QStringLiteral(
"tms" )
397 ? ( 1 << ( nodeId.d - 1 ) ) - nodeId.y - 1
402#include "qgsquantizedmeshterraingenerator.moc"
double terrainVerticalScale() const
Returns vertical scale (exaggeration) of terrain.
bool isTerrainShadingEnabled() const
Returns whether terrain shading is enabled.
QgsPhongMaterialSettings terrainShadingMaterial() const
Returns terrain shading material.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0).
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...
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
A simple 4x4 matrix implementation useful for transformation in 3D space.
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.
A class to represent a 2D point.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Exception thrown on failure to parse Quantized Mesh tile (malformed data)
virtual QgsChunkNode * createRootNode() const override
bool setLayer(QgsTiledSceneLayer *layer)
Set layer to take tiles from.
virtual void resolveReferences(const QgsProject &project) override
After read of XML, resolve references to any layers that have been read as layer IDs.
virtual void setTerrain(QgsTerrainEntity *t) override
Sets terrain entity for the generator (does not transfer ownership)
virtual QVector< QgsChunkNode * > createChildren(QgsChunkNode *node) const override
QgsTiledSceneLayer * layer() const
Returns the layer we take tiles from.
virtual QgsRectangle rootChunkExtent() const override
extent of the terrain's root chunk in terrain's CRS
virtual void writeXml(QDomElement &elem) const override
Write terrain generator's configuration to XML.
virtual void rootChunkHeightRange(float &hMin, float &hMax) const override
Returns height range of the root chunk in world coordinates.
virtual QgsTerrainGenerator::Type type() const override
What texture generator implementation is this.
virtual QgsTerrainGenerator * clone() const override
Makes a copy of the current instance.
virtual float rootChunkError(const Qgs3DMapSettings &map) const override
Returns error of the root chunk in world coordinates.
virtual QgsChunkLoader * createChunkLoader(QgsChunkNode *node) const override
QgsQuantizedMeshTerrainGenerator()
virtual void readXml(const QDomElement &elem) override
Read terrain generator's configuration from XML.
virtual float heightAt(double x, double y, const Qgs3DRenderContext &context) const override
Returns height at (x,y) in map's CRS.
virtual void setExtent(const QgsRectangle &extent) override
sets the extent of the terrain in terrain's CRS
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Type
Enumeration of the available terrain generators.
@ QuantizedMesh
Terrain is built from quantized mesh tiles.
QgsTilingScheme mTerrainTilingScheme
Tiling scheme of the terrain.
virtual QgsRectangle extent() const
extent of the terrain in terrain's CRS, might be non-square and smaller than rootChunkExtent()
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.
QgsTiledSceneDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
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.
Triangular/Derived Mesh is 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.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
#define QgsDebugError(str)
_LayerRef< QgsMapLayer > QgsMapLayerRef
Mesh - vertices, edges and faces.
void removeDegenerateTriangles()
QgsMesh toMesh(QgsRectangle tileBounds)
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer.
TYPE * resolve(const QgsProject *project)
Resolves the map layer by attempting to find a layer with matching ID within a project.
QString layerId
Original layer ID.