Skip to content
Permalink
Browse files

Created QgsExportObject to manage each object data (position coordina…

…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 69017d4628aeef50c68f449c0341817a483b5f69
@@ -69,6 +69,7 @@ SET(QGIS_3D_SRCS
mesh/qgsmesh3dmaterial_p.cpp
mesh/qgsmeshterraingenerator.cpp
qgs3dsceneexporter.cpp
qgsexportobject.cpp
)

SET(QGIS_3D_HDRS
@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
qgs3dmapexportsettings.h
--------------------------------------
Date : July 2020
@@ -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;
};

@@ -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
@@ -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() )
@@ -40,6 +40,7 @@
#include "qgsdemterraingenerator.h"
#include "qgsdemterraintileloader_p.h"
#include "qgsdemterraintilegeometry_p.h"
#include "qgsexportobject.h"

#include <numeric>

@@ -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 );
}
@@ -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;
@@ -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 )
@@ -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 )
{

}
@@ -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 )
@@ -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;
@@ -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;
@@ -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() )
@@ -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 )
@@ -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 )
@@ -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.
You can’t perform that action at this time.