17#include "moc_qgs3dsceneexporter.cpp" 
   20#include <Qt3DCore/QEntity> 
   21#include <Qt3DCore/QComponent> 
   22#include <Qt3DCore/QNode> 
   24#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) 
   25#include <Qt3DRender/QAttribute> 
   26#include <Qt3DRender/QBuffer> 
   27#include <Qt3DRender/QGeometry> 
   33#include <Qt3DCore/QAttribute> 
   34#include <Qt3DCore/QBuffer> 
   35#include <Qt3DCore/QGeometry> 
   42#include <Qt3DRender/QGeometryRenderer> 
   43#include <Qt3DExtras/QPlaneGeometry> 
   44#include <Qt3DCore/QTransform> 
   45#include <Qt3DExtras/QDiffuseSpecularMaterial> 
   46#include <Qt3DExtras/QTextureMaterial> 
   47#include <Qt3DRender/QTextureImage> 
   48#include <Qt3DRender/QTexture> 
   49#include <Qt3DRender/QMesh> 
   50#include <Qt3DRender/QSceneLoader> 
   51#include <Qt3DRender/QAbstractTexture> 
   52#include <Qt3DExtras/QCylinderGeometry> 
   53#include <Qt3DExtras/QConeGeometry> 
   54#include <Qt3DExtras/QSphereGeometry> 
   55#include <Qt3DExtras/QCuboidGeometry> 
   56#include <Qt3DExtras/QTorusGeometry> 
   57#include <Qt3DExtras/QExtrudedTextMesh> 
   58#include <Qt3DExtras/QPhongMaterial> 
   59#include <Qt3DRender/QAbstractTextureImage> 
   78#include "qgsmeshterraingenerator.h" 
   79#include "qgsmeshterraintileloader_p.h" 
   92  const uint bytesOffset = attribute->byteOffset();
 
   93  const uint bytesStride = attribute->byteStride();
 
   94  const uint vertexSize = attribute->vertexSize();
 
   95  const uint dataSize = 
static_cast<uint
>( data.size() );
 
   98  if ( bytesStride == 0 )
 
  100    QgsDebugError( 
"bytesStride==0, the attribute probably was not set properly" );
 
  104  const char *pData = data.constData();
 
  105  for ( 
unsigned int i = bytesOffset; i < dataSize; i += bytesStride )
 
  107    for ( 
unsigned int j = 0; j < vertexSize * 
sizeof( T ); j += 
sizeof( T ) )
 
  110      memcpy( &v, pData + i + j, 
sizeof( T ) );
 
  111      result.push_back( v );
 
 
  120  QVector<uint> result;
 
  121  const char *pData = data.constData();
 
  122  for ( 
int i = 0; i < data.size(); i += 
sizeof( T ) )
 
  125    memcpy( &v, pData + i, 
sizeof( T ) );
 
  126    result.push_back( ( uint ) v );
 
 
  133  switch ( indexAttribute->vertexBaseType() )
 
  135    case Qt3DQAttribute::VertexBaseType::Int:
 
  136      return _getIndexDataImplementation<int>( data );
 
  137    case Qt3DQAttribute::VertexBaseType::UnsignedInt:
 
  138      return _getIndexDataImplementation<uint>( data );
 
  139    case Qt3DQAttribute::VertexBaseType::Short:
 
  140      return _getIndexDataImplementation<short>( data );
 
  141    case Qt3DQAttribute::VertexBaseType::UnsignedShort:
 
  142      return _getIndexDataImplementation<ushort>( data );
 
  143    case Qt3DQAttribute::VertexBaseType::Byte:
 
  144      return _getIndexDataImplementation<char>( data );
 
  145    case Qt3DQAttribute::VertexBaseType::UnsignedByte:
 
  146      return _getIndexDataImplementation<uchar>( data );
 
  148      QgsDebugError( 
"Probably trying to get index data using an attribute that has vertex data" );
 
  151  return QVector<uint>();
 
 
  156  QByteArray bytes = buffer->data();
 
  157  if ( bytes.isNull() )
 
 
  166  QVector<Qt3DQAttribute *> attributes = geometry->attributes();
 
  169    if ( attribute->attributeType() != type )
 
  171    if ( name.isEmpty() || attribute->name() == name )
 
 
  177template<
