Skip to content
Permalink
Browse files

Encapsulate entities for selected/not selected points in a root entity

  • Loading branch information
pblottiere authored and wonder-sk committed Aug 5, 2017
1 parent b0c98b7 commit a4e3a77dadc75e412c6274e442791e0fa52dd710
@@ -32,36 +32,131 @@
PointEntity::PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, Qt3DCore::QNode *parent )
: Qt3DCore::QEntity( parent )
{
QgsFeatureRequest request;
request.setDestinationCrs( map.crs );
QList<QVector3D> pos = positions( map, layer, request );
addEntityForSelectedPoints( map, layer, symbol );
addEntityForNotSelectedPoints( map, layer, symbol );
}

addComponent( renderer( symbol, pos ) );
addComponent( material( map, symbol ) );
Qt3DRender::QMaterial *PointEntity::material( const Point3DSymbol &symbol ) const
{
Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
filterKey->setName( "renderingStyle" );
filterKey->setValue( "forward" );

// the fragment shader implements a simplified version of phong shading that uses hardcoded light
// (instead of whatever light we have defined in the scene)
// TODO: use phong shading that respects lights from the scene
Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram;
shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( "qrc:/shaders/instanced.vert" ) ) );
shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( "qrc:/shaders/instanced.frag" ) ) );

Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass;
renderPass->setShaderProgram( shaderProgram );

Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
technique->addFilterKey( filterKey );
technique->addRenderPass( renderPass );
technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
technique->graphicsApiFilter()->setMajorVersion( 3 );
technique->graphicsApiFilter()->setMinorVersion( 2 );

Qt3DRender::QParameter *ambientParameter = new Qt3DRender::QParameter( QStringLiteral( "ka" ), QColor::fromRgbF( 0.05f, 0.05f, 0.05f, 1.0f ) );
Qt3DRender::QParameter *diffuseParameter = new Qt3DRender::QParameter( QStringLiteral( "kd" ), QColor::fromRgbF( 0.7f, 0.7f, 0.7f, 1.0f ) );
Qt3DRender::QParameter *specularParameter = new Qt3DRender::QParameter( QStringLiteral( "ks" ), QColor::fromRgbF( 0.01f, 0.01f, 0.01f, 1.0f ) );
Qt3DRender::QParameter *shininessParameter = new Qt3DRender::QParameter( QStringLiteral( "shininess" ), 150.0f );

diffuseParameter->setValue( symbol.material.diffuse() );
ambientParameter->setValue( symbol.material.ambient() );
specularParameter->setValue( symbol.material.specular() );
shininessParameter->setValue( symbol.material.shininess() );

QMatrix4x4 transformMatrix = symbol.transform;
QMatrix3x3 normalMatrix = transformMatrix.normalMatrix(); // transponed inverse of 3x3 sub-matrix

// QMatrix3x3 is not supported for passing to shaders, so we pass QMatrix4x4
float *n = normalMatrix.data();
QMatrix4x4 normalMatrix4(
n[0], n[3], n[6], 0,
n[1], n[4], n[7], 0,
n[2], n[5], n[8], 0,
0, 0, 0, 0 );

Qt3DRender::QParameter *paramInst = new Qt3DRender::QParameter;
paramInst->setName( "inst" );
paramInst->setValue( transformMatrix );

Qt3DRender::QParameter *paramInstNormal = new Qt3DRender::QParameter;
paramInstNormal->setName( "instNormal" );
paramInstNormal->setValue( normalMatrix4 );

Qt3DRender::QEffect *effect = new Qt3DRender::QEffect;
effect->addTechnique( technique );
effect->addParameter( paramInst );
effect->addParameter( paramInstNormal );

effect->addParameter( ambientParameter );
effect->addParameter( diffuseParameter );
effect->addParameter( specularParameter );
effect->addParameter( shininessParameter );

Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
material->setEffect( effect );

return material;
}

