21#include "qgsmesh3dentity_p.h"
39#include <qcomponent.h>
40#include <qdiffusespecularmaterial.h>
43#include <qnamespace.h>
44#include <qphongmaterial.h>
45#include <qtconcurrentrun.h>
46#include <qtexturematerial.h>
50class QgsQuantizedMeshTerrainChunkLoader :
public QgsTerrainTileLoader
54 QgsQuantizedMeshTerrainChunkLoader(
56 virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent )
override;
59 virtual void onTextureLoaded()
override;
62 QgsTerrainTileEntity *mEntity =
nullptr;
63 bool mMeshLoaded =
false;
64 bool mTextureLoaded =
false;
65 std::mutex mFinishedMutex;
68QgsQuantizedMeshTerrainChunkLoader::QgsQuantizedMeshTerrainChunkLoader( QgsTerrainEntity *terrain_, QgsChunkNode *node,
long long tileId,
QgsTiledSceneIndex index,
const QgsCoordinateTransform &tileCrsToMapCrs )
69 : QgsTerrainTileLoader( terrain_, node )
79 QThreadPool::globalInstance()->start( [
this, node, tileId, index, tileCrsToMapCrs, vertScale, mapOrigin, shadingEnabled ]()
81 if ( tileId == QgsQuantizedMeshIndex::ROOT_TILE_ID )
92 QString uri = tile.
resources().value( QStringLiteral(
"content" ) ).toString();
93 Q_ASSERT( !uri.isEmpty() );
95 uri = tile.
baseUrl().resolved( uri ).toString();
98 QgsGltf3DUtils::EntityTransform entityTransform;
100 entityTransform.sceneOriginTargetCrs = mapOrigin;
101 entityTransform.ecefToTargetCrs = &tileCrsToMapCrs;
102 entityTransform.gltfUpAxis =
static_cast< Qgis::Axis >( tile.
metadata().value( QStringLiteral(
"gltfUpAxis" ),
static_cast< int >(
Qgis::Axis::Y ) ).toInt() );
108 qmTile.removeDegenerateTriangles();
114 bbox.
xMin, qmTile.mHeader.MinimumHeight * vertScale, bbox.
zMin,
115 bbox.
xMax, qmTile.mHeader.MaximumHeight * vertScale, bbox.
zMax ) );
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;
230 return mMetadata->mBoundingVolume.bounds().toRectangle();
236 return mMetadata->geometricErrorAtZoom( -1 );
241 hMin = mMetadata->mBoundingVolume.bounds().zMinimum();
242 hMax = mMetadata->mBoundingVolume.bounds().xMaximum();
257 QDomDocument doc = elem.ownerDocument();
259 elem.setAttribute( QStringLiteral(
"layer" ), mLayerRef.
layerId );
266 mLayerRef = layerRef;
277 long long tileId = QgsQuantizedMeshIndex::encodeTileId( nodeIdToTile( node->tileId() ) );
278 return new QgsQuantizedMeshTerrainChunkLoader(
mTerrain, node, tileId, mIndex, mTileCrsToMapCrs );
283 return new QgsChunkNode(
286 mMetadata->geometricErrorAtZoom( -1 ) );
291 QVector<QgsChunkNode *> children;
293 for (
auto offset : std::vector<std::pair<int, int>> {{0, 0}, {0, 1}, {1, 0}, {1, 1}} )
295 QgsChunkNodeId childId(
296 node->tileId().d + 1,
297 node->tileId().x * 2 + offset.first,
298 node->tileId().y * 2 + offset.second
301 if ( !mMetadata->containsTile( tile ) )
308 {extent2d.
xMinimum(), extent2d.
yMinimum(), mMetadata->dummyZRange.lower()} );
310 {extent2d.
xMaximum(), extent2d.
yMaximum(), mMetadata->dummyZRange.upper()} );
315 corner1.
x(), corner1.
y(), corner1.
z(),
316 corner2.
x(), corner2.
y(), corner2.
z() ),
317 mMetadata->geometricErrorAtZoom( tile.
zoomLevel() ),
333 const QgsQuantizedMeshDataProvider *provider = qobject_cast<const QgsQuantizedMeshDataProvider *>(
layer->
dataProvider() );
336 QgsDebugError(
"QgsQuantizedMeshTerrainGenerator provided with non-QM layer" );
339 mMetadata = provider->quantizedMeshMetadata();
340 mIndex = provider->index();
350 return qobject_cast<QgsTiledSceneLayer *>( mLayerRef.
get() );
354 : mLayerRef( layerRef )
355 , mMetadata( metadata )
359QgsTileXYZ QgsQuantizedMeshTerrainGenerator::nodeIdToTile( QgsChunkNodeId nodeId )
const
367 mMetadata->mTileScheme == QStringLiteral(
"tms" )
368 ? ( 1 << ( nodeId.d - 1 ) ) - nodeId.y - 1
373#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).
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.
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 terrain's CRS.
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of 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.
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.
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.
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
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.