25#include <Qt3DCore/QTransform>
26#include <Qt3DRender/QMaterial>
27#include <Qt3DExtras/QPhongMaterial>
29#include <Qt3DExtras/QDiffuseMapMaterial>
30#include <Qt3DRender/QAbstractTextureImage>
31#include <Qt3DRender/QTexture>
33#include <Qt3DRender/QEffect>
34#include <Qt3DRender/QTechnique>
35#include <Qt3DRender/QCullFace>
36#include <Qt3DRender/QGeometryRenderer>
50class QgsPolygon3DSymbolHandler :
public QgsFeature3DHandler
55 , mSelectedIds( selectedIds ) {}
57 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
58 void processFeature(
const QgsFeature &f,
const Qgs3DRenderContext &context )
override;
59 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
66 std::unique_ptr<QgsTessellator> tessellator;
67 QVector<QgsFeatureId> triangleIndexFids;
68 QVector<uint> triangleIndexStartingIndices;
69 QByteArray materialDataDefined;
72 void processPolygon(
const QgsPolygon *poly,
QgsFeatureId fid,
float offset,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out );
73 void processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, PolygonData &out );
74 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected );
75 Qt3DRender::QMaterial *material(
const QgsPolygon3DSymbol *symbol,
bool isSelected,
const Qgs3DRenderContext &context )
const;
78 std::unique_ptr< QgsPolygon3DSymbol > mSymbol;
83 PolygonData outNormal;
84 PolygonData outSelected;
86 QgsLineVertexData outEdges;
90bool QgsPolygon3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
92 outEdges.withAdjacency =
true;
93 outEdges.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), 0, &context.map() );
97 outNormal.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol->invertNormals(), mSymbol->addBackFaces(),
false,
99 mSymbol->renderedFacade(),
100 texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
101 outSelected.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol->invertNormals(),
102 mSymbol->addBackFaces(),
false,
104 mSymbol->renderedFacade(),
105 texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
108 attributeNames.unite( attrs );
109 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.expressionContext() );
110 attributeNames.unite( attrs );
114void QgsPolygon3DSymbolHandler::processPolygon(
const QgsPolygon *poly,
QgsFeatureId fid,
float offset,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out )
116 std::unique_ptr< QgsPolygon > polyClone( poly->
clone() );
118 const uint oldVerticesCount = out.tessellator->dataVerticesCount();
119 if ( mSymbol->edgesEnabled() )
122 outEdges.addLineString( *
static_cast<const QgsLineString *
>( polyClone->exteriorRing() ), offset );
123 for (
int i = 0; i < polyClone->numInteriorRings(); ++i )
124 outEdges.addLineString( *
static_cast<const QgsLineString *
>( polyClone->interiorRing( i ) ), offset );
126 if ( extrusionHeight )
130 outEdges.addLineString( *exterior, extrusionHeight + offset );
131 outEdges.addVerticalLines( *exterior, extrusionHeight, offset );
132 for (
int i = 0; i < polyClone->numInteriorRings(); ++i )
135 outEdges.addLineString( *interior, extrusionHeight + offset );
136 outEdges.addVerticalLines( *interior, extrusionHeight, offset );
141 Qgs3DUtils::clampAltitudes( polyClone.get(), mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), offset, context.map() );
143 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
144 const uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
145 out.triangleIndexStartingIndices.append( startingTriangleIndex );
146 out.triangleIndexFids.append( fid );
147 out.tessellator->addPolygon( *polyClone, extrusionHeight );
148 if ( !out.tessellator->error().isEmpty() )
153 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
154 processMaterialDatadefined( out.tessellator->dataVerticesCount() - oldVerticesCount, context.expressionContext(), out );
157void QgsPolygon3DSymbolHandler::processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsPolygon3DSymbolHandler::PolygonData &out )
159 const QByteArray bytes = mSymbol->materialSettings()->dataDefinedVertexColorsAsByte( context );
160 out.materialDataDefined.append( bytes.repeated( verticesCount ) );
163void QgsPolygon3DSymbolHandler::processFeature(
const QgsFeature &f,
const Qgs3DRenderContext &context )
168 PolygonData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
184 float offset = mSymbol->offset();
185 float extrusionHeight = mSymbol->extrusionHeight();
188 if ( hasDDExtrusion )
191 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
193 processPolygon( poly, f.
id(), offset, extrusionHeight, context, out );
195 else if (
const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
197 for (
int i = 0; i < mpoly->numGeometries(); ++i )
199 const QgsPolygon *poly = mpoly->polygonN( i );
200 processPolygon( poly, f.
id(), offset, extrusionHeight, context, out );
205 for (
int i = 0; i < gc->numGeometries(); ++i )
211 processPolygon( poly, f.
id(), offset, extrusionHeight, context, out );
216 qWarning() <<
"not a polygon";
221void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
224 makeEntity( parent, context, outNormal,
false );
225 makeEntity( parent, context, outSelected,
true );
227 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
228 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
231 if ( mSymbol->edgesEnabled() && !outEdges.indexes.isEmpty() )
233 QgsLineMaterial *mat =
new QgsLineMaterial;
234 mat->setLineColor( mSymbol->edgeColor() );
235 mat->setLineWidth( mSymbol->edgeWidth() );
237 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
238 entity->setObjectName( parent->objectName() +
"_EDGES" );
241 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
242 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
243 renderer->setGeometry( outEdges.createGeometry( entity ) );
244 renderer->setVertexCount( outEdges.indexes.count() );
245 renderer->setPrimitiveRestartEnabled(
true );
246 renderer->setRestartIndexValue( 0 );
249 entity->addComponent( renderer );
250 entity->addComponent( mat );
251 entity->setParent( parent );
256void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &polyData,
bool selected )
258 if ( polyData.tessellator->dataVerticesCount() == 0 )
261 Qt3DRender::QMaterial *mat = material( mSymbol.get(), selected, context );
264 const QByteArray data(
reinterpret_cast<const char *
>( polyData.tessellator->data().constData() ),
static_cast<int>( polyData.tessellator->data().count() *
sizeof(
float ) ) );
265 const int nVerts = data.count() / polyData.tessellator->stride();
272 geometry->
setData( data, nVerts, polyData.triangleIndexFids, polyData.triangleIndexStartingIndices );
274 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
275 mSymbol->materialSettings()->applyDataDefinedToGeometry( geometry, nVerts, polyData.materialDataDefined );
277 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
278 renderer->setGeometry( geometry );
281 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
282 entity->setObjectName( parent->objectName() +
"_CHUNK_MESH" );
283 entity->addComponent( renderer );
284 entity->addComponent( mat );
285 entity->setParent( parent );
297 const auto techniques = material->effect()->techniques();
298 for (
auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
300 auto renderPasses = ( *tit )->renderPasses();
301 for (
auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
303 Qt3DRender::QCullFace *cullFace =
new Qt3DRender::QCullFace;
305 ( *rpit )->addRenderState( cullFace );
310Qt3DRender::QMaterial *QgsPolygon3DSymbolHandler::material(
const QgsPolygon3DSymbol *symbol,
bool isSelected,
const Qgs3DRenderContext &context )
const
316 const bool dataDefined = mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties();
320 applyCullingMode( symbol->
cullingMode(), material );
328namespace Qgs3DSymbolImpl
335 if ( !polygonSymbol )
@ Main3DRenderer
Renderer for normal entities.
static const char * PROP_NAME_3D_RENDERER_FLAG
Qt property name to hold the 3D geometry renderer flag.
CullingMode
Triangle culling mode.
static Qt3DRender::QCullFace::CullingMode qt3DcullingMode(Qgs3DTypes::CullingMode mode)
Converts Qgs3DTypes::CullingMode mode into its Qt3D equivalent.
static void clampAltitudes(QgsLineString *lineString, Qgis::AltitudeClamping altClamp, Qgis::AltitudeBinding altBind, const QgsPoint ¢roid, float offset, const Qgs3DMapSettings &map)
Clamps altitude of vertices of a linestring according to the settings.
@ ExtrusionHeight
Extrusion height (zero means no extrusion)
@ Height
Height (altitude)
Abstract base class for all geometries.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const
Returns a reference to the simplest lossless representation of this geometry, e.g.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual Qt3DRender::QMaterial * toMaterial(QgsMaterialSettingsRenderingTechnique technique, const QgsMaterialContext &context) const =0
Creates a new QMaterial object representing the material settings.
QgsPropertyCollection dataDefinedProperties() const
Returns the symbol material property collection, used for data defined overrides.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Line string geometry type, with support for z-dimension and m-values.
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.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Multi polygon geometry collection.
bool requiresTextureCoordinates() const
Returns true if the material requires texture coordinates to be generated during triangulation....
float textureRotation() const
Returns the texture rotation, in degrees.
QgsAbstractMaterialSettings * materialSettings() const
Returns material settings used for shading of the symbol.
Qgs3DTypes::CullingMode cullingMode() const
Returns front/back culling mode.
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const final
Returns the set of any fields referenced by the active properties from the collection.
void setData(const QByteArray &vertexBufferData, int vertexCount, const QVector< QgsFeatureId > &triangleIndexFids, const QVector< uint > &triangleIndexStartingIndices)
Initializes vertex buffer (and other members) from data that were already tessellated.
Class that takes care of tessellation of polygons into triangles.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
static bool isCurvedType(Qgis::WkbType type)
Returns true if the WKB type is a curved type or can contain curved geometries.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
QgsMaterialSettingsRenderingTechnique
Material rendering techniques 3.
@ Triangles
Triangle based rendering (default)
@ TrianglesDataDefined
Triangle based rendering with possibility of datadefined color.
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features