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>
50 class 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(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
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;
90 bool 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->material()->dataDefinedProperties().referencedFields( context.expressionContext() );
110 attributeNames.unite( attrs );
114 void QgsPolygon3DSymbolHandler::processPolygon(
QgsPolygon *polyClone,
QgsFeatureId fid,
float height,
float extrusionHeight,
const Qgs3DRenderContext &context, PolygonData &out )
116 const uint oldVerticesCount = out.tessellator->dataVerticesCount();
117 if ( mSymbol->edgesEnabled() )
124 if ( extrusionHeight )
128 outEdges.addLineString( *exterior, extrusionHeight + height );
129 outEdges.addVerticalLines( *exterior, extrusionHeight, height );
133 outEdges.addLineString( *interior, extrusionHeight + height );
134 outEdges.addVerticalLines( *interior, extrusionHeight, height );
141 Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 );
142 const uint startingTriangleIndex =
static_cast<uint
>( out.tessellator->dataVerticesCount() / 3 );
143 out.triangleIndexStartingIndices.append( startingTriangleIndex );
144 out.triangleIndexFids.append( fid );
145 out.tessellator->addPolygon( *polyClone, extrusionHeight );
148 if ( mSymbol->material()->dataDefinedProperties().hasActiveProperties() )
149 processMaterialDatadefined( out.tessellator->dataVerticesCount() - oldVerticesCount, context.expressionContext(), out );
152 void QgsPolygon3DSymbolHandler::processMaterialDatadefined( uint verticesCount,
const QgsExpressionContext &context, QgsPolygon3DSymbolHandler::PolygonData &out )
154 const QByteArray bytes = mSymbol->material()->dataDefinedVertexColorsAsByte( context );
155 out.materialDataDefined.append( bytes.repeated( verticesCount ) );
158 void QgsPolygon3DSymbolHandler::processFeature(
const QgsFeature &f,
const Qgs3DRenderContext &context )
163 PolygonData &out = mSelectedIds.contains( f.
id() ) ? outSelected : outNormal;
179 float height = mSymbol->height();
180 float extrusionHeight = mSymbol->extrusionHeight();
183 if ( hasDDExtrusion )
186 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon *>( g ) )
189 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
191 else if (
const QgsMultiPolygon *mpoly = qgsgeometry_cast< const QgsMultiPolygon *>( g ) )
193 for (
int i = 0; i < mpoly->numGeometries(); ++i )
196 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
201 for (
int i = 0; i < gc->numGeometries(); ++i )
207 processPolygon( polyClone, f.
id(), height, extrusionHeight, context, out );
212 qWarning() <<
"not a polygon";
217 void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context )
220 makeEntity( parent, context, outNormal,
false );
221 makeEntity( parent, context, outSelected,
true );
223 mZMin = std::min( outNormal.tessellator->zMinimum(), outSelected.tessellator->zMinimum() );
224 mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() );
227 if ( mSymbol->edgesEnabled() && !outEdges.indexes.isEmpty() )
229 QgsLineMaterial *mat =
new QgsLineMaterial;
230 mat->setLineColor( mSymbol->edgeColor() );
231 mat->setLineWidth( mSymbol->edgeWidth() );
233 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
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 );
251 void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent,
const Qgs3DRenderContext &context, PolygonData &out,
bool selected )
253 if ( out.tessellator->dataVerticesCount() == 0 )
256 Qt3DRender::QMaterial *mat = material( mSymbol.get(), selected, context );
259 const QByteArray data( (
const char * )out.tessellator->data().constData(), out.tessellator->data().count() *
sizeof(
float ) );
260 const int nVerts = data.count() / out.tessellator->stride();
266 geometry->
setData( data, nVerts, out.triangleIndexFids, out.triangleIndexStartingIndices );
267 if ( mSymbol->material()->dataDefinedProperties().hasActiveProperties() )
268 mSymbol->material()->applyDataDefinedToGeometry( geometry, nVerts, out.materialDataDefined );
270 Qt3DRender::QGeometryRenderer *renderer =
new Qt3DRender::QGeometryRenderer;
271 renderer->setGeometry( geometry );
274 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity;
275 entity->addComponent( renderer );
276 entity->addComponent( mat );
277 entity->setParent( parent );
280 entity->findChild<Qt3DRender::QGeometryRenderer *>()->setObjectName( QStringLiteral(
"main" ) );
295 return Qt3DRender::QCullFace::NoCulling;
301 const auto techniques = material->effect()->techniques();
302 for (
auto tit = techniques.constBegin(); tit != techniques.constEnd(); ++tit )
304 auto renderPasses = ( *tit )->renderPasses();
305 for (
auto rpit = renderPasses.begin(); rpit != renderPasses.end(); ++rpit )
307 Qt3DRender::QCullFace *cullFace =
new Qt3DRender::QCullFace;
308 cullFace->setMode( _qt3DcullingMode( cullingMode ) );
309 ( *rpit )->addRenderState( cullFace );
314 Qt3DRender::QMaterial *QgsPolygon3DSymbolHandler::material(
const QgsPolygon3DSymbol *symbol,
bool isSelected,
const Qgs3DRenderContext &context )
const
320 const bool dataDefined = mSymbol->material()->dataDefinedProperties().hasActiveProperties();
324 applyCullingMode( symbol->
cullingMode(), material );
332 namespace Qgs3DSymbolImpl
339 if ( !polygonSymbol )
347 QgsFeature3DHandler *handler = handlerForPolygon3DSymbol( layer, &symbol );
348 Qt3DCore::QEntity *e = entityFromHandler( handler, map, layer );