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" }
Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) { QgsPointXY origin( map.origin().x(), map.origin().y() ); // TODO: configurable int nSegments = 4; QgsGeometry::EndCapStyle endCapStyle = QgsGeometry::CapRound; QgsGeometry::JoinStyle joinStyle = QgsGeometry::JoinStyleRound; double mitreLimit = 0; QList<QgsPolygon *> polygons; QgsFeature f; QgsFeatureIterator fi = layer->getFeatures( request ); while ( fi.nextFeature( f ) ) { if ( f.geometry().isNull() ) continue; QgsGeometry geom = f.geometry(); // segmentize curved geometries if necessary if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) ) geom = QgsGeometry( geom.constGet()->segmentize() ); const QgsAbstractGeometry *g = geom.constGet(); QgsGeos engine( g ); QgsAbstractGeometry *buffered = engine.buffer( symbol.width() / 2., nSegments, endCapStyle, joinStyle, mitreLimit ); // factory if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::Polygon ) { QgsPolygon *polyBuffered = static_cast<QgsPolygon *>( buffered ); Qgs3DUtils::clampAltitudes( polyBuffered, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), map ); polygons.append( polyBuffered ); } else if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::MultiPolygon ) { QgsMultiPolygon *mpolyBuffered = static_cast<QgsMultiPolygon *>( buffered ); for ( int i = 0; i < mpolyBuffered->numGeometries(); ++i ) { QgsAbstractGeometry *partBuffered = mpolyBuffered->geometryN( i ); Q_ASSERT( QgsWkbTypes::flatType( partBuffered->wkbType() ) == QgsWkbTypes::Polygon ); QgsPolygon *polyBuffered = static_cast<QgsPolygon *>( partBuffered )->clone(); // need to clone individual geometry parts Qgs3DUtils::clampAltitudes( polyBuffered, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), map ); polygons.append( polyBuffered ); } delete buffered; } } mGeometry = new QgsTessellatedPolygonGeometry; mGeometry->setPolygons( polygons, origin, symbol.extrusionHeight() ); Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; renderer->setGeometry( mGeometry ); return renderer; }
Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *parent ) { QgsTerrainTileEntity *entity = new QgsTerrainTileEntity; // create geometry renderer Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer; mesh->setGeometry( new DemTerrainTileGeometry( mResolution, mHeightMap, mesh ) ); entity->addComponent( mesh ); // takes ownership if the component has no parent // create material createTextureComponent( entity ); // create transform Qt3DCore::QTransform *transform; transform = new Qt3DCore::QTransform(); entity->addComponent( transform ); float zMin, zMax; _heightMapMinMax( mHeightMap, zMin, zMax ); const Qgs3DMapSettings &map = terrain()->map3D(); QgsRectangle extent = map.terrainGenerator()->tilingScheme().tileToExtent( mNode->tileX(), mNode->tileY(), mNode->tileZ() ); //node->extent; double x0 = extent.xMinimum() - map.originX(); double y0 = extent.yMinimum() - map.originY(); double side = extent.width(); double half = side / 2; transform->setScale3D( QVector3D( side, map.terrainVerticalScale(), side ) ); transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) ); mNode->setExactBbox( QgsAABB( x0, zMin * map.terrainVerticalScale(), -y0, x0 + side, zMax * map.terrainVerticalScale(), -( y0 + side ) ) ); entity->setEnabled( false ); entity->setParent( parent ); return entity; }
virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) { Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; // create geometry renderer Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer; mesh->setGeometry( new QuantizedMeshGeometry( qmt, mTerrain->map3D(), mapSettings.mapToPixel(), mTerrain->terrainToMapTransform(), mesh ) ); entity->addComponent( mesh ); // create material createTextureComponent( entity ); // create transform Qt3DCore::QTransform *transform; transform = new Qt3DCore::QTransform(); entity->addComponent( transform ); const Map3D &map = mTerrain->map3D(); transform->setScale3D( QVector3D( 1.f, map.zExaggeration, 1.f ) ); QgsRectangle mapExtent = mapSettings.extent(); float x0 = mapExtent.xMinimum() - map.originX; float y0 = mapExtent.yMinimum() - map.originY; float x1 = mapExtent.xMaximum() - map.originX; float y1 = mapExtent.yMaximum() - map.originY; float z0 = qmt->header.MinimumHeight, z1 = qmt->header.MaximumHeight; node->setExactBbox( AABB( x0, z0 * map.zExaggeration, -y0, x1, z1 * map.zExaggeration, -y1 ) ); //epsilon = mapExtent.width() / map.tileTextureSize; entity->setEnabled( false ); entity->setParent( parent ); return entity; }
Qt3DCore::QEntity *FlatTerrainChunkLoader::createEntity( Qt3DCore::QEntity *parent ) { QgsTerrainTileEntity *entity = new QgsTerrainTileEntity; // make geometry renderer // simple quad geometry shared by all tiles // QPlaneGeometry by default is 1x1 with mesh resolution QSize(2,2), centered at 0 // TODO: the geometry could be shared inside Terrain instance (within terrain-generator specific data?) mTileGeometry = new Qt3DExtras::QPlaneGeometry; Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer; mesh->setGeometry( mTileGeometry ); // takes ownership if the component has no parent entity->addComponent( mesh ); // takes ownership if the component has no parent // create material createTextureComponent( entity ); // create transform Qt3DCore::QTransform *transform = nullptr; transform = new Qt3DCore::QTransform(); entity->addComponent( transform ); // set up transform according to the extent covered by the quad geometry QgsAABB bbox = mNode->bbox(); double side = bbox.xMax - bbox.xMin; double half = side / 2; transform->setScale( side ); transform->setTranslation( QVector3D( bbox.xMin + half, 0, bbox.zMin + half ) ); entity->setEnabled( false ); entity->setParent( parent ); return entity; }
Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::rendererSimple( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) { QVector<QVector3D> vertices; vertices << QVector3D(); // the first index is invalid, we use it for primitive restart QVector<unsigned int> indexes; QgsPoint centroid; QgsPointXY origin( map.origin().x(), map.origin().y() ); QgsFeature f; QgsFeatureIterator fi = layer->getFeatures( request ); while ( fi.nextFeature( f ) ) { if ( f.geometry().isNull() ) continue; if ( symbol.altitudeBinding() == AltBindCentroid ) centroid = QgsPoint( f.geometry().centroid().asPoint() ); QgsGeometry geom = f.geometry(); const QgsAbstractGeometry *g = geom.constGet(); if ( const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( g ) ) { for ( int i = 0; i < ls->vertexCount(); ++i ) { QgsPoint p = ls->pointN( i ); float z = Qgs3DUtils::clampAltitude( p, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), centroid, map ); vertices << QVector3D( p.x() - map.origin().x(), z, -( p.y() - map.origin().y() ) ); indexes << vertices.count() - 1; } } else if ( const QgsMultiLineString *mls = qgsgeometry_cast<const QgsMultiLineString *>( g ) ) { for ( int nGeom = 0; nGeom < mls->numGeometries(); ++nGeom ) { const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( mls->geometryN( nGeom ) ); for ( int i = 0; i < ls->vertexCount(); ++i ) { QgsPoint p = ls->pointN( i ); float z = Qgs3DUtils::clampAltitude( p, symbol.altitudeClamping(), symbol.altitudeBinding(), symbol.height(), centroid, map ); vertices << QVector3D( p.x() - map.origin().x(), z, -( p.y() - map.origin().y() ) ); indexes << vertices.count() - 1; } indexes << 0; // add primitive restart } } indexes << 0; // add primitive restart } QByteArray vertexBufferData; vertexBufferData.resize( vertices.size() * 3 * sizeof( float ) ); float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() ); int idx = 0; for ( const auto &v : vertices ) { rawVertexArray[idx++] = v.x(); rawVertexArray[idx++] = v.y(); rawVertexArray[idx++] = v.z(); } QByteArray indexBufferData; indexBufferData.resize( indexes.size() * sizeof( int ) ); unsigned int *rawIndexArray = reinterpret_cast<unsigned int *>( indexBufferData.data() ); idx = 0; for ( unsigned int indexVal : indexes ) { rawIndexArray[idx++] = indexVal; } Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this ); vertexBuffer->setData( vertexBufferData ); Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, this ); indexBuffer->setData( indexBufferData ); Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute( this ); 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( this ); 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( vertices.count() ); renderer->setPrimitiveRestartEnabled( true ); renderer->setRestartIndexValue( 0 ); return renderer; }
Qt3DRender::QGeometryRenderer *QgsPolygon3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsPolygon3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) { QgsPointXY origin( map.origin().x(), map.origin().y() ); QList<QgsPolygon *> polygons; QList<float> extrusionHeightPerPolygon; // will stay empty if not needed per polygon QgsExpressionContext ctx( _expressionContext3D() ); ctx.setFields( layer->fields() ); const QgsPropertyCollection &ddp = symbol.dataDefinedProperties(); bool hasDDHeight = ddp.isActive( QgsAbstract3DSymbol::PropertyHeight ); bool hasDDExtrusion = ddp.isActive( QgsAbstract3DSymbol::PropertyExtrusionHeight ); QgsFeature f; QgsFeatureIterator fi = layer->getFeatures( request ); while ( fi.nextFeature( f ) ) { if ( f.geometry().isNull() ) continue; QgsGeometry geom = f.geometry(); // segmentize curved geometries if necessary if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) ) geom = QgsGeometry( geom.constGet()->segmentize() ); const QgsAbstractGeometry *g = geom.constGet(); ctx.setFeature( f ); float height = symbol.height(); float extrusionHeight = symbol.extrusionHeight(); if ( hasDDHeight ) height = ddp.valueAsDouble( QgsAbstract3DSymbol::PropertyHeight, ctx, height ); if ( hasDDExtrusion ) extrusionHeight = ddp.valueAsDouble( QgsAbstract3DSymbol::PropertyExtrusionHeight, ctx, extrusionHeight ); if ( const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) ) { QgsPolygon *polyClone = poly->clone(); Qgs3DUtils::clampAltitudes( polyClone, symbol.altitudeClamping(), symbol.altitudeBinding(), height, map ); polygons.append( polyClone ); if ( hasDDExtrusion ) extrusionHeightPerPolygon.append( extrusionHeight ); } else if ( const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) ) { for ( int i = 0; i < mpoly->numGeometries(); ++i ) { const QgsAbstractGeometry *g2 = mpoly->geometryN( i ); Q_ASSERT( QgsWkbTypes::flatType( g2->wkbType() ) == QgsWkbTypes::Polygon ); QgsPolygon *polyClone = static_cast< const QgsPolygon *>( g2 )->clone(); Qgs3DUtils::clampAltitudes( polyClone, symbol.altitudeClamping(), symbol.altitudeBinding(), height, map ); polygons.append( polyClone ); if ( hasDDExtrusion ) extrusionHeightPerPolygon.append( extrusionHeight ); } } else qDebug() << "not a polygon"; } mGeometry = new QgsTessellatedPolygonGeometry; mGeometry->setPolygons( polygons, origin, symbol.extrusionHeight(), extrusionHeightPerPolygon ); Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; renderer->setGeometry( mGeometry ); return renderer; }
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 ); }
void checkInitialAndCleanedUpState() { // GIVEN Qt3DRender::Render::GeometryRenderer renderGeometryRenderer; // THEN QVERIFY(renderGeometryRenderer.peerUuid().isNull()); QVERIFY(renderGeometryRenderer.geometryId().isNull()); QCOMPARE(renderGeometryRenderer.isDirty(), false); QCOMPARE(renderGeometryRenderer.instanceCount(), 0); QCOMPARE(renderGeometryRenderer.primitiveCount(), 0); QCOMPARE(renderGeometryRenderer.baseVertex(), 0); QCOMPARE(renderGeometryRenderer.baseInstance(), 0); QCOMPARE(renderGeometryRenderer.restartIndex(), -1); QCOMPARE(renderGeometryRenderer.primitiveRestart(), false); QCOMPARE(renderGeometryRenderer.primitiveType(), Qt3DRender::QGeometryRenderer::Triangles); QVERIFY(renderGeometryRenderer.geometryFunctor().isNull()); QVERIFY(renderGeometryRenderer.isEnabled()); // GIVEN Qt3DRender::QGeometryRenderer geometryRenderer; Qt3DRender::QGeometry geometry; Qt3DRender::QGeometryFunctorPtr functor(new TestFunctor(1200)); geometryRenderer.setInstanceCount(454); geometryRenderer.setPrimitiveCount(350); geometryRenderer.setBaseVertex(427); geometryRenderer.setBaseInstance(383); geometryRenderer.setRestartIndex(555); geometryRenderer.setPrimitiveRestart(true); geometryRenderer.setPrimitiveType(Qt3DRender::QGeometryRenderer::Patches); geometryRenderer.setGeometry(&geometry); geometryRenderer.setGeometryFunctor(functor); geometryRenderer.setEnabled(false); // WHEN renderGeometryRenderer.updateFromPeer(&geometryRenderer); renderGeometryRenderer.cleanup(); // THEN QVERIFY(renderGeometryRenderer.peerUuid().isNull()); QVERIFY(renderGeometryRenderer.geometryId().isNull()); QCOMPARE(renderGeometryRenderer.isDirty(), false); QCOMPARE(renderGeometryRenderer.instanceCount(), 0); QCOMPARE(renderGeometryRenderer.primitiveCount(), 0); QCOMPARE(renderGeometryRenderer.baseVertex(), 0); QCOMPARE(renderGeometryRenderer.baseInstance(), 0); QCOMPARE(renderGeometryRenderer.restartIndex(), -1); QCOMPARE(renderGeometryRenderer.primitiveRestart(), false); QCOMPARE(renderGeometryRenderer.primitiveType(), Qt3DRender::QGeometryRenderer::Triangles); QVERIFY(renderGeometryRenderer.geometryFunctor().isNull()); QVERIFY(renderGeometryRenderer.isEnabled()); }