33#include <Qt3DCore/QAttribute>
34#include <Qt3DCore/QBuffer>
35#include <Qt3DCore/QGeometry>
36#include <Qt3DExtras/QConeGeometry>
37#include <Qt3DExtras/QCuboidGeometry>
38#include <Qt3DExtras/QCylinderGeometry>
39#include <Qt3DExtras/QExtrudedTextGeometry>
40#include <Qt3DExtras/QPhongMaterial>
41#include <Qt3DExtras/QPlaneGeometry>
42#include <Qt3DExtras/QSphereGeometry>
43#include <Qt3DExtras/QTorusGeometry>
44#include <Qt3DRender/QEffect>
45#include <Qt3DRender/QGraphicsApiFilter>
46#include <Qt3DRender/QMesh>
47#include <Qt3DRender/QPaintedTextureImage>
48#include <Qt3DRender/QParameter>
49#include <Qt3DRender/QSceneLoader>
50#include <Qt3DRender/QTechnique>
52using namespace Qt::StringLiterals;
60class QgsInstancedPoint3DSymbolHandler :
public QgsFeature3DHandler
63 QgsInstancedPoint3DSymbolHandler(
const QgsPoint3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
64 : mSymbol( static_cast<QgsPoint3DSymbol *>( symbol->clone() ) )
65 , mSelectedIds( selectedIds ) {}
67 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
override;
68 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
69 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
72 static QgsMaterial *material(
const QgsPoint3DSymbol *symbol,
const QgsMaterialContext &materialContext );
73 static Qt3DRender::QGeometryRenderer *renderer(
const QgsPoint3DSymbol *symbol,
const QVector<QVector3D> &positions );
74 static Qt3DCore::QGeometry *symbolGeometry(
const QgsPoint3DSymbol *symbol );
79 QVector<QVector3D> positions;
82 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected );
85 std::unique_ptr<QgsPoint3DSymbol> mSymbol;
90 PointData outSelected;
94bool QgsInstancedPoint3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
97 Q_UNUSED( attributeNames )
99 mChunkOrigin = chunkExtent.
center();
100 mChunkExtent = chunkExtent;
107 PointData &out = mSelectedIds.
contains( feature.
id() ) ? outSelected : outNormal;
116void QgsInstancedPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
118 makeEntity( parent, context, outNormal,
false );
119 makeEntity( parent, context, outSelected,
true );
121 updateZRangeFromPositions( outNormal.positions );
122 updateZRangeFromPositions( outSelected.positions );
125 const float symbolOffset = mSymbol->transform().data()[14];
129 switch ( mSymbol->shape() )
133 const float length = mSymbol->shapeProperty( u
"length"_s ).toFloat();
134 mZMin -= length * 0.5f;
135 mZMax += length * 0.5f;
141 const float radius = mSymbol->shapeProperty( u
"radius"_s ).toFloat();
149 const float length = mSymbol->shapeProperty( u
"length"_s ).toFloat();
150 mZMin -= length * 0.5f;
151 mZMax += length * 0.5f;
157 const float size = mSymbol->shapeProperty( u
"size"_s ).toFloat();
158 mZMin -= size * 0.5f;
159 mZMax += size * 0.5f;
165 const float radius = mSymbol->shapeProperty( u
"radius"_s ).toFloat();
175 const float size = mSymbol->shapeProperty( u
"size"_s ).toFloat();
176 mZMin -= size * 0.5f;
177 mZMax += size * 0.5f;
187 mZMin += symbolOffset;
188 mZMax += symbolOffset;
191void QgsInstancedPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected )
193 if ( out.positions.isEmpty() )
203 QgsMaterial *mat = material( mSymbol.get(), materialContext );
206 QgsGeoTransform *tr =
new QgsGeoTransform;
207 tr->setGeoTranslation( mChunkOrigin );
210 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
211 entity->addComponent( renderer( mSymbol.get(), out.positions ) );
212 entity->addComponent( mat );
213 entity->addComponent( tr );
214 entity->setParent( parent );
223 std::unique_ptr<QgsMaterial> material;
231 Qt3DRender::QFilterKey *filterKey =
new Qt3DRender::QFilterKey;
232 filterKey->setName( u
"renderingStyle"_s );
233 filterKey->setValue(
"forward" );
235 Qt3DRender::QShaderProgram *shaderProgram =
new Qt3DRender::QShaderProgram;
236 shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u
"qrc:/shaders/instanced.vert"_s ) ) );
237 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u
"qrc:/shaders/phong.frag"_s ) ) );
239 Qt3DRender::QRenderPass *renderPass =
new Qt3DRender::QRenderPass;
240 renderPass->setShaderProgram( shaderProgram );
242 Qt3DRender::QTechnique *technique =
new Qt3DRender::QTechnique;
243 technique->addFilterKey( filterKey );
244 technique->addRenderPass( renderPass );
245 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
246 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
247 technique->graphicsApiFilter()->setMajorVersion( 3 );
248 technique->graphicsApiFilter()->setMinorVersion( 2 );
250 Qt3DRender::QEffect *effect =
new Qt3DRender::QEffect;
251 effect->addTechnique( technique );
255 material = std::make_unique<QgsMaterial>();
256 material->setEffect( effect );
259 const QMatrix4x4 tempTransformMatrix = symbol->
transform();
263 id.rotate( QQuaternion::fromAxisAndAngle( QVector3D( 1, 0, 0 ), 90 ) );
264 const QMatrix4x4 transformMatrix = tempTransformMatrix * id;
267 QMatrix3x3 normalMatrix = transformMatrix.normalMatrix();
270 float *n = normalMatrix.data();
271 const QMatrix4x4 normalMatrix4(
278 Qt3DRender::QParameter *paramInst =
new Qt3DRender::QParameter;
279 paramInst->setName( u
"inst"_s );
280 paramInst->setValue( transformMatrix );
282 Qt3DRender::QParameter *paramInstNormal =
new Qt3DRender::QParameter;
283 paramInstNormal->setName( u
"instNormal"_s );
284 paramInstNormal->setValue( normalMatrix4 );
286 material->addParameter( paramInst );
287 material->addParameter( paramInstNormal );
289 return material.release();
292Qt3DRender::QGeometryRenderer *QgsInstancedPoint3DSymbolHandler::renderer(
const QgsPoint3DSymbol *symbol,
const QVector<QVector3D> &positions )
294 const int count = positions.count();
295 const int byteCount = positions.count() *
sizeof( QVector3D );
297 ba.resize( byteCount );
298 memcpy( ba.data(), positions.constData(), byteCount );
300 Qt3DCore::QBuffer *instanceBuffer =
new Qt3DCore::QBuffer();
301 instanceBuffer->setData( ba );
303 Qt3DCore::QAttribute *instanceDataAttribute =
new Qt3DCore::QAttribute;
304 instanceDataAttribute->setName( u
"pos"_s );
305 instanceDataAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
306 instanceDataAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
307 instanceDataAttribute->setVertexSize( 3 );
308 instanceDataAttribute->setByteOffset( 0 );
309 instanceDataAttribute->setDivisor( 1 );
310 instanceDataAttribute->setBuffer( instanceBuffer );
311 instanceDataAttribute->setCount( count );
312 instanceDataAttribute->setByteStride( 3 *
sizeof(
float ) );
314 Qt3DCore::QGeometry *geometry = symbolGeometry( symbol );
315 geometry->addAttribute( instanceDataAttribute );
316 geometry->setBoundingVolumePositionAttribute( instanceDataAttribute );
318 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
319 renderer->setGeometry( geometry );
320 renderer->setInstanceCount( count );
325Qt3DCore::QGeometry *QgsInstancedPoint3DSymbolHandler::symbolGeometry(
const QgsPoint3DSymbol *symbol )
327 switch ( symbol->
shape() )
331 const float radius = symbol->
shapeProperty( u
"radius"_s ).toFloat();
332 const float length = symbol->
shapeProperty( u
"length"_s ).toFloat();
333 Qt3DExtras::QCylinderGeometry *g =
new Qt3DExtras::QCylinderGeometry;
336 g->setRadius( radius );
337 g->setLength( length );
343 const float radius = symbol->
shapeProperty( u
"radius"_s ).toFloat();
344 Qt3DExtras::QSphereGeometry *g =
new Qt3DExtras::QSphereGeometry;
345 g->setRadius( radius );
351 const float length = symbol->
shapeProperty( u
"length"_s ).toFloat();
352 const float bottomRadius = symbol->
shapeProperty( u
"bottomRadius"_s ).toFloat();
353 const float topRadius = symbol->
shapeProperty( u
"topRadius"_s ).toFloat();
355 Qt3DExtras::QConeGeometry *g =
new Qt3DExtras::QConeGeometry;
356 g->setLength( length );
357 g->setBottomRadius( bottomRadius );
358 g->setTopRadius( topRadius );
366 const float size = symbol->
shapeProperty( u
"size"_s ).toFloat();
367 Qt3DExtras::QCuboidGeometry *g =
new Qt3DExtras::QCuboidGeometry;
368 g->setXExtent( size );
369 g->setYExtent( size );
370 g->setZExtent( size );
376 const float radius = symbol->
shapeProperty( u
"radius"_s ).toFloat();
377 const float minorRadius = symbol->
shapeProperty( u
"minorRadius"_s ).toFloat();
378 Qt3DExtras::QTorusGeometry *g =
new Qt3DExtras::QTorusGeometry;
379 g->setRadius( radius );
380 g->setMinorRadius( minorRadius );
386 const float size = symbol->
shapeProperty( u
"size"_s ).toFloat();
387 Qt3DExtras::QPlaneGeometry *g =
new Qt3DExtras::QPlaneGeometry;
389 g->setHeight( size );
395 const float depth = symbol->
shapeProperty( u
"depth"_s ).toFloat();
396 const QString text = symbol->
shapeProperty( u
"text"_s ).toString();
397 Qt3DExtras::QExtrudedTextGeometry *g =
new Qt3DExtras::QExtrudedTextGeometry;
398 g->setDepth( depth );
414class QgsModelPoint3DSymbolHandler :
public QgsFeature3DHandler
417 QgsModelPoint3DSymbolHandler(
const QgsPoint3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
418 : mSymbol( static_cast<QgsPoint3DSymbol *>( symbol->clone() ) )
419 , mSelectedIds( selectedIds ) {}
421 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
override;
422 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
423 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
426 static void addSceneEntities(
const Qgs3DRenderContext &context,
const QVector<QVector3D> &positions,
const QgsVector3D &chunkOrigin,
const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent );
427 static void addMeshEntities(
const Qgs3DRenderContext &context,
const QVector<QVector3D> &positions,
const QgsVector3D &chunkOrigin,
const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent,
bool areSelected,
bool areHighlighted );
428 static QgsGeoTransform *transform( QVector3D position,
const QgsPoint3DSymbol *symbol,
const QgsVector3D &chunkOrigin );
433 QVector<QVector3D> positions;
436 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected );
439 std::unique_ptr<QgsPoint3DSymbol> mSymbol;
444 PointData outSelected;
447bool QgsModelPoint3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
450 Q_UNUSED( attributeNames )
452 mChunkOrigin = chunkExtent.
center();
453 mChunkExtent = chunkExtent;
460 PointData &out = mSelectedIds.contains( feature.
id() ) ? outSelected : outNormal;
469void QgsModelPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
471 makeEntity( parent, context, outNormal,
false );
472 makeEntity( parent, context, outSelected,
true );
474 updateZRangeFromPositions( outNormal.positions );
475 updateZRangeFromPositions( outSelected.positions );
478 const float symbolHeight = mSymbol->transform().data()[14];
479 mZMin += symbolHeight;
480 mZMax += symbolHeight;
483void QgsModelPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected )
485 if ( out.positions.isEmpty() )
492 addMeshEntities( context, out.positions, mChunkOrigin, mSymbol.get(), parent,
true, mHighlightingEnabled );
497 if ( mSymbol->shapeProperty( u
"overwriteMaterial"_s ).toBool()
498 || ( mSymbol->materialSettings() && mSymbol->materialSettings()->type() !=
"null"_L1 )
499 || mHighlightingEnabled )
501 addMeshEntities( context, out.positions, mChunkOrigin, mSymbol.get(), parent,
false, mHighlightingEnabled );
505 addSceneEntities( context, out.positions, mChunkOrigin, mSymbol.get(), parent );
516 if ( !source.isEmpty() )
518 for (
const QVector3D &position : positions )
521 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
523 const QUrl url = QUrl::fromLocalFile( source );
524 Qt3DRender::QSceneLoader *modelLoader =
new Qt3DRender::QSceneLoader;
525 modelLoader->setSource( url );
527 entity->addComponent( modelLoader );
528 entity->addComponent( transform( position, symbol, chunkOrigin ) );
529 entity->setParent( parent );
541void QgsModelPoint3DSymbolHandler::addMeshEntities(
const Qgs3DRenderContext &context,
const QVector<QVector3D> &positions,
const QgsVector3D &chunkOrigin,
const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent,
bool areSelected,
bool areHighlighted )
543 if ( positions.empty() )
547 if ( !source.isEmpty() )
559 const QUrl url = QUrl::fromLocalFile( source );
562 for (
const QVector3D &position : positions )
565 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
567 Qt3DRender::QMesh *mesh =
new Qt3DRender::QMesh;
568 mesh->setSource( url );
570 entity->addComponent( mesh );
571 entity->addComponent( mat );
572 entity->addComponent( transform( position, symbol, chunkOrigin ) );
573 entity->setParent( parent );
585QgsGeoTransform *QgsModelPoint3DSymbolHandler::transform( QVector3D position,
const QgsPoint3DSymbol *symbol,
const QgsVector3D &chunkOrigin )
588 QgsGeoTransform *tr =
new QgsGeoTransform;
590 tr->setGeoTranslation( chunkOrigin + position + tr->translation() );
598class QgsPoint3DBillboardSymbolHandler :
public QgsFeature3DHandler
601 QgsPoint3DBillboardSymbolHandler(
const QgsPoint3DSymbol *symbol,
const QgsFeatureIds &selectedIds )
602 : mSymbol( static_cast<QgsPoint3DSymbol *>( symbol->clone() ) )
603 , mSelectedIds( selectedIds ) {}
605 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
override;
606 void processFeature(
const QgsFeature &feature,
const Qgs3DRenderContext &context )
override;
607 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
613 QVector<QVector3D> positions;
616 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected );
619 std::unique_ptr<QgsPoint3DSymbol> mSymbol;
624 PointData outSelected;
627bool QgsPoint3DBillboardSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames,
const QgsBox3D &chunkExtent )
630 Q_UNUSED( attributeNames )
632 mChunkOrigin = chunkExtent.
center();
633 mChunkExtent = chunkExtent;
640 PointData &out = mSelectedIds.contains( feature.
id() ) ? outSelected : outNormal;
649void QgsPoint3DBillboardSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
651 makeEntity( parent, context, outNormal,
false );
652 makeEntity( parent, context, outSelected,
true );
654 updateZRangeFromPositions( outNormal.positions );
655 updateZRangeFromPositions( outSelected.positions );
658 const float billboardHeight = mSymbol->billboardHeight();
659 mZMin += billboardHeight;
660 mZMax += billboardHeight;
663void QgsPoint3DBillboardSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PointData &out,
bool selected )
665 if ( out.positions.isEmpty() )
675 Qt3DRender::QGeometryRenderer *billboardGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
676 billboardGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::Points );
677 billboardGeometryRenderer->setGeometry( billboardGeometry );
678 billboardGeometryRenderer->setVertexCount( billboardGeometry->
count() );
694 QgsGeoTransform *billboardTransform =
new QgsGeoTransform;
695 billboardTransform->setGeoTranslation( mChunkOrigin +
QgsVector3D( 0, 0, mSymbol->billboardHeight() ) );
698 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
700 entity->addComponent( billboardMaterial );
701 entity->addComponent( billboardTransform );
702 entity->addComponent( billboardGeometryRenderer );
703 entity->setParent( parent );
710namespace Qgs3DSymbolImpl
713 QgsFeature3DHandler *handlerForPoint3DSymbol( QgsVectorLayer *layer,
const QgsAbstract3DSymbol *symbol )
715 const QgsPoint3DSymbol *pointSymbol =
dynamic_cast<const QgsPoint3DSymbol *
>( symbol );
723 return new QgsPoint3DBillboardSymbolHandler( pointSymbol, layer->
selectedFeatureIds() );
725 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.
A 3-dimensional box composed of x, y, z coordinates.
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
QgsVector3D center() const
Returns the center of the box as a vector.
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.
bool isHighlighted() const
Returns true if the material should represent a highlighted state.
void setIsHighlighted(bool isHighlighted)
Sets whether the material should represent a highlighted 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).
@ InstancedPoints
Instanced based rendering, requiring triangles and point data.
QSet< QgsFeatureId > QgsFeatureIds
#define QgsDebugMsgLevel(str, level)