Skip to content

Commit

Permalink
[FEATURE] support 3d models
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterPetrik authored and wonder-sk committed Sep 15, 2017
1 parent e83ce54 commit 7d3cf22
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 147 deletions.
7 changes: 6 additions & 1 deletion src/3d/abstract3dsymbol.cpp
@@ -1,4 +1,5 @@
#include "abstract3dsymbol.h"
#include "qgsreadwritecontext.h"

#include "qgsxmlutils.h"

Expand Down Expand Up @@ -70,8 +71,11 @@ void Point3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteContext &cont
material.writeXml( elemMaterial );
elem.appendChild( elemMaterial );

QVariantMap shapePropertiesCopy(shapeProperties);
shapePropertiesCopy["model"] = QVariant(context.pathResolver().writePath(shapePropertiesCopy["model"].toString()));

QDomElement elemShapeProperties = doc.createElement( "shape-properties" );
elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapeProperties, doc ) );
elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapePropertiesCopy, doc ) );
elem.appendChild( elemShapeProperties );

QDomElement elemTransform = doc.createElement( "transform" );
Expand All @@ -88,6 +92,7 @@ void Point3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext

QDomElement elemShapeProperties = elem.firstChildElement( "shape-properties" );
shapeProperties = QgsXmlUtils::readVariant( elemShapeProperties.firstChildElement() ).toMap();
shapeProperties["model"] = QVariant(context.pathResolver().readPath(shapeProperties["model"].toString()));

QDomElement elemTransform = elem.firstChildElement( "transform" );
transform = Utils::stringToMatrix4x4( elemTransform.attribute( "matrix" ) );
Expand Down
143 changes: 109 additions & 34 deletions src/3d/pointentity.cpp
Expand Up @@ -13,6 +13,11 @@
#include <Qt3DExtras/QPlaneGeometry>
#include <Qt3DExtras/QSphereGeometry>
#include <Qt3DExtras/QTorusGeometry>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DRender/QSceneLoader>

#include <Qt3DRender/QMesh>

#if QT_VERSION >= 0x050900
#include <Qt3DExtras/QExtrudedTextGeometry>
#endif
Expand All @@ -26,17 +31,24 @@

#include "qgsvectorlayer.h"
#include "qgspoint.h"

#include "utils.h"


PointEntity::PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, Qt3DCore::QNode *parent )
: Qt3DCore::QEntity( parent )
{
addEntityForSelectedPoints( map, layer, symbol );
addEntityForNotSelectedPoints( map, layer, symbol );
if ( symbol.shapeProperties["shape"].toString() == "model" ) {
Model3DPointEntityFactory::addEntitiesForSelectedPoints(map, layer, symbol, this);
Model3DPointEntityFactory::addEntitiesForNotSelectedPoints(map, layer, symbol, this);
} else {
InstancedPointEntityFactory::addEntityForNotSelectedPoints(map, layer, symbol, this);
InstancedPointEntityFactory::addEntityForSelectedPoints(map, layer, symbol, this);
}
}

Qt3DRender::QMaterial *PointEntity::material( const Point3DSymbol &symbol ) const
//* INSTANCED RENDERING *//

Qt3DRender::QMaterial *InstancedPointEntityFactory::material( const Point3DSymbol &symbol )
{
Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
filterKey->setName( "renderingStyle" );
Expand Down Expand Up @@ -105,7 +117,7 @@ Qt3DRender::QMaterial *PointEntity::material( const Point3DSymbol &symbol ) cons
return material;
}

void PointEntity::addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol )
void InstancedPointEntityFactory::addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
{
// build the default material
Qt3DRender::QMaterial *mat = material( symbol );
Expand All @@ -125,12 +137,12 @@ void PointEntity::addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *
req.setFilterFids( layer->selectedFeatureIds() );

// build the entity
PointEntityNode *entity = new PointEntityNode( map, layer, symbol, req );
InstancedPointEntityNode *entity = new InstancedPointEntityNode( map, layer, symbol, req );
entity->addComponent( mat );
entity->setParent( this );
entity->setParent( parent );
}