typename Component>
 
  182  QVector<Qt3DCore::QComponent *> components = entity->components();
 
  183  for ( Qt3DCore::QComponent *component : components )
 
  185    Component *typedComponent = qobject_cast<Component *>( component );
 
  186    if ( typedComponent )
 
  187      return typedComponent;
 
 
  195  const QString rendererType = abstractRenderer->
type();
 
  197  if ( rendererType == 
"rulebased" )
 
  199    int prevSize = mObjects.size();
 
  201    const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
 
  202    for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
 
  204      Qt3DCore::QEntity *parentEntity = qobject_cast<Qt3DCore::QEntity *>( renderer->parent() );
 
  207      Qgs3DExportObject *
object = processGeometryRenderer( renderer, layer->
name() + QStringLiteral( 
"_" ) );
 
  210      if ( mExportTextures )
 
  211        processEntityMaterial( parentEntity, 
object );
 
  212      mObjects.push_back( 
object );
 
  214    return mObjects.size() > prevSize;
 
  217  else if ( rendererType == 
"vector" )
 
  220    if ( vectorLayerRenderer )
 
  232    QgsDebugMsgLevel( QStringLiteral( 
"Type '%1' of layer '%2' is not exportable." ).arg( layer->
name(), rendererType ), 2 );
 
 
  239void Qgs3DSceneExporter::processEntityMaterial( Qt3DCore::QEntity *entity, 
Qgs3DExportObject *
object )
 
  241  Qt3DExtras::QPhongMaterial *phongMaterial = findTypedComponent<Qt3DExtras::QPhongMaterial>( entity );
 
  245    object->setupMaterial( &material );
 
  248  Qt3DExtras::QDiffuseSpecularMaterial *diffuseMapMaterial = findTypedComponent<Qt3DExtras::QDiffuseSpecularMaterial>( entity );
 
  249  if ( diffuseMapMaterial )
 
  251    const Qt3DRender::QTexture2D *diffuseTexture = diffuseMapMaterial->diffuse().value<Qt3DRender::QTexture2D *>();
 
  252    if ( diffuseTexture )
 
  254      const QVector<Qt3DRender::QAbstractTextureImage *> textureImages = diffuseTexture->textureImages();
 
  255      for ( 
const Qt3DRender::QAbstractTextureImage *tex : textureImages )
 
  260          const QImage image = imageTexture->
getImage();
 
  261          object->setTextureImage( image );
 
  275  QgsChunkNode *node = terrain->rootNode();
 
  280  QgsTerrainTileEntity *terrainTile = 
nullptr;
 
  281  QgsTerrainTextureGenerator *textureGenerator = terrain->textureGenerator();
 
  282  textureGenerator->waitForFinished();
 
  283  const QSize oldResolution = textureGenerator->textureSize();
 
  284  textureGenerator->setTextureSize( QSize( mTerrainTextureResolution, mTerrainTextureResolution ) );
 
  285  switch ( generator->
type() )
 
  288      terrainTile = getDemTerrainEntity( terrain, node );
 
  289      parseDemTile( terrainTile, layerName + QStringLiteral( 
"_" ) );
 
  292      terrainTile = getFlatTerrainEntity( terrain, node );
 
  293      parseFlatTile( terrainTile, layerName + QStringLiteral( 
"_" ) );
 
  296      terrainTile = getMeshTerrainEntity( terrain, node );
 
  297      parseMeshTile( terrainTile, layerName + QStringLiteral( 
"_" ) );
 
  304  textureGenerator->setTextureSize( oldResolution );
 
 
  307QgsTerrainTileEntity *Qgs3DSceneExporter::getFlatTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
 
  310  FlatTerrainChunkLoader *flatTerrainLoader = qobject_cast<FlatTerrainChunkLoader *>( generator->
createChunkLoader( node ) );
 
  311  if ( mExportTextures )
 
  312    terrain->textureGenerator()->waitForFinished();
 
  314  Qt3DCore::QEntity *entity = flatTerrainLoader->createEntity( 
this );
 
  315  QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
 
  319QgsTerrainTileEntity *Qgs3DSceneExporter::getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
 
  325  QgsDemTerrainTileLoader *loader = qobject_cast<QgsDemTerrainTileLoader *>( generator->
createChunkLoader( node ) );
 
  327  if ( mExportTextures )
 
  328    terrain->textureGenerator()->waitForFinished();
 
  329  QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity( 
this ) );
 
  334QgsTerrainTileEntity *Qgs3DSceneExporter::getMeshTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
 
  336  QgsMeshTerrainGenerator *generator = 
