17#include "moc_qgsquantizedmeshterraingenerator.cpp"
22#include "qgsmesh3dentity_p.h"
41#include <qcomponent.h>
42#include <qdiffusespecularmaterial.h>
45#include <qnamespace.h>
46#include <qphongmaterial.h>
47#include <qtconcurrentrun.h>
48#include <qtexturematerial.h>
52class QgsQuantizedMeshTerrainChunkLoader :
public QgsTerrainTileLoader
56 QgsQuantizedMeshTerrainChunkLoader(
58 virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent )
override;
61 virtual void onTextureLoaded()
override;
64 QgsTerrainTileEntity *mEntity =
nullptr;
65 bool mMeshLoaded =
false;
66 bool mTextureLoaded =
false;
67 std::mutex mFinishedMutex;
70QgsQuantizedMeshTerrainChunkLoader::QgsQuantizedMeshTerrainChunkLoader( QgsTerrainEntity *terrain_, QgsChunkNode *node,
long long tileId,
QgsTiledSceneIndex index,
const QgsCoordinateTransform &tileCrsToMapCrs )
71 : QgsTerrainTileLoader( terrain_, node )
81 QThreadPool::globalInstance()->start( [
this, node, tileId, index, tileCrsToMapCrs, vertScale, mapOrigin, shadingEnabled ]()
83 if ( tileId == QgsQuantizedMeshIndex::ROOT_TILE_ID )
94 QString uri = tile.
resources().value( QStringLiteral(
"content" ) ).toString();
95 Q_ASSERT( !uri.isEmpty() );
97 uri = tile.
baseUrl().resolved( uri ).toString();
100 QgsGltf3DUtils::EntityTransform entityTransform;
102 entityTransform.sceneOriginTargetCrs = mapOrigin;
103 entityTransform.ecefToTargetCrs = &tileCrsToMapCrs;
104 entityTransform.gltfUpAxis =
static_cast< Qgis::Axis >( tile.
metadata().value( QStringLiteral(
"gltfUpAxis" ),
static_cast< int >(
Qgis::Axis::Y ) ).toInt() );
110 qmTile.removeDegenerateTriangles();
113 box3D.
setZMinimum( qmTile.mHeader.MinimumHeight * vertScale );
114 box3D.
setZMaximum( qmTile.mHeader.MaximumHeight * vertScale );
115 node->setExactBox3D( box3D );
117 if ( shadingEnabled && qmTile.mNormalCoords.size() == 0 )
119 qmTile.generateNormals();
122 tinygltf::Model model = qmTile.toGltf(
true, 100,
true );
125 Qt3DCore::QEntity *gltfEntity = QgsGltf3DUtils::parsedGltfToEntity( model, entityTransform, uri, &errors );
126 if ( !errors.isEmpty() )
133 QgsTerrainTileEntity *terrainEntity =
new QgsTerrainTileEntity( node->tileId() );
135 Q_ASSERT( gltfEntity->children().size() == 1 );
136 gltfEntity->children()[0]->setParent( terrainEntity );
138 mEntity = terrainEntity;
142 QgsDebugError( QStringLiteral(
"Failed to parse tile from '%1'" ).arg( uri ) );
148 std::lock_guard lock( mFinishedMutex );
149 if ( mTextureLoaded )
156Qt3DCore::QEntity *QgsQuantizedMeshTerrainChunkLoader::createEntity( Qt3DCore::QEntity *parent )
160 mEntity->setParent( parent );
161 Qt3DRender::QTexture2D *texture = createTexture( mEntity );
164 Qt3DRender::QMaterial *material =
nullptr;
169 Qt3DExtras::QDiffuseSpecularMaterial *diffuseMapMaterial =
new Qt3DExtras::QDiffuseSpecularMaterial;
170 diffuseMapMaterial->
setDiffuse( QVariant::fromValue( texture ) );
171 diffuseMapMaterial->setAmbient( shadingMaterial.
ambient() );
172 diffuseMapMaterial->setSpecular( shadingMaterial.
specular() );
173 diffuseMapMaterial->setShininess( shadingMaterial.
shininess() );
174 material = diffuseMapMaterial;
178 Qt3DExtras::QTextureMaterial *textureMaterial =
new Qt3DExtras::QTextureMaterial;
179 textureMaterial->setTexture( texture );
180 material = textureMaterial;
183 Qt3DCore::QEntity *gltfEntity = mEntity->findChild<Qt3DCore::QEntity *>();
185 auto oldMaterial = gltfEntity->componentsOfType<QgsMetalRoughMaterial>();
186 Q_ASSERT( oldMaterial.size() > 0 );
187 gltfEntity->removeComponent( oldMaterial[0] );
188 gltfEntity->addComponent( material );
193void QgsQuantizedMeshTerrainChunkLoader::onTextureLoaded()
195 std::lock_guard lock( mFinishedMutex );
198 mTextureLoaded =
true;
210 mTerrain->mapSettings()->transformContext() );
219 clone->mLayerRef = mLayerRef;
235 return mMetadata->mBoundingVolume.bounds().toRectangle();
241 return mMetadata->geometricErrorAtZoom( -1 );
246 hMin = mMetadata->mBoundingVolume.bounds().zMinimum();
247 hMax = mMetadata->mBoundingVolume.bounds().xMaximum();
255 QgsTileXYZ tileXyz( floor( tileCoords.x() ), floor( tileCoords.y() ), mMetadata->mMaxZoom );
256 if ( !mMetadata->containsTile( tileXyz ) )
260 QgsDebugError( QStringLiteral(
"Quantized Mesh layer doesn't contain max-zoom tile for %1, %2" ).arg( x ).arg( y ) );
266 QString uri = sceneTile.
resources().value( QStringLiteral(
"content" ) ).toString();
267 Q_ASSERT( !uri.isEmpty() );
269 uri = sceneTile.
baseUrl().resolved( uri ).toString();
277 return QgsMeshLayerUtils::interpolateZForPoint( triMesh, point.
x(), point.
y() );
282 QDomDocument doc = elem.ownerDocument();
284 elem.setAttribute( QStringLiteral(
"layer" ), mLayerRef.
layerId );
291 mLayerRef = layerRef;
302 long long tileId = QgsQuantizedMeshIndex::encodeTileId( nodeIdToTile( node->tileId() ) );
303 return new QgsQuantizedMeshTerrainChunkLoader(
mTerrain, node, tileId, mIndex, mTileCrsToMapCrs );
308 return new QgsChunkNode(
311 mMetadata->geometricErrorAtZoom( -1 ) );
316 QVector<QgsChunkNode *> children;
318 for (
auto offset : std::vector<std::pair<int, int>> {{0, 0}, {0, 1}, {1, 0}, {1, 1}} )
320 QgsChunkNodeId childId(
321 node->tileId().d + 1,
322 node->tileId().x * 2 + offset.first,
323 node->tileId().y * 2 + offset.second
326 if ( !mMetadata->containsTile( tile ) )
341 mMetadata->geometricErrorAtZoom( tile.
zoomLevel() ),
357 const QgsQuantizedMeshDataProvider *provider = qobject_cast<const QgsQuantizedMeshDataProvider *>(
layer->
dataProvider() );
360 QgsDebugError(
"QgsQuantizedMeshTerrainGenerator provided with non-QM layer" );
363 mMetadata = provider->quantizedMeshMetadata();
364 mIndex = provider->index();
374 return qobject_cast<QgsTiledSceneLayer *>( mLayerRef.
get() );
378 : mLayerRef( layerRef )
379 , mMetadata( metadata )
383QgsTileXYZ QgsQuantizedMeshTerrainGenerator::nodeIdToTile( QgsChunkNodeId nodeId )
const
391 mMetadata->mTileScheme == QStringLiteral(
"tms" )
392 ? ( 1 << ( nodeId.d - 1 ) ) - nodeId.y - 1
397#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 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.
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...
#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.