void PointEntity::addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol )
void InstancedPointEntityFactory::addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
{
// build the default material
Qt3DRender::QMaterial *mat = material( symbol );
Expand All @@ -144,19 +156,19 @@ void PointEntity::addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLaye
req.setFilterFids( notSelected );

// build the entity
PointEntityNode *entity = new PointEntityNode( map, layer, symbol, req );
InstancedPointEntityNode *entity = new InstancedPointEntityNode( map, layer, symbol, req );
entity->addComponent( mat );
entity->setParent( this );
entity->setParent( parent );
}

PointEntityNode::PointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent )
InstancedPointEntityNode::InstancedPointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent )
: Qt3DCore::QEntity( parent )
{
QList<QVector3D> pos = positions( map, layer, req );
QList<QVector3D> pos = Utils::positions( map, layer, req );
addComponent( renderer( symbol, pos ) );
}

Qt3DRender::QGeometryRenderer *PointEntityNode::renderer( const Point3DSymbol &symbol, const QList<QVector3D> &positions ) const
Qt3DRender::QGeometryRenderer *InstancedPointEntityNode::renderer( const Point3DSymbol &symbol, const QList<QVector3D> &positions ) const
{
int count = positions.count();

Expand Down Expand Up @@ -263,28 +275,91 @@ Qt3DRender::QGeometryRenderer *PointEntityNode::renderer( const Point3DSymbol &s
return renderer;
}

QList<QVector3D> PointEntityNode::positions( const Map3D &map, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) const
//* 3D MODEL RENDERING *//

static Qt3DExtras::QPhongMaterial* phongMaterial(const Point3DSymbol &symbol) {
Qt3DExtras::QPhongMaterial* phong = new Qt3DExtras::QPhongMaterial;

phong->setAmbient(symbol.material.ambient());
phong->setDiffuse(symbol.material.diffuse());
phong->setSpecular(symbol.material.specular());
phong->setShininess(symbol.material.shininess());

return phong;
}

void Model3DPointEntityFactory::addEntitiesForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
{
QList<QVector3D> positions;
QgsFeature f;
QgsFeatureIterator fi = layer->getFeatures( request );
while ( fi.nextFeature( f ) )
{
if ( f.geometry().isNull() )
continue;

QgsAbstractGeometry *g = f.geometry().geometry();
if ( QgsWkbTypes::flatType( g->wkbType() ) == QgsWkbTypes::Point )
{
QgsPoint *pt = static_cast<QgsPoint *>( g );
// TODO: use Z coordinates if the point is 3D
float h = map.terrainGenerator()->heightAt( pt->x(), pt->y(), map ) * map.terrainVerticalScale();
positions.append( QVector3D( pt->x() - map.originX, h, -( pt->y() - map.originY ) ) );
//qDebug() << positions.last();
}
else
qDebug() << "not a point";
QgsFeatureRequest req;
req.setDestinationCrs( map.crs );
req.setFilterFids( layer->selectedFeatureIds() );

addMeshEntities(map, layer, req, symbol, parent, true);
}



void Model3DPointEntityFactory::addEntitiesForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
{
// build the feature request to select features
QgsFeatureRequest req;
req.setDestinationCrs( map.crs );
QgsFeatureIds notSelected = layer->allFeatureIds();
notSelected.subtract( layer->selectedFeatureIds() );
req.setFilterFids( notSelected );

if (symbol.shapeProperties["overwriteMaterial"].toBool()) {
addMeshEntities(map, layer, req, symbol, parent, false);
} else {
addSceneEntities(map, layer, req, symbol, parent);
}
}

void Model3DPointEntityFactory::addSceneEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent) {
QList<QVector3D> positions = Utils::positions( map, layer, req );
Q_FOREACH(const QVector3D& position, positions) {
// build the entity
Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;

QUrl url = QUrl::fromLocalFile(symbol.shapeProperties["model"].toString());
Qt3DRender::QSceneLoader * modelLoader = new Qt3DRender::QSceneLoader;
modelLoader->setSource(url);

entity->addComponent( modelLoader );
entity->addComponent(transform(position, symbol));
entity->setParent( parent );
}
}

void Model3DPointEntityFactory::addMeshEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent, bool are_selected) {
// build the default material
Qt3DExtras::QPhongMaterial *mat = phongMaterial(symbol);

if (are_selected) {
mat->setDiffuse(map.selectionColor());
mat->setAmbient(map.selectionColor().darker());
}

// get nodes
QList<QVector3D> positions = Utils::positions( map, layer, req );
Q_FOREACH(const QVector3D& position, positions) {
// build the entity
Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;

QUrl url = QUrl::fromLocalFile(symbol.shapeProperties["model"].toString());
Qt3DRender::QMesh * mesh = new Qt3DRender::QMesh;
mesh->setSource(url);

entity->addComponent( mesh );
entity->addComponent( mat );
entity->addComponent(transform(position, symbol));
entity->setParent( parent );
}
}

