Skip to content

Commit

Permalink
Created QgsExportObject to manage each object data (position coordina…
Browse files Browse the repository at this point in the history
…tes, textures, normals ...)

Fixed an issue with QgsDemHeightMapGenerator::renderSynchronously because it wasm't doing the same things as asynchronous rendering function
Switched to using just one tile for DEM terrain and using a resolution parameter to handle level of details
  • Loading branch information
NEDJIMAbelgacem committed Jul 4, 2020
1 parent 8a80bac commit 69017d4
Show file tree
Hide file tree
Showing 12 changed files with 729 additions and 145 deletions.
1 change: 1 addition & 0 deletions src/3d/CMakeLists.txt
Expand Up @@ -69,6 +69,7 @@ SET(QGIS_3D_SRCS
mesh/qgsmesh3dmaterial_p.cpp
mesh/qgsmeshterraingenerator.cpp
qgs3dsceneexporter.cpp
qgsexportobject.cpp
)

SET(QGIS_3D_HDRS
Expand Down
14 changes: 7 additions & 7 deletions src/3d/qgs3dmapexportsettings.h
@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
qgs3dmapexportsettings.h
--------------------------------------
Date : July 2020
Expand All @@ -25,20 +25,20 @@ class _3D_EXPORT Qgs3DMapExportSettings : public QObject
{
Q_OBJECT
public:
Qgs3DMapExportSettings(QObject* parent = nullptr);
Qgs3DMapExportSettings( QObject *parent = nullptr );
QString sceneName() const { return mSceneName; }
QString sceneFolderPath() const { return mSceneFolderPath; }
int levelOfDetails() const { return mLevelOfDetails; }
int terrrainResolution() const { return mTerrainResolution; }
bool smoothEdges() const { return mSmoothEdges; }

void setSceneName( const QString& sceneName ) { mSceneName = sceneName; }
void setSceneFolderPath( const QString& sceneFolderPath ) { mSceneFolderPath = sceneFolderPath; }
void setLevelOfDetails( int levelOfDetails ) { mLevelOfDetails = levelOfDetails; }
void setSceneName( const QString &sceneName ) { mSceneName = sceneName; }
void setSceneFolderPath( const QString &sceneFolderPath ) { mSceneFolderPath = sceneFolderPath; }
void setTerrainResolution( int resolution ) { mTerrainResolution = resolution; }
void setSmoothEdges( bool smoothEdges ) { mSmoothEdges = smoothEdges; }
private:
QString mSceneName;
QString mSceneFolderPath;
int mLevelOfDetails;
int mTerrainResolution;
bool mSmoothEdges;
};

Expand Down
45 changes: 45 additions & 0 deletions src/3d/qgs3dmapexportsettings.h.bom
@@ -0,0 +1,45 @@
/***************************************************************************
qgs3dmapexportsettings.h
--------------------------------------
Date : July 2020
Copyright : (C) 2020 by Belgacem Nedjima
Email : gb underscore nedjima at esi dot dz
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGS3DMAPEXPORTSETTINGS_H
#define QGS3DMAPEXPORTSETTINGS_H

#include "qgis_3d.h"

#include <QString>
#include <QObject>

class _3D_EXPORT Qgs3DMapExportSettings : public QObject
{
Q_OBJECT
public:
Qgs3DMapExportSettings(QObject* parent = nullptr);
QString sceneName() const { return mSceneName; }
QString sceneFolderPath() const { return mSceneFolderPath; }
int terrrainResolution() const { return mTerrainResolution; }
bool smoothEdges() const { return mSmoothEdges; }

void setSceneName( const QString& sceneName ) { mSceneName = sceneName; }
void setSceneFolderPath( const QString& sceneFolderPath ) { mSceneFolderPath = sceneFolderPath; }
void setTerrainResolution( int resolution ) { mTerrainResolution = resolution; }
void setSmoothEdges( bool smoothEdges ) { mSmoothEdges = smoothEdges; }
private:
QString mSceneName;
QString mSceneFolderPath;
int mTerrainResolution;
bool mSmoothEdges;
};

#endif // QGS3DMAPEXPORTSETTINGS_H
2 changes: 1 addition & 1 deletion src/3d/qgs3dmapscene.cpp
Expand Up @@ -771,7 +771,7 @@ void Qgs3DMapScene::exportScene( const Qgs3DMapExportSettings &exportSettings )
{
Qgs3DSceneExporter exporter;

exporter.setLevelOfDetails( exportSettings.levelOfDetails() );
exporter.setTerrainResolution( exportSettings.terrrainResolution() );
exporter.setSmoothEdges( exportSettings.smoothEdges() );

for ( QgsMapLayer *layer : mLayerEntities.keys() )
Expand Down
163 changes: 43 additions & 120 deletions src/3d/qgs3dsceneexporter.cpp
Expand Up @@ -40,6 +40,7 @@
#include "qgsdemterraingenerator.h"
#include "qgsdemterraintileloader_p.h"
#include "qgsdemterraintilegeometry_p.h"
#include "qgsexportobject.h"

#include <numeric>

Expand Down Expand Up @@ -80,7 +81,7 @@ QVector<unsigned int> getAttributeData<unsigned int>( Qt3DRender::QAttribute *at
// maybe a problem with indienness can happen?
unsigned int v;
char *vArr = ( char * )&v;
for ( int k = 0; k < sizeof( unsigned int ); ++k )
for ( int k = 0; k < ( int )sizeof( unsigned int ); ++k )
{
vArr[k] = data.at( i + k );
}
Expand All @@ -99,12 +100,8 @@ QVector<float> createPlaneVertexData( float w, float h, const QSize &resolution
Q_ASSERT( resolution.width() >= 2 );
Q_ASSERT( resolution.height() >= 2 );

const int nVerts = resolution.width() * resolution.height();

// Populate a buffer with the interleaved per-vertex data with
// vec3 pos, vec2 texCoord, vec3 normal, vec4 tangent
const quint32 elementSize = 3 + 2 + 3 + 4;
const quint32 stride = elementSize * sizeof( float );
QVector<float> data;

const float x0 = -w / 2.0f;
Expand Down Expand Up @@ -132,13 +129,13 @@ QVector<float> createPlaneVertexData( float w, float h, const QSize &resolution
return data;
}

QVector<int> createPlaneIndexData( const QSize &resolution )
QVector<unsigned int> createPlaneIndexData( const QSize &resolution )
{
// Create the index data. 2 triangles per rectangular face
const int faces = 2 * ( resolution.width() - 1 ) * ( resolution.height() - 1 );
const int indices = 3 * faces;
Q_ASSERT( indices < std::numeric_limits<quint16>::max() );
QVector<int> indexes;
QVector<unsigned int> indexes;

// Iterate over z
for ( int j = 0; j < resolution.height() - 1; ++j )
Expand All @@ -165,10 +162,8 @@ QVector<int> createPlaneIndexData( const QSize &resolution )

Qgs3DSceneExporter::Qgs3DSceneExporter( Qt3DCore::QNode *parent )
: Qt3DCore::QEntity( parent )
, mVertxPosition()
, mIndexes()
, mSmoothEdges( false )
, mLevelOfDetails( 1 )
, mTerrainResolution( 64 )
{

}
Expand Down Expand Up @@ -217,7 +212,8 @@ void Qgs3DSceneExporter::parseEntity( QgsTerrainEntity *terrain )
{
QgsChunkNode *root = terrain->rootNode();

int levelOfDetails = mLevelOfDetails;
// just use LoD0 for now
int levelOfDetails = 0;
QVector<QgsChunkNode *> leafs;
leafs << root;
for ( int i = 0; i < levelOfDetails; ++i )
Expand Down Expand Up @@ -279,15 +275,17 @@ QgsTerrainTileEntity *Qgs3DSceneExporter::getFlatTerrainEntity( QgsTerrainEntity
QgsTerrainTileEntity *Qgs3DSceneExporter::getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
{
QgsTerrainTileEntity *tileEntity = nullptr;
if ( node->entity() != nullptr )
{
// read tile data as displayed in the scene (no need to make the entity)
Qt3DCore::QEntity *entity = node->entity();
tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
}
else
// Just create a new tile (we don't need to export exact level of details as in the scene)

// if ( node->entity() != nullptr )
// {
// // read tile data as displayed in the scene (no need to make the entity)
// Qt3DCore::QEntity *entity = node->entity();
// tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
// }
// else
{
// create the entity synchronously and then it will be deleted once our scene exporter instance is deallocated
// create the entity synchronously and then it will be deleted once our scene exporter instance is deallocated
tileEntity = createDEMTileEntity( terrain, node );
}
return tileEntity;
Expand Down Expand Up @@ -319,10 +317,11 @@ QgsTerrainTileEntity *Qgs3DSceneExporter::createDEMTileEntity( QgsTerrainEntity
{
const Qgs3DMapSettings &map = terrain->map3D();
QgsDemTerrainGenerator *generator = static_cast<QgsDemTerrainGenerator *>( map.terrainGenerator() );
generator->setResolution( mTerrainResolution );
QgsDemHeightMapGenerator *heightMapGenerator = generator->heightMapGenerator();
float resolution = generator->resolution();
// heightMapGenerator->set
QByteArray heightMap = heightMapGenerator->renderSynchronously( node->tileX(), node->tileY(), node->tileZ() );

float resolution = generator->resolution();
float skirtHeight = generator->skirtHeight();

float zMin, zMax;
Expand Down Expand Up @@ -370,9 +369,9 @@ QgsTerrainTileEntity *Qgs3DSceneExporter::createDEMTileEntity( QgsTerrainEntity
return entity;
}


void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity )
{
qDebug() << "Parsing Terrain tile entity";
Qt3DRender::QGeometryRenderer *mesh = nullptr;
Qt3DCore::QTransform *transform = nullptr;
for ( Qt3DCore::QComponent *component : tileEntity->components() )
Expand Down Expand Up @@ -402,17 +401,13 @@ void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity )
QVector3D translation = transform->translation();

QVector<float> positionBuffer = createPlaneVertexData( scale, scale, tileGeometry->resolution() );
QVector<int> indexesBuffer = createPlaneIndexData( tileGeometry->resolution() );
QVector<unsigned int> indexesBuffer = createPlaneIndexData( tileGeometry->resolution() );

int startIndex = mVertxPosition.size() / 3 + 1;
for ( int i : indexesBuffer ) mIndexes << startIndex + i;
for ( int i = 0; i < positionBuffer.size(); i += 3 )
{
for ( int j = 0; j < 3; ++j )
{
mVertxPosition << positionBuffer[i + j] + translation[j];
}
}
QgsExportObject *object = new QgsExportObject( "Flat_tile", "", this );
mObjects.push_back( object );

object->setSmoothEdges( mSmoothEdges );
object->setupPositionCoordinates( positionBuffer, indexesBuffer, scale, translation );
}

void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity )
Expand Down Expand Up @@ -448,45 +443,22 @@ void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity )
QVector<float> positionBuffer = getAttributeData<float>( tileGeometry->positionAttribute() );
QVector<unsigned int> indexBuffer = getAttributeData<unsigned int>( tileGeometry->indexAttribute() );

QgsExportObject *object = new QgsExportObject( "DEM_tile", "", this );
mObjects.push_back( object );

int startIndex = mVertxPosition.size() / 3 + 1;
// TODO: delete vertices not just ignore them
QSet<int> ignoredVetices;
for ( int i = 0; i < positionBuffer.size(); i += 3 )
{
bool isIgnored = false;
for ( int j = 0; j < 3; ++j )
{
mVertxPosition << positionBuffer[i + j] * scale + translation[j];
// Vertices that have Y=0 are invalid and therefore any polygon that uses them shouldn't be contained in the model
if ( positionBuffer[i + j] == 0 ) isIgnored = true;
}
if ( isIgnored ) ignoredVetices.insert( i / 3 );
}

for ( int i = 0; i < indexBuffer.size(); i += 3 )
{
if ( ignoredVetices.contains( indexBuffer[i] ) ) continue;
if ( ignoredVetices.contains( indexBuffer[i + 1] ) ) continue;
if ( ignoredVetices.contains( indexBuffer[i + 2] ) ) continue;
mIndexes << startIndex + indexBuffer[i];
mIndexes << startIndex + indexBuffer[i + 1];
mIndexes << startIndex + indexBuffer[i + 2];
}
object->setSmoothEdges( mSmoothEdges );
object->setupPositionCoordinates( positionBuffer, indexBuffer, scale, translation );
}

void Qgs3DSceneExporter::processAttribute( Qt3DRender::QAttribute *attribute )
{
QVector<float> floatData = getAttributeData<float>( attribute );

int currentIndex = mIndexes.size() + 1;
QgsExportObject *object = new QgsExportObject( "attribute", "", this );
mObjects.push_back( object );

for ( int i = 0; i < floatData.size(); i += 3 )
{
mVertxPosition << floatData[i] << floatData[i + 1] << floatData[i + 2];
mIndexes << currentIndex;
++currentIndex;
}
mObjects.push_back( object );
object->setupPositionCoordinates( floatData );
}

void Qgs3DSceneExporter::process( QgsTessellatedPolygonGeometry *geom )
Expand All @@ -495,76 +467,27 @@ void Qgs3DSceneExporter::process( QgsTessellatedPolygonGeometry *geom )
processAttribute( geom->mPositionAttribute );
}

void Qgs3DSceneExporter::process( Qt3DExtras::QPlaneGeometry *geom )
{
for ( Qt3DRender::QAttribute *attribute : geom->attributes() )
{
if ( attribute->name() == Qt3DRender::QAttribute::defaultPositionAttributeName() )
{
qDebug() << "Processing plane gemetry attribute";
processAttribute( attribute );
}
}
}

void Qgs3DSceneExporter::saveToFile( const QString &filePath )
{
QFile file( filePath );
if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
return;

float maxX = std::numeric_limits<float>::min(), maxY = std::numeric_limits<float>::min(), maxZ = std::numeric_limits<float>::min();
float minX = std::numeric_limits<float>::max(), minY = std::numeric_limits<float>::max(), minZ = std::numeric_limits<float>::max();
for ( int i = 0; i < mVertxPosition.size(); i += 3 )
{
if ( mVertxPosition[i + 1] < 0 ) continue;
if ( mVertxPosition[i] > maxX ) maxX = mVertxPosition[i];
if ( mVertxPosition[i + 1] > maxY ) maxY = mVertxPosition[i + 1];
if ( mVertxPosition[i + 2] > maxZ ) maxZ = mVertxPosition[i + 2];
if ( mVertxPosition[i] < minX ) minX = mVertxPosition[i];
if ( mVertxPosition[i + 1] < minY ) minY = mVertxPosition[i + 1];
if ( mVertxPosition[i + 2] < minZ ) minZ = mVertxPosition[i + 2];
}
float maxfloat = std::numeric_limits<float>::max(), minFloat = std::numeric_limits<float>::lowest();
float minX = maxfloat, minY = maxfloat, minZ = maxfloat, maxX = minFloat, maxY = minFloat, maxZ = minFloat;
for ( QgsExportObject *obj : mObjects ) obj->objectBounds( minX, minY, minZ, maxX, maxY, maxZ );

float diffX = 1.0f, diffY = 1.0f, diffZ = 1.0f;
if ( mVertxPosition.size() >= 3 )
{
diffX = maxX - minX;
diffY = maxY - minY;
diffZ = maxZ - minZ;
}
diffX = maxX - minX;
diffY = maxY - minY;
diffZ = maxZ - minZ;

float centerX = ( minX + maxX ) / 2.0f;
float centerY = ( minY + maxY ) / 2.0f;
float centerZ = ( minZ + maxZ ) / 2.0f;

qDebug() << "Vertical span : " << diffY;

float scale = std::max( diffX, std::max( diffY, diffZ ) );
float scale = std::min( diffX, std::min( diffY, diffZ ) );

QTextStream out( &file );

QSet<int> ignored;

// Construct vertices
for ( int i = 0; i < mVertxPosition.size(); i += 3 )
{
// for now just ignore some vertex positions
if ( mVertxPosition[i + 1] < 0 ) ignored.insert( i / 3 );
out << "v ";
out << ( mVertxPosition[i] - centerX ) / scale << " ";
out << ( mVertxPosition[i + 1] - centerY ) / scale << " ";
out << ( mVertxPosition[i + 2] - centerZ ) / scale << "\n";
}

// smoothen edges
if ( mSmoothEdges ) out << "s on\n";
else out << "s off\n";

// Construct faces
for ( int i = 0; i < mIndexes.size(); i += 3 )
{
if ( ignored.contains( mIndexes[i] ) || ignored.contains( mIndexes[i + 1] ) || ignored.contains( mIndexes[i + 2] ) ) continue;
out << "f " << mIndexes[i] << " " << mIndexes[i + 1] << " " << mIndexes[i + 2] << "\n";
}
for ( QgsExportObject *obj : mObjects ) obj->saveTo( out, scale, QVector3D( centerX, centerY, centerZ ) );
}

0 comments on commit 69017d4

Please sign in to comment.