PointEntity::PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, bool sel, Qt3DCore::QNode *parent )
: Qt3DCore::QEntity( parent )
void PointEntity::addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol )
{
QgsFeatureRequest request;
request.setDestinationCrs( map.crs );
// build the default material
Qt3DRender::QMaterial *mat = material( symbol );

if ( sel )
request.setFilterFids( layer->selectedFeatureIds() );
else
// update the material with selection colors
Q_FOREACH ( Qt3DRender::QParameter *param, mat->effect()->parameters() )
{
QgsFeatureIds notSelected = layer->allFeatureIds();
notSelected.subtract( layer->selectedFeatureIds() );
request.setFilterFids( notSelected );
if ( param->name() == "kd" ) // diffuse
param->setValue( map.selectionColor() );
else if ( param->name() == "ka" ) // ambient
param->setValue( map.selectionColor().darker() );
}

QList<QVector3D> pos = positions( map, layer, request );
// build the feature request to select features
QgsFeatureRequest req;
req.setDestinationCrs( map.crs );
req.setFilterFids( layer->selectedFeatureIds() );

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

void PointEntity::addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol )
{
// build the default material
Qt3DRender::QMaterial *mat = material( symbol );

// build the feature request to select features
QgsFeatureRequest req;
req.setDestinationCrs( map.crs );

QgsFeatureIds notSelected = layer->allFeatureIds();
notSelected.subtract( layer->selectedFeatureIds() );
req.setFilterFids( notSelected );

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

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

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

@@ -168,82 +263,7 @@ Qt3DRender::QGeometryRenderer *PointEntity::renderer( const Point3DSymbol &symbo
return renderer;
}

Qt3DRender::QMaterial *PointEntity::material( const Map3D &map, const Point3DSymbol &symbol, bool sel ) const
{
Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
filterKey->setName( "renderingStyle" );
filterKey->setValue( "forward" );

// the fragment shader implements a simplified version of phong shading that uses hardcoded light
// (instead of whatever light we have defined in the scene)
// TODO: use phong shading that respects lights from the scene
Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram;
shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( "qrc:/shaders/instanced.vert" ) ) );
shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( "qrc:/shaders/instanced.frag" ) ) );

Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass;
renderPass->setShaderProgram( shaderProgram );

Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
technique->addFilterKey( filterKey );
technique->addRenderPass( renderPass );
technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
technique->graphicsApiFilter()->setMajorVersion( 3 );
technique->graphicsApiFilter()->setMinorVersion( 2 );

Qt3DRender::QParameter *ambientParameter = new Qt3DRender::QParameter( QStringLiteral( "ka" ), QColor::fromRgbF( 0.05f, 0.05f, 0.05f, 1.0f ) );
Qt3DRender::QParameter *diffuseParameter = new Qt3DRender::QParameter( QStringLiteral( "kd" ), QColor::fromRgbF( 0.7f, 0.7f, 0.7f, 1.0f ) );
Qt3DRender::QParameter *specularParameter = new Qt3DRender::QParameter( QStringLiteral( "ks" ), QColor::fromRgbF( 0.01f, 0.01f, 0.01f, 1.0f ) );
Qt3DRender::QParameter *shininessParameter = new Qt3DRender::QParameter( QStringLiteral( "shininess" ), 150.0f );

diffuseParameter->setValue( symbol.material.diffuse() );
ambientParameter->setValue( symbol.material.ambient() );
specularParameter->setValue( symbol.material.specular() );
shininessParameter->setValue( symbol.material.shininess() );

if ( sel )
{
diffuseParameter->setValue( map.selectionColor() );
ambientParameter->setValue( map.selectionColor().darker() );
}

QMatrix4x4 transformMatrix = symbol.transform;
QMatrix3x3 normalMatrix = transformMatrix.normalMatrix(); // transponed inverse of 3x3 sub-matrix

// QMatrix3x3 is not supported for passing to shaders, so we pass QMatrix4x4
float *n = normalMatrix.data();
QMatrix4x4 normalMatrix4(
n[0], n[3], n[6], 0,
n[1], n[4], n[7], 0,
n[2], n[5], n[8], 0,
0, 0, 0, 0 );

Qt3DRender::QParameter *paramInst = new Qt3DRender::QParameter;
paramInst->setName( "inst" );
paramInst->setValue( transformMatrix );

Qt3DRender::QParameter *paramInstNormal = new Qt3DRender::QParameter;
paramInstNormal->setName( "instNormal" );
paramInstNormal->setValue( normalMatrix4 );

Qt3DRender::QEffect *effect = new Qt3DRender::QEffect;
effect->addTechnique( technique );
effect->addParameter( paramInst );
effect->addParameter( paramInstNormal );

effect->addParameter( ambientParameter );
effect->addParameter( diffuseParameter );
effect->addParameter( specularParameter );
effect->addParameter( shininessParameter );

Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
material->setEffect( effect );

return material;
}

QList<QVector3D> PointEntity::positions( const Map3D &map, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) const
QList<QVector3D> PointEntityNode::positions( const Map3D &map, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) const
{
QList<QVector3D> positions;
QgsFeature f;
@@ -18,11 +18,20 @@ class PointEntity : public Qt3DCore::QEntity
public:
PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, Qt3DCore::QNode *parent = nullptr );

PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, bool sel, 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 );

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

