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 += QStringLiteral(
"_" );
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 const QString objFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral(
".obj" ) );
814 const QString mtlFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral(
".mtl" ) );
816 QFile file( objFilePath );
817 if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
819 QgsDebugError( QStringLiteral(
"Scene can not be exported to '%1'. File access error." ).arg( objFilePath ) );
822 QFile mtlFile( mtlFilePath );
823 if ( !mtlFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
825 QgsDebugError( QStringLiteral(
"Scene can not be exported to '%1'. File access error." ).arg( mtlFilePath ) );
829 float maxfloat = std::numeric_limits<float>::max(), minFloat = std::numeric_limits<float>::lowest();
830 float minX = maxfloat, minY = maxfloat, minZ = maxfloat, maxX = minFloat, maxY = minFloat, maxZ = minFloat;
833 obj->
objectBounds( minX, minY, minZ, maxX, maxY, maxZ );
836 float diffX = 1.0f, diffY = 1.0f, diffZ = 1.0f;
841 const float centerX = ( minX + maxX ) / 2.0f;
842 const float centerY = ( minY + maxY ) / 2.0f;
843 const float centerZ = ( minZ + maxZ ) / 2.0f;
845 const float scale = std::max( diffX, std::max( diffY, diffZ ) );
847 QTextStream out( &file );
849 const QString mtlLibName = sceneName +
".mtl";
850 out <<
"mtllib " << mtlLibName <<
"\n";
852 QTextStream mtlOut( &mtlFile );
858 const QString material = obj->
saveMaterial( mtlOut, sceneFolderPath );
859 out <<
"o " << obj->
name() <<
"\n";
860 if ( material != QString() )
861 out <<
"usemtl " << material <<
"\n";
865 QgsDebugMsgLevel( QStringLiteral(
"Scene exported to '%1'" ).arg( objFilePath ), 2 );
868QString Qgs3DSceneExporter::getObjectName(
const QString &name )
871 if ( usedObjectNamesCounter.contains( name ) )
873 ret = QStringLiteral(
"%1%2" ).arg( name ).arg( usedObjectNamesCounter[name] );
874 usedObjectNamesCounter[name]++;
877 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.
void save(const QString &sceneName, const QString &sceneFolderPath, int precision=6)
Saves the scene to a .obj file.
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)