19#include <Qt3DCore/QEntity>
20#include <Qt3DCore/QComponent>
21#include <Qt3DCore/QNode>
23#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
24#include <Qt3DRender/QAttribute>
25#include <Qt3DRender/QBuffer>
26#include <Qt3DRender/QGeometry>
32#include <Qt3DCore/QAttribute>
33#include <Qt3DCore/QBuffer>
34#include <Qt3DCore/QGeometry>
41#include <Qt3DRender/QGeometryRenderer>
42#include <Qt3DExtras/QPlaneGeometry>
43#include <Qt3DCore/QTransform>
44#include <Qt3DRender/QMaterial>
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"
91 const uint bytesOffset = attribute->byteOffset();
92 const uint bytesStride = attribute->byteStride();
93 const uint vertexSize = attribute->vertexSize();
94 const uint dataSize =
static_cast<uint
>( data.size() );
97 if ( bytesStride == 0 )
99 QgsDebugError(
"bytesStride==0, the attribute probably was not set properly" );
103 const char *pData = data.constData();
104 for (
unsigned int i = bytesOffset; i < dataSize; i += bytesStride )
106 for (
unsigned int j = 0; j < vertexSize *
sizeof( T ); j +=
sizeof( T ) )
109 memcpy( &v, pData + i + j,
sizeof( T ) );
110 result.push_back( v );
119 QVector<uint> result;
120 const char *pData = data.constData();
121 for (
int i = 0; i < data.size(); i +=
sizeof( T ) )
124 memcpy( &v, pData + i,
sizeof( T ) );
125 result.push_back( ( uint ) v );
132 switch ( indexAttribute->vertexBaseType() )
134 case Qt3DQAttribute::VertexBaseType::Int:
135 return _getIndexDataImplementation<int>( data );
136 case Qt3DQAttribute::VertexBaseType::UnsignedInt:
137 return _getIndexDataImplementation<uint>( data );
138 case Qt3DQAttribute::VertexBaseType::Short:
139 return _getIndexDataImplementation<short>( data );
140 case Qt3DQAttribute::VertexBaseType::UnsignedShort:
141 return _getIndexDataImplementation<ushort>( data );
142 case Qt3DQAttribute::VertexBaseType::Byte:
143 return _getIndexDataImplementation<char>( data );
144 case Qt3DQAttribute::VertexBaseType::UnsignedByte:
145 return _getIndexDataImplementation<uchar>( data );
147 QgsDebugError(
"Probably trying to get index data using an attribute that has vertex data" );
150 return QVector<uint>();
155 QByteArray bytes = buffer->data();
156 if ( bytes.isNull() )
167 if ( attribute->attributeType() != type )
continue;
168 if ( attribute->name() == name )
return attribute;
173template<
typename Component>
176 if ( entity ==
nullptr )
return nullptr;
177 for ( Qt3DCore::QComponent *component : entity->components() )
179 Component *typedComponent = qobject_cast<Component *>( component );
180 if ( typedComponent !=
nullptr )
181 return typedComponent;
189 const QString rendererType = abstractRenderer->
type();
191 if ( rendererType ==
"rulebased" )
193 int prevSize = mObjects.size();
195 const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
196 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
198 Qt3DCore::QEntity *parentEntity = qobject_cast<Qt3DCore::QEntity *>( renderer->parent() );
201 Qgs3DExportObject *
object = processGeometryRenderer( renderer, layer->
name() + QStringLiteral(
"_" ) );
202 if (
object ==
nullptr )
204 if ( mExportTextures )
205 processEntityMaterial( parentEntity,
object );
206 mObjects.push_back(
object );
208 return mObjects.size() > prevSize;
211 else if ( rendererType ==
"vector" )
214 if ( vectorLayerRenderer )
226 QgsDebugMsgLevel( QStringLiteral(
"Type '%1' of layer '%2' is not exportable." ).arg( layer->
name() ).arg( rendererType ), 2 );
233void Qgs3DSceneExporter::processEntityMaterial( Qt3DCore::QEntity *entity,
Qgs3DExportObject *
object )
235 Qt3DExtras::QPhongMaterial *phongMaterial = findTypedComponent<Qt3DExtras::QPhongMaterial>( entity );
239 object->setupMaterial( &material );
242 Qt3DExtras::QDiffuseSpecularMaterial *diffuseMapMaterial = findTypedComponent<Qt3DExtras::QDiffuseSpecularMaterial>( entity );
243 if ( diffuseMapMaterial )
245 const Qt3DRender::QTexture2D *diffuseTexture = diffuseMapMaterial->diffuse().value< Qt3DRender::QTexture2D * >();
246 if ( diffuseTexture )
248 const QVector<Qt3DRender::QAbstractTextureImage *> textureImages = diffuseTexture->textureImages();
249 for (
const Qt3DRender::QAbstractTextureImage *tex : textureImages )
254 const QImage image = imageTexture->
getImage();
255 object->setTextureImage( image );
269 QgsChunkNode *node = terrain->rootNode();
274 QgsTerrainTileEntity *terrainTile =
nullptr;
275 QgsTerrainTextureGenerator *textureGenerator = terrain->textureGenerator();
276 textureGenerator->waitForFinished();
277 const QSize oldResolution = textureGenerator->textureSize();
278 textureGenerator->setTextureSize( QSize( mTerrainTextureResolution, mTerrainTextureResolution ) );
279 switch ( generator->
type() )
282 terrainTile = getDemTerrainEntity( terrain, node );
283 parseDemTile( terrainTile, layerName + QStringLiteral(
"_" ) );
286 terrainTile = getFlatTerrainEntity( terrain, node );
287 parseFlatTile( terrainTile, layerName + QStringLiteral(
"_" ) );
291 terrainTile = getMeshTerrainEntity( terrain, node );
292 parseMeshTile( terrainTile, layerName + QStringLiteral(
"_" ) );
297 textureGenerator->setTextureSize( oldResolution );
300QgsTerrainTileEntity *Qgs3DSceneExporter::getFlatTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
303 FlatTerrainChunkLoader *flatTerrainLoader = qobject_cast<FlatTerrainChunkLoader *>( generator->
createChunkLoader( node ) );
304 if ( mExportTextures )
305 terrain->textureGenerator()->waitForFinished();
307 Qt3DCore::QEntity *entity = flatTerrainLoader->createEntity(
this );
308 QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
312QgsTerrainTileEntity *Qgs3DSceneExporter::getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
318 QgsDemTerrainTileLoader *loader = qobject_cast<QgsDemTerrainTileLoader *>( generator->
createChunkLoader( node ) );
320 if ( mExportTextures )
321 terrain->textureGenerator()->waitForFinished();
322 QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity(
this ) );
327QgsTerrainTileEntity *Qgs3DSceneExporter::getMeshTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
329 QgsMeshTerrainGenerator *generator =
dynamic_cast<QgsMeshTerrainGenerator *
>( terrain->map3D().terrainGenerator() );
330 QgsMeshTerrainTileLoader *loader = qobject_cast<QgsMeshTerrainTileLoader *>( generator->createChunkLoader( node ) );
332 QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity(
this ) );
336void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity,
const QString &layerName )
338 Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
339 Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
342 Qt3DExtras::QPlaneGeometry *tileGeometry = qobject_cast<Qt3DExtras::QPlaneGeometry *>( geometry );
343 if ( tileGeometry ==
nullptr )
345 QgsDebugError(
"Qt3DExtras::QPlaneGeometry* is expected but something else was given" );
349 const float scale = transform->scale();
350 const QVector3D translation = transform->translation();
353 Qt3DQAttribute *positionAttribute = tileGeometry->positionAttribute();
354 const QByteArray verticesBytes =
getData( positionAttribute->buffer() );
355 const QVector<float> positionBuffer = getAttributeData<float>( positionAttribute, verticesBytes );
359 const QByteArray indexBytes =
getData( indexAttribute->buffer() );
360 const QVector<uint> indexesBuffer =
getIndexData( indexAttribute, indexBytes );
362 QString objectNamePrefix = layerName;
363 if ( objectNamePrefix != QString() ) objectNamePrefix += QString();
366 mObjects.push_back(
object );
368 object->setSmoothEdges( mSmoothEdges );
369 object->setupPositionCoordinates( positionBuffer,
scale, translation );
370 object->setupFaces( indexesBuffer );
372 if ( mExportNormals )
375 QVector<float> normalsBuffer;
376 for (
int i = 0; i < positionBuffer.size(); i += 3 ) normalsBuffer << 0.0f << 1.0f << 0.0f;
377 object->setupNormalCoordinates( normalsBuffer );
380 Qt3DQAttribute *texCoordsAttribute = tileGeometry->texCoordAttribute();
381 if ( mExportTextures && texCoordsAttribute !=
nullptr )
384 const QVector<float> texCoords = getAttributeData<float>( texCoordsAttribute, verticesBytes );
385 object->setupTextureCoordinates( texCoords );
387 QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
388 const QImage img = textureImage->getImage();
389 object->setTextureImage( img );
393void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity,
const QString &layerName )
395 Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
396 Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
399 DemTerrainTileGeometry *tileGeometry = qobject_cast<DemTerrainTileGeometry *>( geometry );
400 if ( tileGeometry ==
nullptr )
402 QgsDebugError(
"DemTerrainTileGeometry* is expected but something else was given" );
406 const float scale = transform->scale();
407 const QVector3D translation = transform->translation();
409 Qt3DQAttribute *positionAttribute = tileGeometry->positionAttribute();
410 const QByteArray positionBytes = positionAttribute->buffer()->data();
411 const QVector<float> positionBuffer = getAttributeData<float>( positionAttribute, positionBytes );
414 const QByteArray indexBytes = indexAttribute->buffer()->data();
415 const QVector<unsigned int> indexBuffer =
getIndexData( indexAttribute, indexBytes );
418 mObjects.push_back(
object );
420 object->setSmoothEdges( mSmoothEdges );
421 object->setupPositionCoordinates( positionBuffer,
scale, translation );
422 object->setupFaces( indexBuffer );
424 Qt3DQAttribute *normalsAttributes = tileGeometry->normalAttribute();
425 if ( mExportNormals && normalsAttributes !=
nullptr )
427 const QByteArray normalsBytes = normalsAttributes->buffer()->data();
428 const QVector<float> normalsBuffer = getAttributeData<float>( normalsAttributes, normalsBytes );
429 object->setupNormalCoordinates( normalsBuffer );
432 Qt3DQAttribute *texCoordsAttribute = tileGeometry->texCoordsAttribute();
433 if ( mExportTextures && texCoordsAttribute !=
nullptr )
435 const QByteArray texCoordsBytes = texCoordsAttribute->buffer()->data();
436 const QVector<float> texCoordsBuffer = getAttributeData<float>( texCoordsAttribute, texCoordsBytes );
437 object->setupTextureCoordinates( texCoordsBuffer );
439 QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
440 const QImage img = textureImage->getImage();
441 object->setTextureImage( img );
445void Qgs3DSceneExporter::parseMeshTile( QgsTerrainTileEntity *tileEntity,
const QString &layerName )
447 QString objectNamePrefix = layerName;
448 if ( objectNamePrefix != QString() ) objectNamePrefix += QStringLiteral(
"_" );
450 const QList<Qt3DRender::QGeometryRenderer *> renderers = tileEntity->findChildren<Qt3DRender::QGeometryRenderer *>();
451 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
454 if ( obj ==
nullptr )
continue;
459QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processInstancedPointGeometry( Qt3DCore::QEntity *entity,
const QString &objectNamePrefix )
461 QVector<Qgs3DExportObject *> objects;
462 const QList<Qt3DQGeometry *> geometriesList = entity->findChildren<
Qt3DQGeometry *>();
465 Qt3DQAttribute *positionAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
469 if ( attribute->attributeType() == Qt3DQAttribute::IndexAttribute )
470 indexAttribute = attribute;
472 if ( positionAttribute ==
nullptr || indexAttribute ==
nullptr )
474 const QByteArray vertexBytes =
getData( positionAttribute->buffer() );
475 const QByteArray indexBytes =
getData( indexAttribute->buffer() );
476 const QVector<float> positionData = getAttributeData<float>( positionAttribute, vertexBytes );
477 const QVector<uint> indexData =
getIndexData( indexAttribute, indexBytes );
480 const QByteArray instancePositionBytes =
getData( instanceDataAttribute->buffer() );
481 QVector<float> instancePosition = getAttributeData<float>( instanceDataAttribute, instancePositionBytes );
482 for (
int i = 0; i < instancePosition.size(); i += 3 )
485 objects.push_back(
object );
486 object->setupPositionCoordinates( positionData, 1.0f, QVector3D( instancePosition[i], instancePosition[i + 1], instancePosition[i + 2] ) );
487 object->setupFaces( indexData );
489 object->setSmoothEdges( mSmoothEdges );
491 Qt3DQAttribute *normalsAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultNormalAttributeName(), Qt3DQAttribute::VertexAttribute );
492 if ( mExportNormals && normalsAttribute !=
nullptr )
495 const QVector<float> normalsData = getAttributeData<float>( normalsAttribute, vertexBytes );
496 object->setupNormalCoordinates( normalsData );
503QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processSceneLoaderGeometries( Qt3DRender::QSceneLoader *sceneLoader,
const QString &objectNamePrefix )
505 QVector<Qgs3DExportObject *> objects;
506 Qt3DCore::QEntity *sceneLoaderParent = qobject_cast<Qt3DCore::QEntity *>( sceneLoader->parent() );
507 Qt3DCore::QTransform *entityTransform = findTypedComponent<Qt3DCore::QTransform>( sceneLoaderParent );
508 float sceneScale = 1.0f;
509 QVector3D sceneTranslation( 0.0f, 0.0f, 0.0f );
510 if ( entityTransform )
512 sceneScale = entityTransform->scale();
513 sceneTranslation = entityTransform->translation();
515 for (
const QString &entityName : sceneLoader->entityNames() )
517 Qt3DRender::QGeometryRenderer *mesh = qobject_cast<Qt3DRender::QGeometryRenderer *>( sceneLoader->component( entityName, Qt3DRender::QSceneLoader::GeometryRendererComponent ) );
518 Qgs3DExportObject *
object = processGeometryRenderer( mesh, objectNamePrefix, sceneScale, sceneTranslation );
521 objects.push_back(
object );
526Qgs3DExportObject *Qgs3DSceneExporter::processGeometryRenderer( Qt3DRender::QGeometryRenderer *geomRenderer,
const QString &objectNamePrefix,
float sceneScale, QVector3D sceneTranslation )
529 if ( geomRenderer->primitiveType() != Qt3DRender::QGeometryRenderer::Triangles )
542 QVector<std::pair<uint, uint>> triangleIndexStartingIndiceToKeep;
546 QVector<QgsFeatureId> featureIds = tessGeom->
featureIds();
548 std::sort( featureIds.begin(), featureIds.end() );
551 for (
int idx = 0; idx < featureIds.size(); idx++ )
554 if ( ! mExportedFeatureIds.contains( feat ) )
557 mExportedFeatureIds.insert( feat );
560 const uint startIdx = triangleIndex[idx];
561 const uint endIdx = idx < triangleIndex.size() - 1 ? triangleIndex[idx + 1] : std::numeric_limits<uint>::max();
563 triangleIndexStartingIndiceToKeep.append( std::pair<uint, uint>( startIdx, endIdx ) );
567 if ( triangleIndexStartingIndiceToKeep.isEmpty() )
574 QVector3D translation( 0.0f, 0.0f, 0.0f );
575 QObject *parent = geomRenderer->parent();
576 while ( parent !=
nullptr )
578 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( parent );
579 Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( entity );
580 if ( transform !=
nullptr )
582 scale *= transform->scale();
583 translation += transform->translation();
585 parent = parent->parent();
588 Qt3DQAttribute *positionAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
590 QByteArray indexBytes, vertexBytes;
591 QVector<uint> indexDataTmp;
592 QVector<uint> indexData;
593 QVector<float> positionData;
596 if ( attribute->attributeType() == Qt3DQAttribute::IndexAttribute )
597 indexAttribute = attribute;
600 if ( indexAttribute !=
nullptr )
602 indexBytes =
getData( indexAttribute->buffer() );
603 indexDataTmp =
getIndexData( indexAttribute, indexBytes );
606 if ( positionAttribute !=
nullptr )
608 vertexBytes =
getData( positionAttribute->buffer() );
609 positionData = getAttributeData<float>( positionAttribute, vertexBytes );
613 if ( positionAttribute !=
nullptr && indexAttribute ==
nullptr )
615 for ( uint i = 0; i < static_cast<uint>( positionData.size() / 3 ); ++i )
617 indexDataTmp.push_back( i );
621 if ( triangleIndexStartingIndiceToKeep.empty() )
623 indexData.append( indexDataTmp );
628 const int triangleIndexStartingIndiceToKeepSize = triangleIndexStartingIndiceToKeep.size();
629 const uint indexDataTmpSize =
static_cast<uint
>( indexDataTmp.size() );
630 for ( uint i = 0; i < indexDataTmpSize; ++i )
633 while ( intervalIdx < triangleIndexStartingIndiceToKeepSize
634 && i > triangleIndexStartingIndiceToKeep[intervalIdx].first * 3
635 && i >= triangleIndexStartingIndiceToKeep[intervalIdx].second * 3 )
641 if ( intervalIdx < triangleIndexStartingIndiceToKeepSize
642 && i >= triangleIndexStartingIndiceToKeep[intervalIdx].first * 3
643 && i < triangleIndexStartingIndiceToKeep[intervalIdx].second * 3 )
645 indexData.push_back( indexDataTmp[
static_cast<int>( i )] );
650 if ( positionAttribute ==
nullptr )
652 QgsDebugError(
"Geometry renderer with null data was being processed" );
657 object->setupPositionCoordinates( positionData,
scale * sceneScale, translation + sceneTranslation );
658 object->setupFaces( indexData );
660 Qt3DQAttribute *normalsAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultNormalAttributeName(), Qt3DQAttribute::VertexAttribute );
661 if ( mExportNormals && normalsAttribute !=
nullptr )
664 const QVector<float> normalsData = getAttributeData<float>( normalsAttribute, vertexBytes );
665 object->setupNormalCoordinates( normalsData );
668 Qt3DQAttribute *texCoordsAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultTextureCoordinateAttributeName(), Qt3DQAttribute::VertexAttribute );
669 if ( mExportTextures && texCoordsAttribute !=
nullptr )
672 const QVector<float> texCoordsData = getAttributeData<float>( texCoordsAttribute, vertexBytes );
673 object->setupTextureCoordinates( texCoordsData );
679QVector<Qgs3DExportObject *> Qgs3DSceneExporter::processLines( Qt3DCore::QEntity *entity,
const QString &objectNamePrefix )
681 QVector<Qgs3DExportObject *> objs;
682 const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
683 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
685 if ( renderer->primitiveType() != Qt3DRender::QGeometryRenderer::LineStripAdjacency )
continue;
687 Qt3DQAttribute *positionAttribute =
findAttribute( geom, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
691 if ( attribute->attributeType() == Qt3DQAttribute::IndexAttribute )
693 indexAttribute = attribute;
697 if ( positionAttribute ==
nullptr || indexAttribute ==
nullptr )
699 QgsDebugError(
"Position or index attribute was not found" );
703 const QByteArray vertexBytes =
getData( positionAttribute->buffer() );
704 const QByteArray indexBytes =
getData( indexAttribute->buffer() );
705 const QVector<float> positionData = getAttributeData<float>( positionAttribute, vertexBytes );
706 const QVector<uint> indexData =
getIndexData( indexAttribute, indexBytes );
713 objs.push_back( exportObject );
718Qgs3DExportObject *Qgs3DSceneExporter::processPoints( Qt3DCore::QEntity *entity,
const QString &objectNamePrefix )
720 QVector<float> points;
721 const QList<Qt3DRender::QGeometryRenderer *> renderers = entity->findChildren<Qt3DRender::QGeometryRenderer *>();
722 for ( Qt3DRender::QGeometryRenderer *renderer : renderers )
724 Qt3DQGeometry *geometry = qobject_cast<QgsBillboardGeometry *>( renderer->geometry() );
725 if ( geometry ==
nullptr )
727 Qt3DQAttribute *positionAttribute =
findAttribute( geometry, Qt3DQAttribute::defaultPositionAttributeName(), Qt3DQAttribute::VertexAttribute );
728 const QByteArray positionBytes =
getData( positionAttribute->buffer() );
729 if ( positionBytes.size() == 0 )
731 const QVector<float> positions = getAttributeData<float>( positionAttribute, positionBytes );
742 const QString objFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral(
".obj" ) );
743 const QString mtlFilePath = QDir( sceneFolderPath ).filePath( sceneName + QStringLiteral(
".mtl" ) );
745 QFile file( objFilePath );
746 if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
748 QgsDebugError( QStringLiteral(
"Scene can not be exported to '%1'. File access error." ).arg( objFilePath ) );
751 QFile mtlFile( mtlFilePath );
752 if ( !mtlFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
754 QgsDebugError( QStringLiteral(
"Scene can not be exported to '%1'. File access error." ).arg( mtlFilePath ) );
758 float maxfloat = std::numeric_limits<float>::max(), minFloat = std::numeric_limits<float>::lowest();
759 float minX = maxfloat, minY = maxfloat, minZ = maxfloat, maxX = minFloat, maxY = minFloat, maxZ = minFloat;
762 obj->
objectBounds( minX, minY, minZ, maxX, maxY, maxZ );
765 float diffX = 1.0f, diffY = 1.0f, diffZ = 1.0f;
770 const float centerX = ( minX + maxX ) / 2.0f;
771 const float centerY = ( minY + maxY ) / 2.0f;
772 const float centerZ = ( minZ + maxZ ) / 2.0f;
774 const float scale = std::max( diffX, std::max( diffY, diffZ ) );
776 QTextStream out( &file );
778 const QString mtlLibName = sceneName +
".mtl";
779 out <<
"mtllib " << mtlLibName <<
"\n";
781 QTextStream mtlOut( &mtlFile );
784 if ( obj ==
nullptr )
continue;
786 const QString material = obj->
saveMaterial( mtlOut, sceneFolderPath );
787 out <<
"o " << obj->
name() <<
"\n";
788 if ( material != QString() )
789 out <<
"usemtl " << material <<
"\n";
790 obj->
saveTo( out,
scale / mScale, QVector3D( centerX, centerY, centerZ ) );
793 QgsDebugMsgLevel( QStringLiteral(
"Scene exported to %1" ).arg( objFilePath ), 2 );
796QString Qgs3DSceneExporter::getObjectName(
const QString &name )
799 if ( usedObjectNamesCounter.contains( name ) )
801 ret = QStringLiteral(
"%1%2" ).arg( name ).arg( usedObjectNamesCounter[name] );
802 usedObjectNamesCounter[name]++;
805 usedObjectNamesCounter[name] = 2;
Manages the data of each object of the scene (positions, normals, texture coordinates ....
void saveTo(QTextStream &out, float scale, const QVector3D ¢er)
Saves the current object to the output stream while scaling the object and centering it to be visible...
void setType(ObjectType type)
Sets the object type.
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 setupPositionCoordinates(const QVector< float > &positionsBuffer, float scale=1.0f, const QVector3D &translation=QVector3D(0, 0, 0))
Sets positions coordinates and does the translation and scaling.
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 parseTerrain(QgsTerrainEntity *terrain, const QString &layer)
Creates terrain export objects from the terrain entity.
void save(const QString &sceneName, const QString &sceneFolderPath)
Saves the scene to a .obj file.
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.
@ 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
Qt3DCore::QGeometry Qt3DQGeometry
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)