dynamic_cast<QgsMeshTerrainGenerator *
>( terrain->mapSettings()->terrainGenerator() );
 
  337  QgsMeshTerrainTileLoader *loader = qobject_cast<QgsMeshTerrainTileLoader *>( generator->createChunkLoader( node ) );
 
  339  QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity( 
this ) );
 
  343void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity, 
const QString &layerName )
 
  345  Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
 
  346  Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
 
  349  Qt3DExtras::QPlaneGeometry *tileGeometry = qobject_cast<Qt3DExtras::QPlaneGeometry *>( geometry );
 
  352    QgsDebugError( 
"Qt3DExtras::QPlaneGeometry* is expected but something else was given" );
 
  357  Qt3DQAttribute *positionAttribute = tileGeometry->positionAttribute();
 
  358  if ( !positionAttribute )
 
  360    QgsDebugError( QString( 
"Cannot export '%1' - geometry has no position attribute!" ).arg( layerName ) );
 
  363  const QByteArray verticesBytes = 
getData( positionAttribute->buffer() );
 
  364  if ( verticesBytes.isNull() )
 
  366    QgsDebugError( QString( 
"Geometry for '%1' has position attribute with empty data!" ).arg( layerName ) );
 
  369  const QVector<float> positionBuffer = getAttributeData<float>( positionAttribute, verticesBytes );
 
  373  if ( !indexAttribute )
 
  375    QgsDebugError( QString( 
"Cannot export '%1' - geometry has no index attribute!" ).arg( layerName ) );
 
  378  const QByteArray indexBytes = 
getData( indexAttribute->buffer() );
 
  379  if ( indexBytes.isNull() )
 
  381    QgsDebugError( QString( 
"Geometry for '%1' has index attribute with empty data!" ).arg( layerName ) );
 
  384  const QVector<uint> indexesBuffer = 
getIndexData( indexAttribute, indexBytes );
 
  386  QString objectNamePrefix = layerName;
 
  387  if ( objectNamePrefix != QString() )
 
  388    objectNamePrefix += QString();
 
  391  mObjects.push_back( 
object );
 
  393  object->setSmoothEdges( mSmoothEdges );
 
  394  object->setupPositionCoordinates( positionBuffer, transform->matrix() );
 
  395  object->setupFaces( indexesBuffer );
 
  397  if ( mExportNormals )
 
  400    QVector<float> normalsBuffer;
 
  401    for ( 
int i = 0; i < positionBuffer.size(); i += 3 )
 
  402      normalsBuffer << 0.0f << 1.0f << 0.0f;
 
  403    object->setupNormalCoordinates( normalsBuffer, transform->matrix() );
 
  406  Qt3DQAttribute *texCoordsAttribute = tileGeometry->texCoordAttribute();
 
  407  if ( mExportTextures && texCoordsAttribute )
 
  410    const QVector<float> texCoords = getAttributeData<float>( texCoordsAttribute, verticesBytes );
 
  411    object->setupTextureCoordinates( texCoords );
 
  413    QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
 
  414    const QImage img = textureImage->getImage();
 
  415    object->setTextureImage( img );
 
  419void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity, 
const QString &layerName )
 
  421  Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
 
  422  Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
 
  425  DemTerrainTileGeometry *tileGeometry = qobject_cast<DemTerrainTileGeometry *>( geometry );
 
  428    QgsDebugError( 
"DemTerrainTileGeometry* is expected but something else was given" );
 
  432  Qt3DQAttribute *positionAttribute = tileGeometry->positionAttribute();
 
  433  const QByteArray positionBytes = positionAttribute->buffer()->data();
 
  434  const QVector<float> positionBuffer = getAttributeData<float>( positionAttribute, positionBytes );
 
  437  const QByteArray indexBytes = indexAttribute->buffer()->data();
 
  438  const QVector<unsigned int> indexBuffer = 
