18#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
19#include <Qt3DRender/QAttribute>
20#include <Qt3DRender/QBuffer>
21#include <Qt3DRender/QGeometry>
27#include <Qt3DCore/QAttribute>
28#include <Qt3DCore/QBuffer>
29#include <Qt3DCore/QGeometry>
36#include <Qt3DRender/QEffect>
37#include <Qt3DRender/QGraphicsApiFilter>
38#include <Qt3DRender/QParameter>
39#include <Qt3DRender/QTechnique>
41#include <Qt3DExtras/QCylinderGeometry>
42#include <Qt3DExtras/QConeGeometry>
43#include <Qt3DExtras/QCuboidGeometry>
44#include <Qt3DExtras/QPlaneGeometry>
45#include <Qt3DExtras/QSphereGeometry>
46#include <Qt3DExtras/QTorusGeometry>
47#include <Qt3DExtras/QPhongMaterial>
48#include <Qt3DRender/QSceneLoader>
49#include <Qt3DRender/QPaintedTextureImage>
51#include <Qt3DRender/QMesh>
53#include <Qt3DExtras/QExtrudedTextGeometry>
73class QgsInstancedPoint3DSymbolHandler :
public QgsFeature3DHandler
76 QgsInstancedPoint3DSymbolHandler(
const QgsPoint3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
77 : mSymbol( static_cast<QgsPoint3DSymbol *>( symbol->clone() ) )
78 , mSelectedIds( selectedIds ) {}
80 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsVector3D &chunkOrigin )
override;
81 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
82 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
85 static QgsMaterial *material(
const QgsPoint3DSymbol *symbol,
const QgsMaterialContext &materialContext );
86 static Qt3DRender::QGeometryRenderer *renderer(
const QgsPoint3DSymbol *symbol,
const QVector<QVector3D> &positions );
87 static Qt3DQGeometry *symbolGeometry(
const QgsPoint3DSymbol *symbol );
92 QVector<QVector3D> positions;
95 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected );
98 std::unique_ptr<QgsPoint3DSymbol> mSymbol;
103 QgsVector3D mChunkOrigin;
107 PointData outSelected;
111bool QgsInstancedPoint3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsVector3D &chunkOrigin )
114 Q_UNUSED( attributeNames )
116 mChunkOrigin = chunkOrigin;
123 PointData &out = mSelectedIds.contains( feature.
id() ) ? outSelected : outNormal;
132void QgsInstancedPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
134 makeEntity( parent, context, outNormal,
false );
135 makeEntity( parent, context, outSelected,
true );
137 updateZRangeFromPositions( outNormal.positions );
138 updateZRangeFromPositions( outSelected.positions );
141 const float symbolOffset = mSymbol->transform().data()[14];
145 switch ( mSymbol->shape() )
149 const float length = mSymbol->shapeProperty( QStringLiteral(
"length" ) ).toFloat();
150 mZMin -= length * 0.5f;
151 mZMax += length * 0.5f;
157 const float radius = mSymbol->shapeProperty( QStringLiteral(
"radius" ) ).toFloat();
165 const float length = mSymbol->shapeProperty( QStringLiteral(
"length" ) ).toFloat();
166 mZMin -= length * 0.5f;
167 mZMax += length * 0.5f;
173 const float size = mSymbol->shapeProperty( QStringLiteral(
"size" ) ).toFloat();
174 mZMin -= size * 0.5f;
175 mZMax += size * 0.5f;
181 const float radius = mSymbol->shapeProperty( QStringLiteral(
"radius" ) ).toFloat();
191 const float size = mSymbol->shapeProperty( QStringLiteral(
"size" ) ).toFloat();
192 mZMin -= size * 0.5f;
193 mZMax += size * 0.5f;
203 mZMin += symbolOffset;
204 mZMax += symbolOffset;
207void QgsInstancedPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected )
209 if ( out.positions.isEmpty() )
218 QgsMaterial *mat = material( mSymbol.get(), materialContext );
221 QgsGeoTransform *tr =
new QgsGeoTransform;
222 tr->setGeoTranslation( mChunkOrigin );
225 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
226 entity->addComponent( renderer( mSymbol.get(), out.positions ) );
227 entity->addComponent( mat );
228 entity->addComponent( tr );
229 entity->setParent( parent );
238 Qt3DRender::QFilterKey *filterKey =
new Qt3DRender::QFilterKey;
239 filterKey->setName( QStringLiteral(
"renderingStyle" ) );
240 filterKey->setValue(
"forward" );
242 Qt3DRender::QShaderProgram *shaderProgram =
new Qt3DRender::QShaderProgram;
243 shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral(
"qrc:/shaders/instanced.vert" ) ) ) );
244 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral(
"qrc:/shaders/phong.frag" ) ) ) );
246 Qt3DRender::QRenderPass *renderPass =
new Qt3DRender::QRenderPass;
247 renderPass->setShaderProgram( shaderProgram );
249 Qt3DRender::QTechnique *technique =
new Qt3DRender::QTechnique;
250 technique->addFilterKey( filterKey );
251 technique->addRenderPass( renderPass );
252 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
253 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
254 technique->graphicsApiFilter()->setMajorVersion( 3 );
255 technique->graphicsApiFilter()->setMinorVersion( 2 );
257 const QMatrix4x4 tempTransformMatrix = symbol->
transform();
261 id.rotate( QQuaternion::fromAxisAndAngle( QVector3D( 1, 0, 0 ), 90 ) );
262 const QMatrix4x4 transformMatrix = tempTransformMatrix * id;
265 QMatrix3x3 normalMatrix = transformMatrix.normalMatrix();
268 float *n = normalMatrix.data();
269 const QMatrix4x4 normalMatrix4(
276 Qt3DRender::QParameter *paramInst =
new Qt3DRender::QParameter;
277 paramInst->setName( QStringLiteral(
"inst" ) );
278 paramInst->setValue( transformMatrix );
280 Qt3DRender::QParameter *paramInstNormal =
new Qt3DRender::QParameter;
281 paramInstNormal->setName( QStringLiteral(
"instNormal" ) );
282 paramInstNormal->setValue( normalMatrix4 );
284 Qt3DRender::QEffect *effect =
new Qt3DRender::QEffect;
285 effect->addTechnique( technique );
286 effect->addParameter( paramInst );
287 effect->addParameter( paramInstNormal );
292 material->setEffect( effect );
297Qt3DRender::QGeometryRenderer *QgsInstancedPoint3DSymbolHandler::renderer(
const QgsPoint3DSymbol *symbol,
const QVector<QVector3D> &positions )
299 const int count = positions.count();
300 const int byteCount = positions.count() *
sizeof( QVector3D );
302 ba.resize( byteCount );
303 memcpy( ba.data(), positions.constData(), byteCount );
306 instanceBuffer->setData( ba );
309 instanceDataAttribute->setName( QStringLiteral(
"pos" ) );
310 instanceDataAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
311 instanceDataAttribute->setVertexBaseType( Qt3DQAttribute::Float );
312 instanceDataAttribute->setVertexSize( 3 );
313 instanceDataAttribute->setByteOffset( 0 );
314 instanceDataAttribute->setDivisor( 1 );
315 instanceDataAttribute->setBuffer( instanceBuffer );
316 instanceDataAttribute->setCount( count );
317 instanceDataAttribute->setByteStride( 3 *
sizeof(
float ) );
320 geometry->addAttribute( instanceDataAttribute );
321 geometry->setBoundingVolumePositionAttribute( instanceDataAttribute );
323 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
324 renderer->setGeometry( geometry );
325 renderer->setInstanceCount( count );
332 switch ( symbol->
shape() )
336 const float radius = symbol->
shapeProperty( QStringLiteral(
"radius" ) ).toFloat();
337 const float length = symbol->
shapeProperty( QStringLiteral(
"length" ) ).toFloat();
338 Qt3DExtras::QCylinderGeometry *g =
new Qt3DExtras::QCylinderGeometry;
341 g->setRadius( radius );
342 g->setLength( length );
348 const float radius = symbol->
shapeProperty( QStringLiteral(
"radius" ) ).toFloat();
349 Qt3DExtras::QSphereGeometry *g =
new Qt3DExtras::QSphereGeometry;
350 g->setRadius( radius );
356 const float length = symbol->
shapeProperty( QStringLiteral(
"length" ) ).toFloat();
357 const float bottomRadius = symbol->
shapeProperty( QStringLiteral(
"bottomRadius" ) ).toFloat();
358 const float topRadius = symbol->
shapeProperty( QStringLiteral(
"topRadius" ) ).toFloat();
360 Qt3DExtras::QConeGeometry *g =
new Qt3DExtras::QConeGeometry;
361 g->setLength( length );
362 g->setBottomRadius( bottomRadius );
363 g->setTopRadius( topRadius );
371 const float size = symbol->
shapeProperty( QStringLiteral(
"size" ) ).toFloat();
372 Qt3DExtras::QCuboidGeometry *g =
new Qt3DExtras::QCuboidGeometry;
373 g->setXExtent( size );
374 g->setYExtent( size );
375 g->setZExtent( size );
381 const float radius = symbol->
shapeProperty( QStringLiteral(
"radius" ) ).toFloat();
382 const float minorRadius = symbol->
shapeProperty( QStringLiteral(
"minorRadius" ) ).toFloat();
383 Qt3DExtras::QTorusGeometry *g =
new Qt3DExtras::QTorusGeometry;
384 g->setRadius( radius );
385 g->setMinorRadius( minorRadius );
391 const float size = symbol->
shapeProperty( QStringLiteral(
"size" ) ).toFloat();
392 Qt3DExtras::QPlaneGeometry *g =
new Qt3DExtras::QPlaneGeometry;
394 g->setHeight( size );
400 const float depth = symbol->
shapeProperty( QStringLiteral(
"depth" ) ).toFloat();
401 const QString text = symbol->
shapeProperty( QStringLiteral(
"text" ) ).toString();
402 Qt3DExtras::QExtrudedTextGeometry *g =
new Qt3DExtras::QExtrudedTextGeometry;
403 g->setDepth( depth );
419class QgsModelPoint3DSymbolHandler :
public QgsFeature3DHandler
422 QgsModelPoint3DSymbolHandler(
const QgsPoint3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
423 : mSymbol( static_cast<QgsPoint3DSymbol *>( symbol->clone() ) )
424 , mSelectedIds( selectedIds ) {}
426 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsVector3D &chunkOrigin )
override;
427 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
428 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
431 static void addSceneEntities(
const Qgs3DRenderContext &context,
const QVector<QVector3D> &positions,
const QgsVector3D &chunkOrigin,
const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent );
432 static void addMeshEntities(
const Qgs3DRenderContext &context,
const QVector<QVector3D> &positions,
const QgsVector3D &chunkOrigin,
const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent,
bool are_selected );
433 static QgsGeoTransform *transform( QVector3D position,
const QgsPoint3DSymbol *symbol,
const QgsVector3D &chunkOrigin );
438 QVector<QVector3D> positions;
441 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected );
444 std::unique_ptr<QgsPoint3DSymbol> mSymbol;
449 QgsVector3D mChunkOrigin;
453 PointData outSelected;
456bool QgsModelPoint3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsVector3D &chunkOrigin )
459 Q_UNUSED( attributeNames )
461 mChunkOrigin = chunkOrigin;
468 PointData &out = mSelectedIds.contains( feature.
id() ) ? outSelected : outNormal;
477void QgsModelPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
479 makeEntity( parent, context, outNormal,
false );
480 makeEntity( parent, context, outSelected,
true );
482 updateZRangeFromPositions( outNormal.positions );
483 updateZRangeFromPositions( outSelected.positions );
486 const float symbolHeight = mSymbol->transform().data()[14];
487 mZMin += symbolHeight;
488 mZMax += symbolHeight;
491void QgsModelPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected )
493 if ( out.positions.isEmpty() )
500 addMeshEntities( context, out.positions, mChunkOrigin, mSymbol.get(), parent,
true );
505 if ( mSymbol->shapeProperty( QStringLiteral(
"overwriteMaterial" ) ).toBool()
506 || ( mSymbol->materialSettings() && mSymbol->materialSettings()->type() != QLatin1String(
"null" ) ) )
508 addMeshEntities( context, out.positions, mChunkOrigin, mSymbol.get(), parent,
false );
512 addSceneEntities( context, out.positions, mChunkOrigin, mSymbol.get(), parent );
523 if ( !source.isEmpty() )
525 for (
const QVector3D &position : positions )
528 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
530 const QUrl url = QUrl::fromLocalFile( source );
531 Qt3DRender::QSceneLoader *modelLoader =
new Qt3DRender::QSceneLoader;
532 modelLoader->setSource( url );
534 entity->addComponent( modelLoader );
535 entity->addComponent( transform( position, symbol, chunkOrigin ) );
536 entity->setParent( parent );
544 QgsDebugMsgLevel( QStringLiteral(
"File '%1' is not accessible!" ).arg( symbol->
shapeProperty( QStringLiteral(
"model" ) ).toString() ), 1 );
548void QgsModelPoint3DSymbolHandler::addMeshEntities(
const Qgs3DRenderContext &context,
const QVector<QVector3D> &positions,
const QgsVector3D &chunkOrigin,
const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent,
bool are_selected )
550 if ( positions.empty() )
554 if ( !source.isEmpty() )
562 const QUrl url = QUrl::fromLocalFile( source );
565 for (
const QVector3D &position : positions )
568 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
570 Qt3DRender::QMesh *mesh =
new Qt3DRender::QMesh;
571 mesh->setSource( url );
573 entity->addComponent( mesh );
574 entity->addComponent( mat );
575 entity->addComponent( transform( position, symbol, chunkOrigin ) );
576 entity->setParent( parent );
584 QgsDebugMsgLevel( QStringLiteral(
"File '%1' is not accessible!" ).arg( symbol->
shapeProperty( QStringLiteral(
"model" ) ).toString() ), 1 );
588QgsGeoTransform *QgsModelPoint3DSymbolHandler::transform( QVector3D position,
const QgsPoint3DSymbol *symbol,
const QgsVector3D &chunkOrigin )
591 QgsGeoTransform *tr =
new QgsGeoTransform;
593 tr->setGeoTranslation( chunkOrigin + position + tr->translation() );
601class QgsPoint3DBillboardSymbolHandler :
public QgsFeature3DHandler
604 QgsPoint3DBillboardSymbolHandler(
const QgsPoint3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
605 : mSymbol( static_cast<QgsPoint3DSymbol *>( symbol->clone() ) )
606 , mSelectedIds( selectedIds ) {}
608 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsVector3D &chunkOrigin )
override;
609 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
610 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
616 QVector<QVector3D> positions;
619 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected );
622 std::unique_ptr<QgsPoint3DSymbol> mSymbol;
627 QgsVector3D mChunkOrigin;
631 PointData outSelected;
634bool QgsPoint3DBillboardSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsVector3D &chunkOrigin )
637 Q_UNUSED( attributeNames )
639 mChunkOrigin = chunkOrigin;
646 PointData &out = mSelectedIds.contains( feature.
id() ) ? outSelected : outNormal;
655void QgsPoint3DBillboardSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
657 makeEntity( parent, context, outNormal,
false );
658 makeEntity( parent, context, outSelected,
true );
660 updateZRangeFromPositions( outNormal.positions );
661 updateZRangeFromPositions( outSelected.positions );
664 const float billboardHeight = mSymbol->billboardHeight();
665 mZMin += billboardHeight;
666 mZMax += billboardHeight;
669void QgsPoint3DBillboardSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected )
671 if ( out.positions.isEmpty() )
681 Qt3DRender::QGeometryRenderer *billboardGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
682 billboardGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
683 billboardGeometryRenderer->setGeometry( billboardGeometry );
684 billboardGeometryRenderer->setVertexCount( billboardGeometry->
count() );
700 QgsGeoTransform *billboardTransform =
new QgsGeoTransform;
701 billboardTransform->setGeoTranslation( mChunkOrigin +
QgsVector3D( 0, 0, mSymbol->billboardHeight() ) );
704 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
706 entity->addComponent( billboardMaterial );
707 entity->addComponent( billboardTransform );
708 entity->addComponent( billboardGeometryRenderer );
709 entity->setParent( parent );
716namespace Qgs3DSymbolImpl
719 QgsFeature3DHandler *handlerForPoint3DSymbol( QgsVectorLayer *layer,
const QgsAbstract3DSymbol *symbol )
721 const QgsPoint3DSymbol *pointSymbol =
dynamic_cast<const QgsPoint3DSymbol *
>( symbol );
729 return new QgsPoint3DBillboardSymbolHandler( pointSymbol, layer->
selectedFeatureIds() );
731 return new QgsInstancedPoint3DSymbolHandler( pointSymbol, layer->
selectedFeatureIds() );
@ ExtrudedText
Extruded text.
Rendering context for preparation of 3D entities.
QColor selectionColor() const
Returns color used for selected features.
static void extractPointPositions(const QgsFeature &f, const Qgs3DRenderContext &context, const QgsVector3D &chunkOrigin, Qgis::AltitudeClamping altClamp, QVector< QVector3D > &positions)
Calculates (x,y,z) positions of (multi)point from the given feature.
virtual void addParametersToEffect(Qt3DRender::QEffect *effect, const QgsMaterialContext &materialContext) const =0
Adds parameters from the material to a destination effect.
virtual QgsMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const =0
Creates a new QgsMaterial object representing the material settings.
static QgsSourceCache * sourceCache()
Returns the application's source cache, used for caching embedded and remote source strings as local ...
Geometry of the billboard rendering for points in 3D map view.
void setPositions(const QVector< QVector3D > &vertices)
Sets the vertex positions for the billboards.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
A marker symbol type, for rendering Point and MultiPoint geometries.
Context settings for a material.
void setIsSelected(bool isSelected)
Sets whether the material should represent a selected state.
void setSelectionColor(const QColor &color)
Sets the color for representing materials in a selected state.
Base class for all materials used within QGIS 3D views.
Material of the billboard rendering for points in 3D map view.
void useDefaultSymbol(const Qgs3DRenderContext &context, bool selected=false)
Set default symbol for the texture with context and selected parameter for rendering.
void setTexture2DFromSymbol(const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected=false)
Set markerSymbol for the texture with context and selected parameter for rendering.
3D symbol that draws point geometries as 3D objects using one of the predefined shapes.
QgsAbstractMaterialSettings * materialSettings() const
Returns material settings used for shading of the symbol.
QMatrix4x4 transform() const
Returns transform for individual objects represented by the symbol.
QgsMarkerSymbol * billboardSymbol() const
Returns a symbol for billboard.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
QVariant shapeProperty(const QString &property) const
Returns the value for a specific shape property.
QString localFilePath(const QString &path, bool blocking=false)
Returns a local file path reflecting the content of a specified source path.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
@ Triangles
Triangle based rendering (default).
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
Qt3DCore::QGeometry Qt3DQGeometry
QSet< QgsFeatureId > QgsFeatureIds
#define QgsDebugMsgLevel(str, level)