17#include "moc_qgsquantizedmeshterraingenerator.cpp" 
   23#include "qgsmesh3dentity_p.h" 
   45#include <QDiffuseSpecularMaterial> 
   48#include <QPhongMaterial> 
   49#include <QtConcurrentRun> 
   50#include <QTextureMaterial> 
   54class QgsQuantizedMeshTerrainChunkLoader : 
public QgsTerrainTileLoader
 
   58    QgsQuantizedMeshTerrainChunkLoader(
 
   61    virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) 
override;
 
   64    virtual void onTextureLoaded() 
override;
 
   67    QgsTerrainTileEntity *mEntity = 
nullptr;
 
   68    bool mMeshLoaded = 
false;
 
   69    bool mTextureLoaded = 
false;
 
   70    std::mutex mFinishedMutex;
 
   73QgsQuantizedMeshTerrainChunkLoader::QgsQuantizedMeshTerrainChunkLoader( QgsTerrainEntity *terrain_, QgsChunkNode *node, 
long long tileId, 
QgsTiledSceneIndex index, 
const QgsCoordinateTransform &tileCrsToMapCrs )
 
   74  : QgsTerrainTileLoader( terrain_, node )
 
   84  QThreadPool::globalInstance()->start( [
this, node, tileId, index, tileCrsToMapCrs, vertScale, chunkOrigin, shadingEnabled]() {
 
   85    if ( tileId == QgsQuantizedMeshIndex::ROOT_TILE_ID )
 
   96    QString uri = tile.
resources().value( QStringLiteral( 
"content" ) ).toString();
 
   97    Q_ASSERT( !uri.isEmpty() );
 
   99    uri = tile.
baseUrl().resolved( uri ).toString();
 
  102    QgsGltf3DUtils::EntityTransform entityTransform;
 
  104    entityTransform.chunkOriginTargetCrs = chunkOrigin;
 
  105    entityTransform.ecefToTargetCrs = &tileCrsToMapCrs;
 
  106    entityTransform.gltfUpAxis = 
static_cast<Qgis::Axis>( tile.
metadata().value( QStringLiteral( 
"gltfUpAxis" ), 
static_cast<int>( 
Qgis::Axis::Y ) ).toInt() );
 
  112      qmTile.removeDegenerateTriangles();
 
  115      box3D.
setZMinimum( qmTile.mHeader.MinimumHeight * vertScale );
 
  116      box3D.
setZMaximum( qmTile.mHeader.MaximumHeight * vertScale );
 
  117      node->setExactBox3D( box3D );
 
  119      if ( shadingEnabled && qmTile.mNormalCoords.size() == 0 )
 
  121        qmTile.generateNormals();
 
  124      tinygltf::Model model = qmTile.toGltf( 
true, 100, 
true );
 
  127      Qt3DCore::QEntity *gltfEntity = QgsGltf3DUtils::parsedGltfToEntity( model, entityTransform, uri, &errors );
 
  128      if ( !errors.isEmpty() )
 
  135      QgsTerrainTileEntity *terrainEntity = 
new QgsTerrainTileEntity( node->tileId() );
 
  137      Q_ASSERT( gltfEntity->children().size() == 1 );
 
  138      gltfEntity->children()[0]->setParent( terrainEntity );
 
  140      QgsGeoTransform *transform = 
new QgsGeoTransform;
 
  141      transform->setGeoTranslation( chunkOrigin );
 
  142      terrainEntity->addComponent( transform );
 
  145      mEntity = terrainEntity;
 
  149      QgsDebugError( QStringLiteral( 
"Failed to parse tile from '%1'" ).arg( uri ) );
 
  155      std::lock_guard lock( mFinishedMutex );
 
  156      if ( mTextureLoaded )
 
  163Qt3DCore::QEntity *QgsQuantizedMeshTerrainChunkLoader::createEntity( Qt3DCore::QEntity *parent )
 
  167    mEntity->setParent( parent );
 
  168    Qt3DRender::QTexture2D *texture = createTexture( mEntity );
 
  171    Qt3DRender::QMaterial *material = 
nullptr;
 
  176      Qt3DExtras::QDiffuseSpecularMaterial *diffuseMapMaterial = 
new Qt3DExtras::QDiffuseSpecularMaterial;
 
  177      diffuseMapMaterial->
setDiffuse( QVariant::fromValue( texture ) );
 
  178      diffuseMapMaterial->setAmbient( shadingMaterial.
ambient() );
 
  179      diffuseMapMaterial->setSpecular( shadingMaterial.
specular() );
 
  180      diffuseMapMaterial->setShininess( shadingMaterial.
shininess() );
 
  181      material = diffuseMapMaterial;
 
  185      Qt3DExtras::QTextureMaterial *textureMaterial = 
new Qt3DExtras::QTextureMaterial;
 
  186      textureMaterial->setTexture( texture );
 
  187      material = textureMaterial;
 
  190    Qt3DCore::QEntity *gltfEntity = mEntity->findChild<Qt3DCore::QEntity *>();
 
  192    auto oldMaterial = gltfEntity->componentsOfType<QgsMetalRoughMaterial>();
 
  193    Q_ASSERT( oldMaterial.size() > 0 );
 
  194    gltfEntity->removeComponent( oldMaterial[0] );
 
  195    gltfEntity->addComponent( material );
 
  200void QgsQuantizedMeshTerrainChunkLoader::onTextureLoaded()
 
  202  std::lock_guard lock( mFinishedMutex );
 
  205  mTextureLoaded = 
true;
 
  221    mTerrain->mapSettings()->transformContext()
 
 
  231    clone->mLayer = mLayer; 
 
 
  247  return mMetadata->mBoundingVolume.bounds().toRectangle();
 
 
  253  return mMetadata->geometricErrorAtZoom( -1 );
 
 
  258  hMin = mMetadata->mBoundingVolume.bounds().zMinimum();
 
  259  hMax = mMetadata->mBoundingVolume.bounds().xMaximum();
 
 
  267  QgsTileXYZ tileXyz( floor( tileCoords.x() ), floor( tileCoords.y() ), mMetadata->mMaxZoom );
 
  268  if ( !mMetadata->containsTile( tileXyz ) )
 
  272    QgsDebugError( QStringLiteral( 
"Quantized Mesh layer doesn't contain max-zoom tile for %1, %2" ).arg( x ).arg( y ) );
 
  278  QString uri = sceneTile.
resources().value( QStringLiteral( 
"content" ) ).toString();
 
  279  Q_ASSERT( !uri.isEmpty() );
 
  281  uri = sceneTile.
baseUrl().resolved( uri ).toString();
 
  289  return QgsMeshLayerUtils::interpolateZForPoint( triMesh, point.
x(), point.
y() );
 
 
  294  long long tileId = QgsQuantizedMeshIndex::encodeTileId( nodeIdToTile( node->tileId() ) );
 
  295  return new QgsQuantizedMeshTerrainChunkLoader( 
mTerrain, node, tileId, mIndex, mTileCrsToMapCrs );
 
 
  300  return new QgsChunkNode(
 
  303    mMetadata->geometricErrorAtZoom( -1 )
 
 
  309  QVector<QgsChunkNode *> children;
 
  311  for ( 
auto offset : std::vector<std::pair<int, int>> { { 0, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 } } )
 
  313    QgsChunkNodeId childId(
 
  314      node->tileId().d + 1,
 
  315      node->tileId().x * 2 + offset.first,
 
  316      node->tileId().y * 2 + offset.second
 
  319    if ( !mMetadata->containsTile( tile ) )
 
  334        mMetadata->geometricErrorAtZoom( tile.
zoomLevel() ),
 
 
  352  const QgsQuantizedMeshDataProvider *provider = qobject_cast<const QgsQuantizedMeshDataProvider *>( 
layer->
dataProvider() );
 
  355    QgsDebugError( 
"QgsQuantizedMeshTerrainGenerator provided with non-QM layer" );
 
  358  mMetadata = provider->quantizedMeshMetadata();
 
  359  mIndex = provider->index();
 
 
  372QgsTileXYZ QgsQuantizedMeshTerrainGenerator::nodeIdToTile( QgsChunkNodeId nodeId )
 const 
  379    mMetadata->mTileScheme == QStringLiteral( 
"tms" )
 
  380      ? ( 1 << ( nodeId.d - 1 ) ) - nodeId.y - 1
 
  386#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).
 
Terrain generator using a Quantized Mesh tile layer.
 
virtual QgsChunkNode * createRootNode() const override
 
bool setLayer(QgsTiledSceneLayer *layer)
Set layer to take tiles from.
 
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
 
static QgsTerrainGenerator * create()
Creates a new instance of a QgsQuantizedMeshTerrainGenerator object.
 
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 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.
 
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.
 
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.
 
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)