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>
49class QgsPolygon3DSymbolHandler :
public QgsFeature3DHandler
54 , mSelectedIds( selectedIds ) {}
56 bool prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
override;
57 void processFeature(
const QgsFeature &f,
const Qgs3DRenderContext &context )
override;
58 void finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
override;
65 std::unique_ptr<QgsTessellator> tessellator;
66 QVector<QgsFeatureId> triangleIndexFids;
67 QVector<uint> triangleIndexStartingIndices;
68 QByteArray materialDataDefined;
71 void processPolygon(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out );
72 void processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, PolygonData &out );
73 void makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected );
74 Qt3DRender::QMaterial *material(
const QgsPolygon3DSymbol *symbol,
bool isSelected,
const Qgs3DRenderContext &context )
const;
77 std::unique_ptr< QgsPolygon3DSymbol > mSymbol;
82 PolygonData outNormal;
83 PolygonData outSelected;
85 QgsLineVertexData outEdges;
89bool QgsPolygon3DSymbolHandler::prepare(
const Qgs3DRenderContext &context, QSet<QString> &attributeNames )
91 outEdges.withAdjacency =
true;
92 outEdges.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), 0, &context.map() );
96 outNormal.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol->invertNormals(), mSymbol->addBackFaces(),
false,
98 mSymbol->renderedFacade(),
99 texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
100 outSelected.tessellator.reset(
new QgsTessellator( context.map().origin().x(), context.map().origin().y(),
true, mSymbol->invertNormals(),
101 mSymbol->addBackFaces(),
false,
103 mSymbol->renderedFacade(),
104 texturedMaterialSettings ? texturedMaterialSettings->
textureRotation() : 0 ) );
107 attributeNames.unite( attrs );
108 attrs = mSymbol->materialSettings()->dataDefinedProperties().referencedFields( context.expressionContext() );
109 attributeNames.unite( attrs );
113void QgsPolygon3DSymbolHandler::processPolygon(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out )
115 const uint oldVerticesCount = out.tessellator->dataVerticesCount();
116 if ( mSymbol->edgesEnabled() )
123 if ( extrusionHeight )
127 outEdges.addLineString( *exterior, extrusionHeight + height );
128 outEdges.addVerticalLines( *exterior, extrusionHeight, height );
132 outEdges.addLineString( *interior, extrusionHeight + height );
133 outEdges.addVerticalLines( *interior, extrusionHeight, height );
140 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
141 const uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
142 out.triangleIndexStartingIndices.append( startingTriangleIndex );
143 out.triangleIndexFids.append( fid );
144 out.tessellator->addPolygon( *polyClone, extrusionHeight );
147 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
148 processMaterialDatadefined( out.tessellator->dataVerticesCount() - oldVerticesCount, context.expressionContext(), out );
151void QgsPolygon3DSymbolHandler::processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsPolygon3DSymbolHandler::PolygonData &out )
153 const QByteArray bytes = mSymbol->materialSettings()->dataDefinedVertexColorsAsByte( context );
154 out.materialDataDefined.append( bytes.repeated( verticesCount ) );
157void QgsPolygon3DSymbolHandler::processFeature(
const QgsFeature &f,
const Qgs3DRenderContext &context )
162 PolygonData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
178 float height = mSymbol->height();
179 float extrusionHeight = mSymbol->extrusionHeight();
182 if ( hasDDExtrusion )
185 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
188 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
190 else if (
const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
192 for (
int i = 0; i < mpoly->numGeometries(); ++i )
195 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
200 for (
int i = 0; i < gc->numGeometries(); ++i )
206 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
211 qWarning() <<
"not a polygon";
216void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
219 makeEntity( parent, context, outNormal,
false );
220 makeEntity( parent, context, outSelected,
true );
222 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
223 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
226 if ( mSymbol->edgesEnabled() && !outEdges.indexes.isEmpty() )
228 QgsLineMaterial *mat =
new QgsLineMaterial;
229 mat->setLineColor( mSymbol->edgeColor() );
230 mat->setLineWidth( mSymbol->edgeWidth() );
232 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
233 entity->setObjectName( parent->objectName() +
"_EDGES" );
236 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
237 renderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::LineStripAdjacency );
238 renderer->setGeometry( outEdges.createGeometry( entity ) );
239 renderer->setVertexCount( outEdges.indexes.count() );
240 renderer->setPrimitiveRestartEnabled(
true );
241 renderer->setRestartIndexValue( 0 );
244 entity->addComponent( renderer );
245 entity->addComponent( mat );
246 entity->setParent( parent );
251void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &polyData,
bool selected )
253 if ( polyData.tessellator->dataVerticesCount() == 0 )
256 Qt3DRender::QMaterial *mat = material( mSymbol.get(), selected, context );
259 const QByteArray data(
reinterpret_cast<const char *
>( polyData.tessellator->data().constData() ),
static_cast<int>( polyData.tessellator->data().count() *
sizeof(
float ) ) );
260 const int nVerts = data.count() / polyData.tessellator->stride();
267 geometry->
setData( data, nVerts, polyData.triangleIndexFids, polyData.triangleIndexStartingIndices );
269 if ( mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties() )
270 mSymbol->materialSettings()->applyDataDefinedToGeometry( geometry, nVerts, polyData.materialDataDefined );
272 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
273 renderer->setGeometry( geometry );
276 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
277 entity->setObjectName( parent->objectName() +
"_CHUNK_MESH" );
278 entity->addComponent( renderer );
279 entity->addComponent( mat );
280 entity->setParent( parent );
299 return Qt3DRender::QCullFace::NoCulling;
305 const auto techniques = material->effect()->techniques();
306 for (
auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
308 auto renderPasses = ( *tit )->renderPasses();
309 for (
auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
311 Qt3DRender::QCullFace *cullFace =
new Qt3DRender::QCullFace;
312 cullFace->setMode( _qt3DcullingMode( cullingMode ) );
313 ( *rpit )->addRenderState( cullFace );
318Qt3DRender::QMaterial *QgsPolygon3DSymbolHandler::material(
const QgsPolygon3DSymbol *symbol,
bool isSelected,
const Qgs3DRenderContext &context )
const
324 const bool dataDefined = mSymbol->materialSettings()->dataDefinedProperties().hasActiveProperties();
328 applyCullingMode( symbol->
cullingMode(), material );
336namespace Qgs3DSymbolImpl
343 if ( !polygonSymbol )
351 QgsFeature3DHandler *handler = handlerForPolygon3DSymbol( layer, &symbol );
352 Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );
@ 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.
@ FrontAndBack
Will not render anything.
@ NoCulling
Will render both front and back faces of triangles.
@ Front
Will render only back faces of triangles.
@ Back
Will render only front faces of triangles (recommended when input data are consistent)
static void clampAltitudes(QgsLineString *lineString, Qgis::AltitudeClamping altClamp, Qgis::AltitudeBinding altBind, const QgsPoint ¢roid, float height, const Qgs3DMapSettings &map)
Clamps altitude of vertices of a linestring according to the settings.
@ PropertyHeight
Height (altitude)
@ PropertyExtrusionHeight
Extrusion height (zero means no extrusion)
Abstract base class for all geometries.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const SIP_HOLDGIL
Returns a reference to the simplest lossless representation of this geometry, e.g.
Qgis::WkbType wkbType() const SIP_HOLDGIL
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.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
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 SIP_HOLDGIL
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.
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.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const override
Returns the set of any fields referenced by the active properties from the collection.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
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) SIP_HOLDGIL
Returns true if the WKB type is a curved type or can contain curved geometries.
static Qgis::WkbType flatType(Qgis::WkbType type) SIP_HOLDGIL
Returns the flat type for a WKB type.
@ 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