getIndexData( indexAttribute, indexBytes );
 
  441  mObjects.push_back( 
object );
 
  443  object->setSmoothEdges( mSmoothEdges );
 
  444  object->setupPositionCoordinates( positionBuffer, transform->matrix() );
 
  445  object->setupFaces( indexBuffer );
 
  447  Qt3DQAttribute *normalsAttributes = tileGeometry->normalAttribute();
 
  448  if ( mExportNormals && normalsAttributes )
 
  450    const QByteArray normalsBytes = normalsAttributes->buffer()->data();
 
  451    const QVector<float> normalsBuffer = getAttributeData<float>( normalsAttributes, normalsBytes );
 
  452    object->setupNormalCoordinates( normalsBuffer, transform->matrix() );
 
  455  Qt3DQAttribute *texCoordsAttribute = tileGeometry->texCoordsAttribute();
 
  456  if ( mExportTextures && texCoordsAttribute )
 
  458    const QByteArray texCoordsBytes = texCoordsAttribute->buffer()->data();
 
  459    const QVector<float> texCoordsBuffer = getAttributeData<float>( texCoordsAttribute, texCoordsBytes );
 
  460    object->setupTextureCoordinates( texCoordsBuffer );
 
  462    QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
 
  463    const QImage img = textureImage->getImage();
 
  464    object->setTextureImage( img );
 
  468void Qgs3DSceneExporter::parseMeshTile( QgsTerrainTileEntity *tileEntity, 
const QString &layerName )
 
  470  QString objectNamePrefix = layerName;
 
  471  if ( objectNamePrefix != QString() )
 
  472    objectNamePrefix += QLatin1Char( 
'_' );
 
  474  const QList<Qt3DRender::QGeometryRenderer *> renderers = tileEntity->findChildren<Qt3DRender::QGeometryRenderer *>();
 
  475  for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
 
  484QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processInstancedPointGeometry( Qt3DCore::QEntity *entity, 
const QString &objectNamePrefix )
 
  486  QVector<Qgs3DExportObject *> objects;
 
  487  const QList<Qt3DQGeometry *> geometriesList = entity->findChildren<
Qt3DQGeometry *>();
 
  490    Qt3DQAttribute *positionAttribute = 
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
 
  492    if ( !positionAttribute || !indexAttribute )
 
  494      QgsDebugError( QString( 
"Cannot export '%1' - geometry has no position or index attribute!" ).arg( objectNamePrefix ) );
 
  498    const QByteArray vertexBytes = positionAttribute->buffer()->data();
 
  499    const QByteArray indexBytes = indexAttribute->buffer()->data();
 
  500    if ( vertexBytes.isNull() || indexBytes.isNull() )
 
  502      QgsDebugError( QString( 
"Geometry for '%1' has position or index attribute with empty data!" ).arg( objectNamePrefix ) );
 
  506    const QVector<float> positionData = getAttributeData<float>( positionAttribute, vertexBytes );
 
  507    const QVector<uint> indexData = 
getIndexData( indexAttribute, indexBytes );
 
  510    if ( !instanceDataAttribute )
 
  512      QgsDebugError( QString( 
"Cannot export '%1' - geometry has no instanceData attribute!" ).arg( objectNamePrefix ) );
 
  515    const QByteArray instancePositionBytes = 
getData( instanceDataAttribute->buffer() );
 
  516    if ( instancePositionBytes.isNull() )
 
  518      QgsDebugError( QString( 
"Geometry for '%1' has instanceData attribute with empty data!" ).arg( objectNamePrefix ) );
 
  521    QVector<float> instancePosition = getAttributeData<float>( instanceDataAttribute, instancePositionBytes );
 
  523    for ( 
int i = 0; i < instancePosition.size(); i += 3 )
 
  526      objects.push_back( 
object );
 
  527      QMatrix4x4 instanceTransform;
 
  528      instanceTransform.translate( instancePosition[i], instancePosition[i + 1], instancePosition[i + 2] );
 
  529      object->setupPositionCoordinates( positionData, instanceTransform );
 
  530      object->setupFaces( indexData );
 
  532      object->setSmoothEdges( mSmoothEdges );
 
  534      Qt3DQAttribute *normalsAttribute = 
