Qgs3DMapScene::Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *engine ) : mMap( map ) , mEngine( engine ) { connect( &map, &Qgs3DMapSettings::backgroundColorChanged, this, &Qgs3DMapScene::onBackgroundColorChanged ); onBackgroundColorChanged(); // TODO: strange - setting OnDemand render policy still keeps QGIS busy (Qt 5.9.0) // actually it is more busy than with the default "Always" policy although there are no changes in the scene. //mRenderer->renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand ); #if QT_VERSION >= 0x050900 // we want precise picking of terrain (also bounding volume picking does not seem to work - not sure why) mEngine->renderSettings()->pickingSettings()->setPickMethod( Qt3DRender::QPickingSettings::TrianglePicking ); #endif QRect viewportRect( QPoint( 0, 0 ), mEngine->size() ); // Camera float aspectRatio = ( float )viewportRect.width() / viewportRect.height(); mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f ); mFrameAction = new Qt3DLogic::QFrameAction(); connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered, this, &Qgs3DMapScene::onFrameTriggered ); addComponent( mFrameAction ); // takes ownership // Camera controlling mCameraController = new QgsCameraController( this ); // attaches to the scene mCameraController->setViewport( viewportRect ); mCameraController->setCamera( mEngine->camera() ); mCameraController->resetView( 1000 ); addCameraViewCenterEntity( mEngine->camera() ); // create terrain entity createTerrainDeferred(); connect( &map, &Qgs3DMapSettings::terrainGeneratorChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::terrainVerticalScaleChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::mapTileResolutionChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::maxTerrainScreenErrorChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::maxTerrainGroundErrorChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::terrainShadingChanged, this, &Qgs3DMapScene::createTerrain ); connect( &map, &Qgs3DMapSettings::pointLightsChanged, this, &Qgs3DMapScene::updateLights ); connect( &map, &Qgs3DMapSettings::fieldOfViewChanged, this, &Qgs3DMapScene::updateCameraLens ); // create entities of renderers Q_FOREACH ( const QgsAbstract3DRenderer *renderer, map.renderers() ) { Qt3DCore::QEntity *newEntity = renderer->createEntity( map ); newEntity->setParent( this ); } // listen to changes of layers in order to add/remove 3D renderer entities connect( &map, &Qgs3DMapSettings::layersChanged, this, &Qgs3DMapScene::onLayersChanged ); updateLights(); #if 0 ChunkedEntity *testChunkEntity = new ChunkedEntity( AABB( -500, 0, -500, 500, 100, 500 ), 2.f, 3.f, 7, new TestChunkLoaderFactory ); testChunkEntity->setEnabled( false ); testChunkEntity->setParent( this ); chunkEntities << testChunkEntity; #endif connect( mCameraController, &QgsCameraController::cameraChanged, this, &Qgs3DMapScene::onCameraChanged ); connect( mCameraController, &QgsCameraController::viewportChanged, this, &Qgs3DMapScene::onCameraChanged ); #if 0 // experiments with loading of existing 3D models. // scene loader only gets loaded only when added to a scene... // it loads everything: geometries, materials, transforms, lights, cameras (if any) Qt3DCore::QEntity *loaderEntity = new Qt3DCore::QEntity; Qt3DRender::QSceneLoader *loader = new Qt3DRender::QSceneLoader; loader->setSource( QUrl( "file:///home/martin/Downloads/LowPolyModels/tree.dae" ) ); loaderEntity->addComponent( loader ); loaderEntity->setParent( this ); // mesh loads just geometry as one geometry... // so if there are different materials (e.g. colors) used in the model, this information is lost Qt3DCore::QEntity *meshEntity = new Qt3DCore::QEntity; Qt3DRender::QMesh *mesh = new Qt3DRender::QMesh; mesh->setSource( QUrl( "file:///home/martin/Downloads/LowPolyModels/tree.obj" ) ); meshEntity->addComponent( mesh ); Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial; material->setAmbient( Qt::red ); meshEntity->addComponent( material ); Qt3DCore::QTransform *meshTransform = new Qt3DCore::QTransform; meshTransform->setScale( 1 ); meshEntity->addComponent( meshTransform ); meshEntity->setParent( this ); #endif if ( map.hasSkyboxEnabled() ) { Qt3DExtras::QSkyboxEntity *skybox = new Qt3DExtras::QSkyboxEntity; skybox->setBaseName( map.skyboxFileBase() ); skybox->setExtension( map.skyboxFileExtension() ); skybox->setParent( this ); // docs say frustum culling must be disabled for skybox. // it _somehow_ works even when frustum culling is enabled with some camera positions, // but then when zoomed in more it would disappear - so let's keep frustum culling disabled mEngine->setFrustumCullingEnabled( false ); } // force initial update of chunked entities onCameraChanged(); }
void QgsPolygon3DSymbolEntity::addEntityForSelectedPolygons( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPolygon3DSymbol &symbol ) { // build the default material Qt3DExtras::QPhongMaterial *mat = material( symbol ); // update the material with selection colors mat->setDiffuse( map.selectionColor() ); mat->setAmbient( map.selectionColor().darker() ); // build a transform function Qt3DCore::QTransform *tform = new Qt3DCore::QTransform; tform->setTranslation( QVector3D( 0, 0, 0 ) ); // build the feature request to select features QgsFeatureRequest req; req.setDestinationCrs( map.crs() ); req.setSubsetOfAttributes( _requiredAttributes( symbol, layer ), layer->fields() ); req.setFilterFids( layer->selectedFeatureIds() ); // build the entity QgsPolygon3DSymbolEntityNode *entity = new QgsPolygon3DSymbolEntityNode( map, layer, symbol, req ); entity->addComponent( mat ); entity->addComponent( tform ); entity->setParent( this ); }
void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &out, bool selected ) { if ( out.polygons.isEmpty() ) return; // nothing to show - no need to create the entity Qt3DExtras::QPhongMaterial *mat = _material( mSymbol ); if ( selected ) { // update the material with selection colors mat->setDiffuse( context.map().selectionColor() ); mat->setAmbient( context.map().selectionColor().darker() ); } QgsPointXY origin( context.map().origin().x(), context.map().origin().y() ); QgsTessellatedPolygonGeometry *geometry = new QgsTessellatedPolygonGeometry; geometry->setPolygons( out.polygons, out.fids, origin, mSymbol.extrusionHeight() ); Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; renderer->setGeometry( geometry ); // make entity Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; entity->addComponent( renderer ); entity->addComponent( mat ); entity->setParent( parent ); if ( !selected ) entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral( "main" ) ); // temporary measure to distinguish between "selected" and "main" }
Qt3DExtras::QPhongMaterial *QgsPolygon3DSymbolEntity::material( const QgsPolygon3DSymbol &symbol ) const { Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial; material->setAmbient( symbol.material().ambient() ); material->setDiffuse( symbol.material().diffuse() ); material->setSpecular( symbol.material().specular() ); material->setShininess( symbol.material().shininess() ); return material; }
QgsChunkBoundsEntity::QgsChunkBoundsEntity( Qt3DCore::QNode *parent ) : Qt3DCore::QEntity( parent ) { mAabbMesh = new AABBMesh; addComponent( mAabbMesh ); Qt3DExtras::QPhongMaterial *bboxesMaterial = new Qt3DExtras::QPhongMaterial; bboxesMaterial->setAmbient( Qt::red ); addComponent( bboxesMaterial ); }
static Qt3DExtras::QPhongMaterial *_material( const QgsLine3DSymbol &symbol ) { Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial; material->setAmbient( symbol.material().ambient() ); material->setDiffuse( symbol.material().diffuse() ); material->setSpecular( symbol.material().specular() ); material->setShininess( symbol.material().shininess() ); return material; }
void QgsLine3DSymbolEntity::addEntityForSelectedLines( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ) { // build the default material Qt3DExtras::QPhongMaterial *mat = material( symbol ); // update the material with selection colors mat->setDiffuse( map.selectionColor() ); mat->setAmbient( map.selectionColor().darker() ); // build the feature request to select features QgsFeatureRequest req; req.setDestinationCrs( map.crs(), map.transformContext() ); req.setFilterFids( layer->selectedFeatureIds() ); // build the entity QgsLine3DSymbolEntityNode *entity = new QgsLine3DSymbolEntityNode( map, layer, symbol, req ); entity->addComponent( mat ); entity->setParent( this ); }
bool BrainSourceSpaceTreeItem::addData(const MNEHemisphere& tHemisphere, Qt3DCore::QEntity* parent) { //Create renderable 3D entity m_pParentEntity = parent; m_pRenderable3DEntity = new Renderable3DEntity(m_pParentEntity); //Initial transformation also regarding the surface offset m_pRenderable3DEntity->setRotX(90); m_pRenderable3DEntity->setRotY(180); //Create sources as small 3D spheres RowVector3f sourcePos; QVector3D pos; if(tHemisphere.isClustered()) { for(int i = 0; i < tHemisphere.cluster_info.centroidVertno.size(); i++) { Renderable3DEntity* pSourceSphereEntity = new Renderable3DEntity(m_pRenderable3DEntity); sourcePos = tHemisphere.rr.row(tHemisphere.cluster_info.centroidVertno.at(i)); pos.setX(sourcePos(0)); pos.setY(sourcePos(1)); pos.setZ(sourcePos(2)); Qt3DExtras::QSphereMesh* sourceSphere = new Qt3DExtras::QSphereMesh(); sourceSphere->setRadius(0.001f); pSourceSphereEntity->addComponent(sourceSphere); pSourceSphereEntity->setPosition(pos); Qt3DExtras::QPhongMaterial*material = new Qt3DExtras::QPhongMaterial(); material->setAmbient(Qt::yellow); pSourceSphereEntity->addComponent(material); m_lSpheres.append(pSourceSphereEntity); } } else { for(int i = 0; i < tHemisphere.vertno.rows(); i++) { Renderable3DEntity* pSourceSphereEntity = new Renderable3DEntity(m_pRenderable3DEntity); sourcePos = tHemisphere.rr.row(tHemisphere.vertno(i)); pos.setX(sourcePos(0)); pos.setY(sourcePos(1)); pos.setZ(sourcePos(2)); Qt3DExtras::QSphereMesh* sourceSphere = new Qt3DExtras::QSphereMesh(); sourceSphere->setRadius(0.001f); pSourceSphereEntity->addComponent(sourceSphere); pSourceSphereEntity->setPosition(pos); Qt3DExtras::QPhongMaterial* material = new Qt3DExtras::QPhongMaterial(); material->setAmbient(Qt::yellow); pSourceSphereEntity->addComponent(material); m_lSpheres.append(pSourceSphereEntity); } } //Create color from curvature information with default gyri and sulcus colors QByteArray arrayVertColor = createVertColor(tHemisphere.rr); //Set renderable 3D entity mesh and color data m_pRenderable3DEntity->setMeshData(tHemisphere.rr, tHemisphere.nn, tHemisphere.tris, arrayVertColor); //Add data which is held by this BrainSourceSpaceTreeItem QVariant data; data.setValue(arrayVertColor); this->setData(data, Data3DTreeModelItemRoles::SurfaceCurrentColorVert); data.setValue(tHemisphere.rr); this->setData(data, Data3DTreeModelItemRoles::SurfaceVert); data.setValue(tHemisphere.tris); this->setData(data, Data3DTreeModelItemRoles::SurfaceTris); data.setValue(tHemisphere.nn); this->setData(data, Data3DTreeModelItemRoles::SurfaceNorm); data.setValue(m_pRenderable3DEntity); this->setData(data, Data3DTreeModelItemRoles::SurfaceRenderable3DEntity); //Add surface meta information as item children QList<QStandardItem*> list; MetaTreeItem* pItemSurfCol = new MetaTreeItem(MetaTreeItemTypes::SurfaceColor, "Surface color"); connect(pItemSurfCol, &MetaTreeItem::surfaceColorChanged, this, &BrainSourceSpaceTreeItem::onSurfaceColorChanged); list << pItemSurfCol; list << new QStandardItem(pItemSurfCol->toolTip()); this->appendRow(list); data.setValue(QColor(100,100,100)); pItemSurfCol->setData(data, MetaTreeItemRoles::SurfaceColor); pItemSurfCol->setData(data, Qt::DecorationRole); return true; }
void QgsSimpleLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &out, bool selected ) { if ( out.indexes.isEmpty() ) return; // material (only ambient color is used for the color) Qt3DExtras::QPhongMaterial *mat = _material( mSymbol ); if ( selected ) { // update the material with selection colors mat->setAmbient( context.map().selectionColor() ); } // geometry renderer QByteArray vertexBufferData; vertexBufferData.resize( out.vertices.size() * 3 * sizeof( float ) ); float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() ); int idx = 0; for ( const auto &v : qgis::as_const( out.vertices ) ) { rawVertexArray[idx++] = v.x(); rawVertexArray[idx++] = v.y(); rawVertexArray[idx++] = v.z(); } QByteArray indexBufferData; indexBufferData.resize( out.indexes.size() * sizeof( int ) ); unsigned int *rawIndexArray = reinterpret_cast<unsigned int *>( indexBufferData.data() ); idx = 0; for ( unsigned int indexVal : qgis::as_const( out.indexes ) ) { rawIndexArray[idx++] = indexVal; } Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, entity ); vertexBuffer->setData( vertexBufferData ); Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, entity ); indexBuffer->setData( indexBufferData ); Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute( entity ); positionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute ); positionAttribute->setBuffer( vertexBuffer ); positionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float ); positionAttribute->setVertexSize( 3 ); positionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() ); Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute( entity ); indexAttribute->setAttributeType( Qt3DRender::QAttribute::IndexAttribute ); indexAttribute->setBuffer( indexBuffer ); indexAttribute->setVertexBaseType( Qt3DRender::QAttribute::UnsignedInt ); Qt3DRender::QGeometry *geom = new Qt3DRender::QGeometry; geom->addAttribute( positionAttribute ); geom->addAttribute( indexAttribute ); Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStrip ); renderer->setGeometry( geom ); renderer->setVertexCount( out.vertices.count() ); renderer->setPrimitiveRestartEnabled( true ); renderer->setRestartIndexValue( 0 ); // make entity entity->addComponent( renderer ); entity->addComponent( mat ); entity->setParent( parent ); }
bool DigitizerTreeItem::addData(const QList<FIFFLIB::FiffDigPoint>& tDigitizer, Qt3DCore::QEntity* parent) { //Clear all data m_lSpheres.clear(); // if(!m_pRenderable3DEntity.isNull()) { // m_pRenderable3DEntity->deleteLater(); // } m_pRenderable3DEntity = new Renderable3DEntity(parent); //Create digitizers as small 3D spheres QVector3D pos; QColor colDefault(100,100,100); for(int i = 0; i < tDigitizer.size(); ++i) { Renderable3DEntity* pSourceSphereEntity = new Renderable3DEntity(m_pRenderable3DEntity); pos.setX(tDigitizer[i].r[0]); pos.setY(tDigitizer[i].r[1]); pos.setZ(tDigitizer[i].r[2]); Qt3DExtras::QSphereMesh* sourceSphere = new Qt3DExtras::QSphereMesh(); if (tDigitizer[i].kind == FIFFV_POINT_CARDINAL) { sourceSphere->setRadius(0.002f); } else { sourceSphere->setRadius(0.001f); } pSourceSphereEntity->addComponent(sourceSphere); pSourceSphereEntity->setPosition(pos); Qt3DExtras::QPhongMaterial* material = new Qt3DExtras::QPhongMaterial(); switch (tDigitizer[i].kind) { case FIFFV_POINT_CARDINAL: colDefault = Qt::yellow; material->setAmbient(colDefault); break; case FIFFV_POINT_HPI: colDefault = Qt::red; material->setAmbient(colDefault); break; case FIFFV_POINT_EEG: colDefault = Qt::green; material->setAmbient(colDefault); break; case FIFFV_POINT_EXTRA: colDefault = Qt::blue; material->setAmbient(colDefault); break; default: colDefault = Qt::white; material->setAmbient(colDefault); break; } pSourceSphereEntity->addComponent(material); pSourceSphereEntity->setParent(m_pRenderable3DEntity); m_lSpheres.append(pSourceSphereEntity); } QList<QStandardItem*> items = this->findChildren(MetaTreeItemTypes::PointColor); for(int i = 0; i < items.size(); ++i) { if(MetaTreeItem* item = dynamic_cast<MetaTreeItem*>(items.at(i))) { QVariant data; data.setValue(colDefault); item->setData(data, MetaTreeItemRoles::PointColor); } } return true; }
bool DigitizerTreeItem::addData(const QList<FIFFLIB::FiffDigPoint>& tDigitizer, Qt3DCore::QEntity* parent) { //Create renderable 3D entity m_pParentEntity = parent; m_pRenderable3DEntity = new Renderable3DEntity(m_pParentEntity); //Initial transformation also regarding the surface offset m_pRenderable3DEntity->setRotX(90); m_pRenderable3DEntity->setRotY(180); //Create sources as small 3D spheres QVector3D pos; QColor colDefault(100,100,100); for(int i = 0; i < tDigitizer.size(); ++i) { Renderable3DEntity* pSourceSphereEntity = new Renderable3DEntity(m_pRenderable3DEntity); pos.setX(tDigitizer[i].r[0]); pos.setY(tDigitizer[i].r[1]); pos.setZ(tDigitizer[i].r[2]); Qt3DExtras::QSphereMesh* sourceSphere = new Qt3DExtras::QSphereMesh(); if (tDigitizer[i].kind == FIFFV_POINT_CARDINAL) { sourceSphere->setRadius(0.002f); } else { sourceSphere->setRadius(0.001f); } pSourceSphereEntity->addComponent(sourceSphere); pSourceSphereEntity->setPosition(pos); Qt3DExtras::QPhongMaterial* material = new Qt3DExtras::QPhongMaterial(); switch (tDigitizer[i].kind) { case FIFFV_POINT_CARDINAL: colDefault = Qt::yellow; material->setAmbient(colDefault); break; case FIFFV_POINT_HPI: colDefault = Qt::red; material->setAmbient(colDefault); break; case FIFFV_POINT_EEG: colDefault = Qt::green; material->setAmbient(colDefault); break; case FIFFV_POINT_EXTRA: colDefault = Qt::blue; material->setAmbient(colDefault); break; default: colDefault = Qt::white; material->setAmbient(colDefault); break; } pSourceSphereEntity->addComponent(material); pSourceSphereEntity->setParent(m_pRenderable3DEntity); m_lSpheres.append(pSourceSphereEntity); } //Add surface meta information as item children QVariant data; QList<QStandardItem*> list; MetaTreeItem* pItemSurfCol = new MetaTreeItem(MetaTreeItemTypes::PointColor, "Point color"); connect(pItemSurfCol, &MetaTreeItem::surfaceColorChanged, this, &DigitizerTreeItem::onSurfaceColorChanged); list.clear(); list << pItemSurfCol; list << new QStandardItem(pItemSurfCol->toolTip()); this->appendRow(list); data.setValue(colDefault); pItemSurfCol->setData(data, MetaTreeItemRoles::PointColor); pItemSurfCol->setData(data, Qt::DecorationRole); return true; }