return positions;
Qt3DCore::QTransform* Model3DPointEntityFactory::transform(const QVector3D& position, const Point3DSymbol &symbol) {
Qt3DCore::QTransform* tr = new Qt3DCore::QTransform;
tr->setMatrix(symbol.transform);
tr->setTranslation(position + tr->translation());
return tr;
}
31 changes: 24 additions & 7 deletions src/3d/pointentity.h
Expand Up @@ -4,6 +4,7 @@
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QMaterial>
#include <Qt3DRender/QGeometryRenderer>
#include <Qt3DCore/QTransform>

class Map3D;
class Point3DSymbol;
Expand All @@ -17,22 +18,38 @@ class PointEntity : public Qt3DCore::QEntity
{
public:
PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, Qt3DCore::QNode *parent = nullptr );
};

private:
void addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol );
void addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol );
class InstancedPointEntityFactory
{
public:
static void addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);
static void addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);

Qt3DRender::QMaterial *material( const Point3DSymbol &symbol ) const;
private:
static Qt3DRender::QMaterial *material( const Point3DSymbol &symbol);
};

class PointEntityNode : public Qt3DCore::QEntity
class InstancedPointEntityNode : public Qt3DCore::QEntity
{
public:
PointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent = nullptr );
InstancedPointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent = nullptr );

private:
Qt3DRender::QGeometryRenderer *renderer( const Point3DSymbol &symbol, const QList<QVector3D> &positions ) const;
QList<QVector3D> positions( const Map3D &map, const QgsVectorLayer *layer, const QgsFeatureRequest &req ) const;
};

class Model3DPointEntityFactory
{
public:
static void addEntitiesForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);
static void addEntitiesForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);

private:
static void addSceneEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent);
static void addMeshEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent, bool are_selected);

static Qt3DCore::QTransform* transform(const QVector3D& position, const Point3DSymbol &symbol);
};

#endif // POINTENTITY_H
30 changes: 30 additions & 0 deletions src/3d/utils.cpp
Expand Up @@ -2,6 +2,11 @@

#include "qgslinestring.h"
#include "qgspolygon.h"
#include "qgsfeaturerequest.h"
#include "qgsfeatureiterator.h"
#include "qgsfeature.h"
#include "qgsabstractgeometry.h"
#include "qgsvectorlayer.h"

#include "terraingenerator.h"

Expand Down Expand Up @@ -189,3 +194,28 @@ bool Utils::isCullable( const AABB &bbox, const QMatrix4x4 &viewProjectionMatrix
}
return out;
}

QList<QVector3D> Utils::positions(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &request) {
QList<QVector3D> positions;
QgsFeature f;
QgsFeatureIterator fi = layer->getFeatures( request );
while ( fi.nextFeature( f ) )
{
if ( f.geometry().isNull() )
continue;

QgsAbstractGeometry *g = f.geometry().geometry();
if ( QgsWkbTypes::flatType( g->wkbType() ) == QgsWkbTypes::Point )
{
QgsPoint *pt = static_cast<QgsPoint *>( g );
// TODO: use Z coordinates if the point is 3D
float h = map.terrainGenerator()->heightAt( pt->x(), pt->y(), map ) * map.terrainVerticalScale();
positions.append( QVector3D( pt->x() - map.originX, h, -( pt->y() - map.originY ) ) );
//qDebug() << positions.last();
}
else
qDebug() << "not a point";
}

return positions;
}
5 changes: 5 additions & 0 deletions src/3d/utils.h
Expand Up @@ -51,6 +51,11 @@ class _3D_EXPORT Utils
This is used to perform object culling checks.
*/
static bool isCullable(const AABB &bbox, const QMatrix4x4 &viewProjectionMatrix );

/*
* Calculates (x,y,z) position of point in the Point vector layers
*/
static QList<QVector3D> positions(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req);
};

#endif // UTILS_H

0 comments on commit 7d3cf22

Please sign in to comment.