findAttribute( geometry, Qt3DQAttribute::defaultNormalAttributeName(), Qt3DQAttribute::VertexAttribute );
 
  535      if ( mExportNormals && normalsAttribute )
 
  538        const QVector<float> normalsData = getAttributeData<float>( normalsAttribute, vertexBytes );
 
  539        object->setupNormalCoordinates( normalsData, instanceTransform );
 
  547QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processSceneLoaderGeometries( Qt3DRender::QSceneLoader *sceneLoader, 
const QString &objectNamePrefix )
 
  549  QVector<Qgs3DExportObject *> objects;
 
  550  Qt3DCore::QEntity *sceneLoaderParent = qobject_cast<Qt3DCore::QEntity *>( sceneLoader->parent() );
 
  551  Qt3DCore::QTransform *entityTransform = findTypedComponent<Qt3DCore::QTransform>( sceneLoaderParent );
 
  552  QMatrix4x4 sceneTransform;
 
  553  if ( entityTransform )
 
  555    sceneTransform = entityTransform->matrix();
 
  557  QStringList entityNames = sceneLoader->entityNames();
 
  558  for ( 
const QString &entityName : entityNames )
 
  560    Qt3DRender::QGeometryRenderer *mesh = qobject_cast<Qt3DRender::QGeometryRenderer *>( sceneLoader->component( entityName, Qt3DRender::QSceneLoader::GeometryRendererComponent ) );
 
  561    Qgs3DExportObject *
object = processGeometryRenderer( mesh, objectNamePrefix, sceneTransform );
 
  564    objects.push_back( 
object );
 
  569Qgs3DExportObject *Qgs3DSceneExporter::processGeometryRenderer( Qt3DRender::QGeometryRenderer *geomRenderer, 
const QString &objectNamePrefix, 
const QMatrix4x4 &sceneTransform )
 
  572  if ( geomRenderer->primitiveType() != Qt3DRender::QGeometryRenderer::Triangles )
 
  587  QVector<std::pair<uint, uint>> triangleIndexStartingIndiceToKeep;
 
  591    QVector<QgsFeatureId> featureIds = tessGeom->
featureIds();
 
  593    QSet<QgsFeatureId> tempFeatToAdd;
 
  596    for ( 
int idx = 0; idx < featureIds.size(); idx++ )
 
  599      if ( !mExportedFeatureIds.contains( feat ) )
 
  602        tempFeatToAdd += feat;
 
  605        const uint startIdx = triangleIndex[idx] * 3;
 
  606        const uint endIdx = idx < triangleIndex.size() - 1 ? triangleIndex[idx + 1] * 3 : std::numeric_limits<uint>::max();
 
  608        if ( startIdx < endIdx ) 
 
  609          triangleIndexStartingIndiceToKeep.append( std::pair<uint, uint>( startIdx, endIdx ) );
 
  612    mExportedFeatureIds += tempFeatToAdd;
 
  614    if ( triangleIndexStartingIndiceToKeep.isEmpty() ) 
 
  621  QMatrix4x4 transformMatrix = sceneTransform;
 
  622  QObject *parent = geomRenderer->parent();
 
  625    Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( parent );
 
  626    Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( entity );
 
  629      transformMatrix = transform->matrix() * transformMatrix;
 
  631    parent = parent->parent();
 
  636  QByteArray indexBytes, vertexBytes;
 
  637  QVector<uint> indexDataTmp;
 
  638  QVector<uint> indexData;
 
  639  QVector<float> positionData;
 
  642  positionAttribute = 
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
 
  643  if ( !positionAttribute )
 
  645    QgsDebugError( QString( 
"Cannot export '%1' - geometry has no position attribute!" ).arg( objectNamePrefix ) );
 
  649  vertexBytes = 