class PointEntityNode : public Qt3DCore::QEntity
{
public:
PointEntityNode( 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;
Qt3DRender::QMaterial *material( const Map3D &map, const Point3DSymbol &symbol, bool sel = false ) const;
QList<QVector3D> positions( const Map3D &map, const QgsVectorLayer *layer, const QgsFeatureRequest &req ) const;
};

@@ -72,10 +72,8 @@ Scene::Scene( const Map3D &map, Qt3DExtras::QForwardRenderer *defaultFrameGraph,

Q_FOREACH ( const QgsAbstract3DRenderer *renderer, map.renderers )
{
QList<Qt3DCore::QEntity *> entities = renderer->createEntities( map );

Q_FOREACH ( Qt3DCore::QEntity *entity, entities )
entity->setParent( this );
Qt3DCore::QEntity *newEntity = renderer->createEntity( map );
newEntity->setParent( this );
}

// listen to changes of layers in order to add/remove 3D renderer entities
@@ -282,13 +280,9 @@ void Scene::addLayerEntity( QgsMapLayer *layer )
QgsAbstract3DRenderer *renderer = layer->renderer3D();
if ( renderer )
{
QList<Qt3DCore::QEntity *> entities = renderer->createEntities( mMap );

Q_FOREACH ( Qt3DCore::QEntity *entity, entities )
{
entity->setParent( this );
mLayerEntities.insert( layer, entity );
}
Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
newEntity->setParent( this );
mLayerEntities.insert( layer, newEntity );
}

connect( layer, &QgsMapLayer::renderer3DChanged, this, &Scene::onLayerRenderer3DChanged );
@@ -302,8 +296,8 @@ void Scene::addLayerEntity( QgsMapLayer *layer )

void Scene::removeLayerEntity( QgsMapLayer *layer )
{
Qt3DCore::QEntity *entity;
while ( ( entity = mLayerEntities.take( layer ) ) )
Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
if ( entity )
entity->deleteLater();

disconnect( layer, &QgsMapLayer::renderer3DChanged, this, &Scene::onLayerRenderer3DChanged );
@@ -62,7 +62,7 @@ class _3D_EXPORT Scene : public Qt3DCore::QEntity
Qt3DExtras::QForwardRenderer *mForwardRenderer;
QList<ChunkedEntity *> chunkEntities;
//! Keeps track of entities that belong to a particular layer
QMultiMap<QgsMapLayer *, Qt3DCore::QEntity *> mLayerEntities;
QMap<QgsMapLayer *, Qt3DCore::QEntity *> mLayerEntities;
bool mTerrainUpdateScheduled = false;
};

@@ -78,28 +78,6 @@ Qt3DCore::QEntity *VectorLayer3DRenderer::createEntity( const Map3D &map ) const
return nullptr;
}

QList<Qt3DCore::QEntity *> VectorLayer3DRenderer::createEntities( const Map3D &map ) const
{
QList<Qt3DCore::QEntity *> entities;

QgsVectorLayer *vl = layer();

if ( !mSymbol || !vl )
return entities;

if ( mSymbol->type() == "polygon" )
entities.append( new PolygonEntity( map, vl, *static_cast<Polygon3DSymbol *>( mSymbol.get() ) ) );
else if ( mSymbol->type() == "point" )
{
entities.append( new PointEntity( map, vl, *static_cast<Point3DSymbol *>( mSymbol.get() ), false ) );
entities.append( new PointEntity( map, vl, *static_cast<Point3DSymbol *>( mSymbol.get() ), true ) );
}
else if ( mSymbol->type() == "line" )
entities.append( new LineEntity( map, vl, *static_cast<Line3DSymbol *>( mSymbol.get() ) ) );

return entities;
}

void VectorLayer3DRenderer::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
{
QDomDocument doc = elem.ownerDocument();
@@ -48,7 +48,6 @@ class _3D_EXPORT VectorLayer3DRenderer : public QgsAbstract3DRenderer
QString type() const override { return "vector"; }
VectorLayer3DRenderer *clone() const override;
Qt3DCore::QEntity *createEntity( const Map3D &map ) const override;
QList<Qt3DCore::QEntity *> createEntities( const Map3D &map ) const override;

void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const override;
void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override;
@@ -25,7 +25,6 @@ class CORE_EXPORT QgsAbstract3DRenderer //: public QObject
virtual QString type() const = 0;
virtual QgsAbstract3DRenderer *clone() const = 0;
virtual Qt3DCore::QEntity *createEntity( const Map3D &map ) const = 0;
virtual QList<Qt3DCore::QEntity *> createEntities( const Map3D &map ) const = 0;

virtual void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const = 0;
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) = 0;

0 comments on commit a4e3a77

Please sign in to comment.
You can’t perform that action at this time.