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 )
continue;
170 if ( name.isEmpty() || attribute->name() == name )
return attribute;
175template<
typename Component>
180 QVector<Qt3DCore::QComponent *> components = entity->components();
181 for ( Qt3DCore::QComponent *component : components )
183 Component *typedComponent = qobject_cast<Component *>( component );
184 if ( typedComponent )
185 return typedComponent;
193 const QString rendererType = abstractRenderer->
type();
195 if ( rendererType ==
"rulebased" )
197 int prevSize = mObjects.size();
199 const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
200 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
202 Qt3DCore::QEntity *parentEntity = qobject_cast<Qt3DCore::QEntity *>( renderer->parent() );
205 Qgs3DExportObject *
object = processGeometryRenderer( renderer, layer->
name() + QStringLiteral(
"_" ) );
208 if ( mExportTextures )
209 processEntityMaterial( parentEntity,
object );
210 mObjects.push_back(
object );
212 return mObjects.size() > prevSize;
215 else if ( rendererType ==
"vector" )
218 if ( vectorLayerRenderer )
230 QgsDebugMsgLevel( QStringLiteral(
"Type '%1' of layer '%2' is not exportable." ).arg( layer->
name(), rendererType ), 2 );
237void Qgs3DSceneExporter::processEntityMaterial( Qt3DCore::QEntity *entity,
Qgs3DExportObject *
object )
239 Qt3DExtras::QPhongMaterial *phongMaterial = findTypedComponent<Qt3DExtras::QPhongMaterial>( entity );
243 object->setupMaterial( &material );
246 Qt3DExtras::QDiffuseSpecularMaterial *diffuseMapMaterial = findTypedComponent<Qt3DExtras::QDiffuseSpecularMaterial>( entity );
247 if ( diffuseMapMaterial )
249 const Qt3DRender::QTexture2D *diffuseTexture = diffuseMapMaterial->diffuse().value< Qt3DRender::QTexture2D * >();
250 if ( diffuseTexture )
252 const QVector<Qt3DRender::QAbstractTextureImage *> textureImages = diffuseTexture->textureImages();
253 for (
const Qt3DRender::QAbstractTextureImage *tex : textureImages )
258 const QImage image = imageTexture->
getImage();
259 object->setTextureImage( image );
273 QgsChunkNode *node = terrain->rootNode();
278 QgsTerrainTileEntity *terrainTile =
nullptr;
279 QgsTerrainTextureGenerator *textureGenerator = terrain->textureGenerator();
280 textureGenerator->waitForFinished();
281 const QSize oldResolution = textureGenerator->textureSize();
282 textureGenerator->setTextureSize( QSize( mTerrainTextureResolution, mTerrainTextureResolution ) );
283 switch ( generator->
type() )
286 terrainTile = getDemTerrainEntity( terrain, node );
287 parseDemTile( terrainTile, layerName + QStringLiteral(
"_" ) );
290 terrainTile = getFlatTerrainEntity( terrain, node );
291 parseFlatTile( terrainTile, layerName + QStringLiteral(
"_" ) );
294 terrainTile = getMeshTerrainEntity( terrain, node );
295 parseMeshTile( terrainTile, layerName + QStringLiteral(
"_" ) );
302 textureGenerator->setTextureSize( oldResolution );
305QgsTerrainTileEntity *Qgs3DSceneExporter::getFlatTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
308 FlatTerrainChunkLoader *flatTerrainLoader = qobject_cast<FlatTerrainChunkLoader *>( generator->
createChunkLoader( node ) );
309 if ( mExportTextures )
310 terrain->textureGenerator()->waitForFinished();
312 Qt3DCore::QEntity *entity = flatTerrainLoader->createEntity(
this );
313 QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
317QgsTerrainTileEntity *Qgs3DSceneExporter::getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
323 QgsDemTerrainTileLoader *loader = qobject_cast<QgsDemTerrainTileLoader *>( generator->
createChunkLoader( node ) );
325 if ( mExportTextures )
326 terrain->textureGenerator()->waitForFinished();
327 QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity(
this ) );
332QgsTerrainTileEntity *Qgs3DSceneExporter::getMeshTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
334 QgsMeshTerrainGenerator *generator =
dynamic_cast<QgsMeshTerrainGenerator *
>( terrain->mapSettings()->terrainGenerator() );
335 QgsMeshTerrainTileLoader *loader = qobject_cast<QgsMeshTerrainTileLoader *>( generator->createChunkLoader( node ) );
337 QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity(
this ) );
341void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity,
const QString &layerName )
343 Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
344 Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
347 Qt3DExtras::QPlaneGeometry *tileGeometry = qobject_cast<Qt3DExtras::QPlaneGeometry *>( geometry );
350 QgsDebugError(
"Qt3DExtras::QPlaneGeometry* is expected but something else was given" );
355 Qt3DQAttribute *positionAttribute = tileGeometry->positionAttribute();
356 if ( !positionAttribute )
358 QgsDebugError( QString(
"Cannot export '%1' - geometry has no position attribute!" ).arg( layerName ) );
361 const QByteArray verticesBytes =
getData( positionAttribute->buffer() );
362 if ( verticesBytes.isNull() )
364 QgsDebugError( QString(
"Geometry for '%1' has position attribute with empty data!" ).arg( layerName ) );
367 const QVector<float> positionBuffer = getAttributeData<float>( positionAttribute, verticesBytes );
371 if ( !indexAttribute )
373 QgsDebugError( QString(
"Cannot export '%1' - geometry has no index attribute!" ).arg( layerName ) );
376 const QByteArray indexBytes =
getData( indexAttribute->buffer() );
377 if ( indexBytes.isNull() )
379 QgsDebugError( QString(
"Geometry for '%1' has index attribute with empty data!" ).arg( layerName ) );
382 const QVector<uint> indexesBuffer =
getIndexData( indexAttribute, indexBytes );
384 QString objectNamePrefix = layerName;
385 if ( objectNamePrefix != QString() ) objectNamePrefix += QString();
388 mObjects.push_back(
object );
390 object->setSmoothEdges( mSmoothEdges );
391 object->setupPositionCoordinates( positionBuffer, transform->matrix() );
392 object->setupFaces( indexesBuffer );
394 if ( mExportNormals )
397 QVector<float> normalsBuffer;
398 for (
int i = 0; i < positionBuffer.size(); i += 3 ) normalsBuffer << 0.0f << 1.0f << 0.0f;
399 object->setupNormalCoordinates( normalsBuffer, transform->matrix() );
402 Qt3DQAttribute *texCoordsAttribute = tileGeometry->texCoordAttribute();
403 if ( mExportTextures && texCoordsAttribute )
406 const QVector<float> texCoords = getAttributeData<float>( texCoordsAttribute, verticesBytes );
407 object->setupTextureCoordinates( texCoords );
409 QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
410 const QImage img = textureImage->getImage();
411 object->setTextureImage( img );
415void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity,
const QString &layerName )
417 Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
418 Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
421 DemTerrainTileGeometry *tileGeometry = qobject_cast<DemTerrainTileGeometry *>( geometry );
424 QgsDebugError(
"DemTerrainTileGeometry* is expected but something else was given" );
428 Qt3DQAttribute *positionAttribute = tileGeometry->positionAttribute();
429 const QByteArray positionBytes = positionAttribute->buffer()->data();
430 const QVector<float> positionBuffer = getAttributeData<float>( positionAttribute, positionBytes );
433 const QByteArray indexBytes = indexAttribute->buffer()->data();
434 const QVector<unsigned int> indexBuffer =
getIndexData( indexAttribute, indexBytes );
437 mObjects.push_back(
object );
439 object->setSmoothEdges( mSmoothEdges );
440 object->setupPositionCoordinates( positionBuffer, transform->matrix() );
441 object->setupFaces( indexBuffer );
443 Qt3DQAttribute *normalsAttributes = tileGeometry->normalAttribute();
444 if ( mExportNormals && normalsAttributes )
446 const QByteArray normalsBytes = normalsAttributes->buffer()->data();
447 const QVector<float> normalsBuffer = getAttributeData<float>( normalsAttributes, normalsBytes );
448 object->setupNormalCoordinates( normalsBuffer, transform->matrix() );
451 Qt3DQAttribute *texCoordsAttribute = tileGeometry->texCoordsAttribute();
452 if ( mExportTextures && texCoordsAttribute )
454 const QByteArray texCoordsBytes = texCoordsAttribute->buffer()->data();
455 const QVector<float> texCoordsBuffer = getAttributeData<float>( texCoordsAttribute, texCoordsBytes );
456 object->setupTextureCoordinates( texCoordsBuffer );
458 QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
459 const QImage img = textureImage->getImage();
460 object->setTextureImage( img );
464void Qgs3DSceneExporter::parseMeshTile( QgsTerrainTileEntity *tileEntity,
const QString &layerName )
466 QString objectNamePrefix = layerName;
467 if ( objectNamePrefix != QString() ) objectNamePrefix += QStringLiteral(
"_" );
469 const QList<Qt3DRender::QGeometryRenderer *> renderers = tileEntity->findChildren<Qt3DRender::QGeometryRenderer *>();
470 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
479QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processInstancedPointGeometry( Qt3DCore::QEntity *entity,
const QString &objectNamePrefix )
481 QVector<Qgs3DExportObject *> objects;
482 const QList<Qt3DQGeometry *> geometriesList = entity->findChildren<
Qt3DQGeometry *>();
485 Qt3DQAttribute *positionAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
487 if ( !positionAttribute || !indexAttribute )
489 QgsDebugError( QString(
"Cannot export '%1' - geometry has no position or index attribute!" ).arg( objectNamePrefix ) );
493 const QByteArray vertexBytes = positionAttribute->buffer()->data();
494 const QByteArray indexBytes = indexAttribute->buffer()->data();
495 if ( vertexBytes.isNull() || indexBytes.isNull() )
497 QgsDebugError( QString(
"Geometry for '%1' has position or index attribute with empty data!" ).arg( objectNamePrefix ) );
501 const QVector<float> positionData = getAttributeData<float>( positionAttribute, vertexBytes );
502 const QVector<uint> indexData =
getIndexData( indexAttribute, indexBytes );
505 if ( !instanceDataAttribute )
507 QgsDebugError( QString(
"Cannot export '%1' - geometry has no instanceData attribute!" ).arg( objectNamePrefix ) );
510 const QByteArray instancePositionBytes =
getData( instanceDataAttribute->buffer() );
511 if ( instancePositionBytes.isNull() )
513 QgsDebugError( QString(
"Geometry for '%1' has instanceData attribute with empty data!" ).arg( objectNamePrefix ) );
516 QVector<float> instancePosition = getAttributeData<float>( instanceDataAttribute, instancePositionBytes );
518 for (
int i = 0; i < instancePosition.size(); i += 3 )
521 objects.push_back(
object );
522 QMatrix4x4 instanceTransform;
523 instanceTransform.translate( instancePosition[i], instancePosition[i + 1], instancePosition[i + 2] );
524 object->setupPositionCoordinates( positionData, instanceTransform );
525 object->setupFaces( indexData );
527 object->setSmoothEdges( mSmoothEdges );
529 Qt3DQAttribute *normalsAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultNormalAttributeName(), Qt3DQAttribute::VertexAttribute );
530 if ( mExportNormals && normalsAttribute )
533 const QVector<float> normalsData = getAttributeData<float>( normalsAttribute, vertexBytes );
534 object->setupNormalCoordinates( normalsData, instanceTransform );
542QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processSceneLoaderGeometries( Qt3DRender::QSceneLoader *sceneLoader,
const QString &objectNamePrefix )
544 QVector<Qgs3DExportObject *> objects;
545 Qt3DCore::QEntity *sceneLoaderParent = qobject_cast<Qt3DCore::QEntity *>( sceneLoader->parent() );
546 Qt3DCore::QTransform *entityTransform = findTypedComponent<Qt3DCore::QTransform>( sceneLoaderParent );
547 QMatrix4x4 sceneTransform;
548 if ( entityTransform )
550 sceneTransform = entityTransform->matrix();
552 QStringList entityNames = sceneLoader->entityNames();
553 for (
const QString &entityName : entityNames )
555 Qt3DRender::QGeometryRenderer *mesh = qobject_cast<Qt3DRender::QGeometryRenderer *>( sceneLoader->component( entityName, Qt3DRender::QSceneLoader::GeometryRendererComponent ) );
556 Qgs3DExportObject *
object = processGeometryRenderer( mesh, objectNamePrefix, sceneTransform );
559 objects.push_back(
object );
564Qgs3DExportObject *Qgs3DSceneExporter::processGeometryRenderer( Qt3DRender::QGeometryRenderer *geomRenderer,
const QString &objectNamePrefix,
const QMatrix4x4 &sceneTransform )
567 if ( geomRenderer->primitiveType() != Qt3DRender::QGeometryRenderer::Triangles )
582 QVector<std::pair<uint, uint>> triangleIndexStartingIndiceToKeep;
586 QVector<QgsFeatureId> featureIds = tessGeom->
featureIds();
588 QSet<QgsFeatureId> tempFeatToAdd;
591 for (
int idx = 0; idx < featureIds.size(); idx++ )
594 if ( ! mExportedFeatureIds.contains( feat ) )
597 tempFeatToAdd += feat;
600 const uint startIdx = triangleIndex[idx] * 3;
601 const uint endIdx = idx < triangleIndex.size() - 1 ? triangleIndex[idx + 1] * 3 : std::numeric_limits<uint>::max();
603 if ( startIdx < endIdx )
604 triangleIndexStartingIndiceToKeep.append( std::pair<uint, uint>( startIdx, endIdx ) );
607 mExportedFeatureIds += tempFeatToAdd;
609 if ( triangleIndexStartingIndiceToKeep.isEmpty() )
616 QMatrix4x4 transformMatrix = sceneTransform;
617 QObject *parent = geomRenderer->parent();
620 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( parent );
621 Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( entity );
624 transformMatrix = transform->matrix() * transformMatrix;
626 parent = parent->parent();
631 QByteArray indexBytes, vertexBytes;
632 QVector<uint> indexDataTmp;
633 QVector<uint> indexData;
634 QVector<float> positionData;
637 positionAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
638 if ( !positionAttribute )
640 QgsDebugError( QString(
"Cannot export '%1' - geometry has no position attribute!" ).arg( objectNamePrefix ) );
644 vertexBytes =
getData( positionAttribute->buffer() );
645 if ( vertexBytes.isNull() )
647 QgsDebugError( QString(
"Will not export '%1' as geometry has empty position data!" ).arg( objectNamePrefix ) );
651 positionData = getAttributeData<float>( positionAttribute, vertexBytes );
654 QVector<Qt3DQAttribute *> attributes = geometry->attributes();
657 if ( attribute->attributeType() == Qt3DQAttribute::IndexAttribute )
659 indexAttribute = attribute;
660 indexBytes =
getData( indexAttribute->buffer() );
661 if ( indexBytes.isNull() )
663 QgsDebugError( QString(
"Geometry for '%1' has index attribute with empty data!" ).arg( objectNamePrefix ) );
667 indexDataTmp =
getIndexData( indexAttribute, indexBytes );
674 if ( !indexAttribute )
676 for ( uint i = 0; i < static_cast<uint>( positionData.size() / 3 ); ++i )
678 indexDataTmp.push_back( i );
683 if ( triangleIndexStartingIndiceToKeep.isEmpty() )
686 indexData.append( indexDataTmp );
692 const int triangleIndexStartingIndiceToKeepSize = triangleIndexStartingIndiceToKeep.size();
693 const uint indexDataTmpSize =
static_cast<uint
>( indexDataTmp.size() );
694 for ( uint i = 0; i < indexDataTmpSize; ++i )
696 uint idx = indexDataTmp[
static_cast<int>( i )];
698 while ( intervalIdx < triangleIndexStartingIndiceToKeepSize
699 && idx > triangleIndexStartingIndiceToKeep[intervalIdx].first
700 && idx >= triangleIndexStartingIndiceToKeep[intervalIdx].second )
706 if ( intervalIdx < triangleIndexStartingIndiceToKeepSize
707 && idx >= triangleIndexStartingIndiceToKeep[intervalIdx].first
708 && idx < triangleIndexStartingIndiceToKeep[intervalIdx].second )
710 indexData.push_back( idx );
717 object->setupPositionCoordinates( positionData, transformMatrix );
718 object->setupFaces( indexData );
720 Qt3DQAttribute *normalsAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultNormalAttributeName(), Qt3DQAttribute::VertexAttribute );
721 if ( mExportNormals && normalsAttribute )
724 const QVector<float> normalsData = getAttributeData<float>( normalsAttribute, vertexBytes );
725 object->setupNormalCoordinates( normalsData, transformMatrix );
728 Qt3DQAttribute *texCoordsAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultTextureCoordinateAttributeName(), Qt3DQAttribute::VertexAttribute );
729 if ( mExportTextures && texCoordsAttribute )
732 const QVector<float> texCoordsData = getAttributeData<float>( texCoordsAttribute, vertexBytes );
733 object->setupTextureCoordinates( texCoordsData );
739QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processLines( Qt3DCore::QEntity *entity,
const QString &objectNamePrefix )
741 QVector<Qgs3DExportObject *> objs;
742 const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
743 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
745 if ( renderer->primitiveType() != Qt3DRender::QGeometryRenderer::LineStripAdjacency )
continue;
747 Qt3DQAttribute *positionAttribute =
findAttribute( geom, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
749 if ( !positionAttribute || !indexAttribute )
751 QgsDebugError( QString(
"Cannot export '%1' - geometry has no position or index attribute!" ).arg( objectNamePrefix ) );
755 const QByteArray vertexBytes =
getData( positionAttribute->buffer() );
756 const QByteArray indexBytes =
getData( indexAttribute->buffer() );
757 if ( vertexBytes.isNull() || indexBytes.isNull() )
759 QgsDebugError( QString(
"Geometry for '%1' has position or index attribute with empty data!" ).arg( objectNamePrefix ) );
762 const QVector<float> positionData = getAttributeData<float>( positionAttribute, vertexBytes );
763 const QVector<uint> indexData =
getIndexData( indexAttribute, indexBytes );
770 objs.push_back( exportObject );
775Qgs3DExportObject *Qgs3DSceneExporter::processPoints( Qt3DCore::QEntity *entity,
const QString &objectNamePrefix )
777 QVector<float> points;
778 const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
779 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
781 Qt3DQGeometry *geometry = qobject_cast<QgsBillboardGeometry *>( renderer->geometry() );
784 Qt3DQAttribute *positionAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
785 if ( !positionAttribute )
787 QgsDebugError( QString(
"Cannot export '%1' - geometry has no position attribute!" ).arg( objectNamePrefix ) );
790 const QByteArray positionBytes =
getData( positionAttribute->buffer() );
791 if ( positionBytes.isNull() )
793 QgsDebugError( QString(
"Geometry for '%1' has position attribute with empty data!" ).arg( objectNamePrefix ) );
796 const QVector<float> positions = getAttributeData<float>( positionAttribute, positionBytes );
807 const QString objFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral(
".obj" ) );
808 const QString mtlFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral(
".mtl" ) );
810 QFile file( objFilePath );
811 if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
813 QgsDebugError( QStringLiteral(
"Scene can not be exported to '%1'. File access error." ).arg( objFilePath ) );
816 QFile mtlFile( mtlFilePath );
817 if ( !mtlFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
819 QgsDebugError( QStringLiteral(
"Scene can not be exported to '%1'. File access error." ).arg( mtlFilePath ) );
823 float maxfloat = std::numeric_limits<float>::max(), minFloat = std::numeric_limits<float>::lowest();
824 float minX = maxfloat, minY = maxfloat, minZ = maxfloat, maxX = minFloat, maxY = minFloat, maxZ = minFloat;
827 obj->
objectBounds( minX, minY, minZ, maxX, maxY, maxZ );
830 float diffX = 1.0f, diffY = 1.0f, diffZ = 1.0f;
835 const float centerX = ( minX + maxX ) / 2.0f;
836 const float centerY = ( minY + maxY ) / 2.0f;
837 const float centerZ = ( minZ + maxZ ) / 2.0f;
839 const float scale = std::max( diffX, std::max( diffY, diffZ ) );
841 QTextStream out( &file );
843 const QString mtlLibName = sceneName +
".mtl";
844 out <<
"mtllib " << mtlLibName <<
"\n";
846 QTextStream mtlOut( &mtlFile );
852 const QString material = obj->
saveMaterial( mtlOut, sceneFolderPath );
853 out <<
"o " << obj->
name() <<
"\n";
854 if ( material != QString() )
855 out <<
"usemtl " << material <<
"\n";
859 QgsDebugMsgLevel( QStringLiteral(
"Scene exported to '%1'" ).arg( objFilePath ), 2 );
862QString Qgs3DSceneExporter::getObjectName(
const QString &name )
865 if ( usedObjectNamesCounter.contains( name ) )
867 ret = QStringLiteral(
"%1%2" ).arg( name ).arg( usedObjectNamesCounter[name] );
868 usedObjectNamesCounter[name]++;
871 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)