getData( positionAttribute->buffer() );
 
  650  if ( vertexBytes.isNull() )
 
  652    QgsDebugError( QString( 
"Will not export '%1' as geometry has empty position data!" ).arg( objectNamePrefix ) );
 
  656  positionData = getAttributeData<float>( positionAttribute, vertexBytes );
 
  659  QVector<Qt3DQAttribute *> attributes = geometry->attributes();
 
  662    if ( attribute->attributeType() == Qt3DQAttribute::IndexAttribute )
 
  664      indexAttribute = attribute;
 
  665      indexBytes = 
getData( indexAttribute->buffer() );
 
  666      if ( indexBytes.isNull() )
 
  668        QgsDebugError( QString( 
"Geometry for '%1' has index attribute with empty data!" ).arg( objectNamePrefix ) );
 
  672        indexDataTmp = 
getIndexData( indexAttribute, indexBytes );
 
  679  if ( !indexAttribute )
 
  681    for ( uint i = 0; i < static_cast<uint>( positionData.size() / 3 ); ++i )
 
  683      indexDataTmp.push_back( i );
 
  688  if ( triangleIndexStartingIndiceToKeep.isEmpty() )
 
  691    indexData.append( indexDataTmp );
 
  697    const int triangleIndexStartingIndiceToKeepSize = triangleIndexStartingIndiceToKeep.size();
 
  698    const uint indexDataTmpSize = 
static_cast<uint
>( indexDataTmp.size() );
 
  699    for ( uint i = 0; i < indexDataTmpSize; ++i )
 
  701      uint idx = indexDataTmp[
static_cast<int>( i )];
 
  703      while ( intervalIdx < triangleIndexStartingIndiceToKeepSize
 
  704              && idx > triangleIndexStartingIndiceToKeep[intervalIdx].first
 
  705              && idx >= triangleIndexStartingIndiceToKeep[intervalIdx].second )
 
  711      if ( intervalIdx < triangleIndexStartingIndiceToKeepSize
 
  712           && idx >= triangleIndexStartingIndiceToKeep[intervalIdx].first
 
  713           && idx < triangleIndexStartingIndiceToKeep[intervalIdx].second )
 
  715        indexData.push_back( idx );
 
  722  object->setupPositionCoordinates( positionData, transformMatrix );
 
  723  object->setupFaces( indexData );
 
  725  Qt3DQAttribute *normalsAttribute = 
findAttribute( geometry, Qt3DQAttribute::defaultNormalAttributeName(), Qt3DQAttribute::VertexAttribute );
 
  726  if ( mExportNormals && normalsAttribute )
 
  729    const QVector<float> normalsData = getAttributeData<float>( normalsAttribute, vertexBytes );
 
  730    object->setupNormalCoordinates( normalsData, transformMatrix );
 
  733  Qt3DQAttribute *texCoordsAttribute = 
findAttribute( geometry, Qt3DQAttribute::defaultTextureCoordinateAttributeName(), Qt3DQAttribute::VertexAttribute );
 
  734  if ( mExportTextures && texCoordsAttribute )
 
  737    const QVector<float> texCoordsData = getAttributeData<float>( texCoordsAttribute, vertexBytes );
 
  738    object->setupTextureCoordinates( texCoordsData );
 
  744QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processLines( Qt3DCore::QEntity *entity, 
const QString &objectNamePrefix )
 
  746  QVector<Qgs3DExportObject *> objs;
 
  747  const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
 
  748  for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
 
  750    if ( renderer->primitiveType() != Qt3DRender::QGeometryRenderer::LineStripAdjacency )
 
  753    Qt3DQAttribute *positionAttribute = 
findAttribute( geom, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
 
  755    if ( !positionAttribute || !indexAttribute )
 
  757      QgsDebugError( QString( 
"Cannot export '%1' - geometry has no position or index attribute!" ).arg( objectNamePrefix ) );
 
  761    const QByteArray vertexBytes = 
getData( positionAttribute->buffer() );
 
  762    const QByteArray indexBytes = 
getData( indexAttribute->buffer() );
 
  763    if ( vertexBytes.isNull() || indexBytes.isNull() )
 
  765      QgsDebugError( QString( 
"Geometry for '%1' has position or index attribute with empty data!" ).arg( objectNamePrefix ) );
 
  768    const QVector<float> positionData = getAttributeData<float>( positionAttribute, vertexBytes );
 
  769    const QVector<uint> indexData = 
getIndexData( indexAttribute, indexBytes );
 
  776    objs.push_back( exportObject );
 
  781Qgs3DExportObject *Qgs3DSceneExporter::processPoints( Qt3DCore::QEntity *entity, 
const QString &objectNamePrefix )
 
  783  QVector<float> points;
 
  784  const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
 
  785  for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
 
  787    Qt3DQGeometry *geometry = qobject_cast<QgsBillboardGeometry *>( renderer->geometry() );
 
  790    Qt3DQAttribute *positionAttribute = 
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
 
  791    if ( !positionAttribute )
 
  793      QgsDebugError( QString( 
"Cannot export '%1' - geometry has no position attribute!" ).arg( objectNamePrefix ) );
 
  796    const QByteArray positionBytes = 
getData( positionAttribute->buffer() );
 
  797    if ( positionBytes.isNull() )
 
  799      QgsDebugError( QString( 
"Geometry for '%1' has position attribute with empty data!" ).arg( objectNamePrefix ) );
 
  802    const QVector<float> positions = getAttributeData<float>( positionAttribute, positionBytes );
 
  813  if ( mObjects.isEmpty() )
 
  818  const QString objFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral( 
".obj" ) );
 
  819  const QString mtlFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral( 
".mtl" ) );
 
  821  QFile file( objFilePath );
 
  822  if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
 
  824    QgsDebugError( QStringLiteral( 
"Scene can not be exported to '%1'. File access error." ).arg( objFilePath ) );
 
  827  QFile mtlFile( mtlFilePath );
 
  828  if ( !mtlFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
 
  830    QgsDebugError( QStringLiteral( 
"Scene can not be exported to '%1'. File access error." ).arg( mtlFilePath ) );
 
  834  float maxfloat = std::numeric_limits<float>::max(), minFloat = std::numeric_limits<float>::lowest();
 
  835  float minX = maxfloat, minY = maxfloat, minZ = maxfloat, maxX = minFloat, maxY = minFloat, maxZ = minFloat;
 
  838    obj->
objectBounds( minX, minY, minZ, maxX, maxY, maxZ );
 
  841  float diffX = 1.0f, diffY = 1.0f, diffZ = 1.0f;
 
  846  const float centerX = ( minX + maxX ) / 2.0f;
 
  847  const float centerY = ( minY + maxY ) / 2.0f;
 
  848  const float centerZ = ( minZ + maxZ ) / 2.0f;
 
  850  const float scale = std::max( diffX, std::max( diffY, diffZ ) );
 
  852  QTextStream out( &file );
 
  854  const QString mtlLibName = sceneName + 
".mtl";
 
  855  out << 
"mtllib " << mtlLibName << 
"\n";
 
  857  QTextStream mtlOut( &mtlFile );
 
  863    const QString material = obj->
saveMaterial( mtlOut, sceneFolderPath );
 
  864    out << 
"o " << obj->
name() << 
"\n";
 
  865    if ( material != QString() )
 
  866      out << 
"usemtl " << material << 
"\n";
 
  870  QgsDebugMsgLevel( QStringLiteral( 
"Scene exported to '%1'" ).arg( objFilePath ), 2 );
 
 
  874QString Qgs3DSceneExporter::getObjectName( 
const QString &name )
 
  877  if ( usedObjectNamesCounter.contains( name ) )
 
  879    ret = QStringLiteral( 
"%1%2" ).arg( name ).arg( usedObjectNamesCounter[name] );
 
  880    usedObjectNamesCounter[name]++;
 
  883    usedObjectNamesCounter[name] = 2;
 
Manages the data of each object of the scene (positions, normals, texture coordinates ....
 
void setType(ObjectType type)
Sets the object type.
 
void setupPositionCoordinates(const QVector< float > &positionsBuffer, const QMatrix4x4 &transform)
Sets positions coordinates and does the translation, rotation and scaling.
 
void objectBounds(float &minX, float &minY, float &minZ, float &maxX, float &maxY, float &maxZ)
Updates the box bounds explained with the current object bounds This expands the bounding box if the ...
 
void saveTo(QTextStream &out, float scale, const QVector3D ¢er, int precision=6)
Saves the current object to the output stream while scaling the object and centering it to be visible...
 
QString name() const
Returns the object name.
 
QString saveMaterial(QTextStream &mtlOut, const QString &folder)
saves the texture of the object and material information
 
void setupLine(const QVector< uint > &facesIndexes)
sets line vertex indexes
 
QgsTerrainGenerator * terrainGenerator() const
Returns the terrain generator.
 
bool terrainRenderingEnabled() const
Returns whether the 2D terrain surface will be rendered.
 
bool save(const QString &sceneName, const QString &sceneFolderPath, int precision=6)
Saves the scene to a .obj file Returns false if the operation failed.
 
void parseTerrain(QgsTerrainEntity *terrain, const QString &layer)
Creates terrain export objects from the terrain entity.
 
float scale() const
Returns the scale of the exported 3D model.
 
bool parseVectorLayerEntity(Qt3DCore::QEntity *entity, QgsVectorLayer *layer)
Creates necessary export objects from entity if it represents valid vector layer entity Returns false...
 
static QgsPhongMaterialSettings phongMaterialFromQt3DComponent(Qt3DExtras::QPhongMaterial *material)
Returns phong material settings object based on the Qt3D material.
 
Base class for all renderers that may to participate in 3D view.
 
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass)
 
virtual bool exportGeometries(Qgs3DSceneExporter *exporter, Qt3DCore::QEntity *entity, const QString &objectNamePrefix) const
Exports the geometries contained within the hierarchy of entity.
 
QgsDemHeightMapGenerator * heightMapGenerator()
Returns height map generator object - takes care of extraction of elevations from the layer)
 
QgsChunkLoader * createChunkLoader(QgsChunkNode *node) const override
 
void setResolution(int resolution)
Sets resolution of the generator (how many elevation samples on one side of a terrain tile)
 
QgsChunkLoader * createChunkLoader(QgsChunkNode *node) const override SIP_FACTORY
 
Holds an image that can be used as a texture in the 3D view.
 
QImage getImage() const
Returns the image.
 
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
 
@ QuantizedMesh
Terrain is built from quantized mesh tiles.
 
@ Dem
Terrain is built from raster layer with digital elevation model.
 
@ Online
Terrain is built from downloaded tiles with digital elevation model.
 
@ Mesh
Terrain is built from mesh layer with z value on vertices.
 
@ Flat
The whole terrain is flat area.
 
virtual Type type() const =0
What texture generator implementation is this.
 
QVector< QgsFeatureId > featureIds() const
Returns included feature ids.
 
QVector< uint > triangleIndexStartingIndices() const
Returns triangle index for features. For a feature featureIds()[i], matching triangles start at trian...
 
3D renderer that renders all features of a vector layer with the same 3D symbol.
 
const QgsAbstract3DSymbol * symbol() const
Returns 3D symbol associated with the renderer.
 
Represents a vector layer which manages a vector based data sets.
 
Qt3DCore::QAttribute Qt3DQAttribute
 
Qt3DCore::QBuffer Qt3DQBuffer
 
QVector< T > getAttributeData(Qt3DQAttribute *attribute, const QByteArray &data)
 
Qt3DQAttribute * findAttribute(Qt3DQGeometry *geometry, const QString &name, Qt3DQAttribute::AttributeType type)
 
Qt3DCore::QAttribute Qt3DQAttribute
 
QVector< uint > getIndexData(Qt3DQAttribute *indexAttribute, const QByteArray &data)
 
QByteArray getData(Qt3DQBuffer *buffer)
 
Qt3DCore::QBuffer Qt3DQBuffer
 
QVector< uint > _getIndexDataImplementation(const QByteArray &data)
 
Component * findTypedComponent(Qt3DCore::QEntity *entity)
 
Qt3DCore::QGeometry Qt3DQGeometry
 
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)