diff --git a/src/3d/qgstessellatedpolygongeometry.cpp b/src/3d/qgstessellatedpolygongeometry.cpp index 50272926228..1441d820637 100644 --- a/src/3d/qgstessellatedpolygongeometry.cpp +++ b/src/3d/qgstessellatedpolygongeometry.cpp @@ -62,7 +62,7 @@ QgsTessellatedPolygonGeometry::~QgsTessellatedPolygonGeometry() void QgsTessellatedPolygonGeometry::setPolygons( const QList &polygons, const QgsPointXY &origin, float extrusionHeight, const QList &extrusionHeightPerPolygon ) { - QgsTessellator tessellator( origin.x(), origin.y(), mWithNormals ); + QgsTessellator tessellator( origin.x(), origin.y(), mWithNormals, mInvertNormals ); for ( int i = 0; i < polygons.count(); ++i ) { QgsPolygon *polygon = polygons.at( i ); diff --git a/src/3d/qgstessellatedpolygongeometry.h b/src/3d/qgstessellatedpolygongeometry.h index 8c49c38668f..16a6ae4c419 100644 --- a/src/3d/qgstessellatedpolygongeometry.h +++ b/src/3d/qgstessellatedpolygongeometry.h @@ -41,6 +41,11 @@ class QgsTessellatedPolygonGeometry : public Qt3DRender::QGeometry QgsTessellatedPolygonGeometry( QNode *parent = nullptr ); ~QgsTessellatedPolygonGeometry(); + //! Returns whether the normals of triangles will be inverted (useful for fixing clockwise / counter-clockwise face vertex orders) + bool invertNormals() const { return mInvertNormals; } + //! Sets whether the normals of triangles will be inverted (useful for fixing clockwise / counter-clockwise face vertex orders) + void setInvertNormals( bool invert ) { mInvertNormals = invert; } + //! Initializes vertex buffer from given polygons. Takes ownership of passed polygon geometries void setPolygons( const QList &polygons, const QgsPointXY &origin, float extrusionHeight, const QList &extrusionHeightPerPolygon = QList() ); @@ -51,6 +56,7 @@ class QgsTessellatedPolygonGeometry : public Qt3DRender::QGeometry Qt3DRender::QBuffer *mVertexBuffer = nullptr; bool mWithNormals = true; + bool mInvertNormals = false; }; #endif // QGSTESSELLATEDPOLYGONGEOMETRY_H diff --git a/src/3d/qgstessellator.cpp b/src/3d/qgstessellator.cpp index 0ba19fca2ba..11bc8ca6ab9 100644 --- a/src/3d/qgstessellator.cpp +++ b/src/3d/qgstessellator.cpp @@ -31,6 +31,7 @@ #include #include + static void make_quad( float x0, float y0, float z0, float x1, float y1, float z1, float height, QVector &data, bool addNormals ) { float dx = x1 - x0; @@ -65,10 +66,11 @@ static void make_quad( float x0, float y0, float z0, float x1, float y1, float z } -QgsTessellator::QgsTessellator( double originX, double originY, bool addNormals ) +QgsTessellator::QgsTessellator( double originX, double originY, bool addNormals, bool invertNormals ) : mOriginX( originX ) , mOriginY( originY ) , mAddNormals( addNormals ) + , mInvertNormals( invertNormals ) { mStride = 3 * sizeof( float ); if ( addNormals ) @@ -118,7 +120,7 @@ static void _makeWalls( const QgsCurve &ring, bool ccw, float extrusionHeight, Q } } -static QVector3D _calculateNormal( const QgsCurve *curve, double originX, double originY ) +static QVector3D _calculateNormal( const QgsCurve *curve, double originX, double originY, bool invertNormal ) { QgsVertexId::VertexType vt; QgsPoint pt1, pt2; @@ -171,7 +173,8 @@ static QVector3D _calculateNormal( const QgsCurve *curve, double originX, double } QVector3D normal( nx, ny, nz ); - //normal = -normal; // TODO: some datasets seem to work better with, others without inversion + if ( invertNormal ) + normal = -normal; normal.normalize(); return normal; } @@ -320,7 +323,7 @@ void QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeigh { const QgsCurve *exterior = polygon.exteriorRing(); - const QVector3D pNormal = _calculateNormal( exterior, mOriginX, mOriginY ); + const QVector3D pNormal = _calculateNormal( exterior, mOriginX, mOriginY, mInvertNormals ); const int pCount = exterior->numPoints(); if ( pCount == 4 && polygon.numInteriorRings() == 0 ) diff --git a/src/3d/qgstessellator.h b/src/3d/qgstessellator.h index b10c4c78c73..a72376dcabb 100644 --- a/src/3d/qgstessellator.h +++ b/src/3d/qgstessellator.h @@ -39,7 +39,7 @@ class _3D_EXPORT QgsTessellator { public: //! Creates tessellator with a specified origin point of the world (in map coordinates) - QgsTessellator( double originX, double originY, bool addNormals ); + QgsTessellator( double originX, double originY, bool addNormals, bool invertNormals = false ); //! Tessellates a triangle and adds its vertex entries to the output data array void addPolygon( const QgsPolygon &polygon, float extrusionHeight ); @@ -57,6 +57,7 @@ class _3D_EXPORT QgsTessellator private: double mOriginX, mOriginY; bool mAddNormals; + bool mInvertNormals; QVector mData; int mStride; }; diff --git a/src/3d/symbols/qgspolygon3dsymbol.cpp b/src/3d/symbols/qgspolygon3dsymbol.cpp index 3ddca251d10..38fe0555b7d 100644 --- a/src/3d/symbols/qgspolygon3dsymbol.cpp +++ b/src/3d/symbols/qgspolygon3dsymbol.cpp @@ -32,6 +32,7 @@ void QgsPolygon3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteContext elemDataProperties.setAttribute( QStringLiteral( "height" ), mHeight ); elemDataProperties.setAttribute( QStringLiteral( "extrusion-height" ), mExtrusionHeight ); elemDataProperties.setAttribute( QStringLiteral( "culling-mode" ), Qgs3DUtils::cullingModeToString( mCullingMode ) ); + elemDataProperties.setAttribute( QStringLiteral( "invert-normals" ), mInvertNormals ? "1" : "0" ); elem.appendChild( elemDataProperties ); QDomElement elemMaterial = doc.createElement( QStringLiteral( "material" ) ); @@ -53,6 +54,7 @@ void QgsPolygon3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteCon mHeight = elemDataProperties.attribute( QStringLiteral( "height" ) ).toFloat(); mExtrusionHeight = elemDataProperties.attribute( QStringLiteral( "extrusion-height" ) ).toFloat(); mCullingMode = Qgs3DUtils::cullingModeFromString( elemDataProperties.attribute( QStringLiteral( "culling-mode" ) ) ); + mInvertNormals = elemDataProperties.attribute( QStringLiteral( "invert-normals" ) ).toInt(); QDomElement elemMaterial = elem.firstChildElement( QStringLiteral( "material" ) ); mMaterial.readXml( elemMaterial ); diff --git a/src/3d/symbols/qgspolygon3dsymbol.h b/src/3d/symbols/qgspolygon3dsymbol.h index 0b32d351476..8c23faaabd7 100644 --- a/src/3d/symbols/qgspolygon3dsymbol.h +++ b/src/3d/symbols/qgspolygon3dsymbol.h @@ -71,6 +71,11 @@ class _3D_EXPORT QgsPolygon3DSymbol : public QgsAbstract3DSymbol //! Sets front/back culling mode void setCullingMode( Qt3DRender::QCullFace::CullingMode mode ) { mCullingMode = mode; } + //! Returns whether the normals of triangles will be inverted (useful for fixing clockwise / counter-clockwise face vertex orders) + bool invertNormals() const { return mInvertNormals; } + //! Sets whether the normals of triangles will be inverted (useful for fixing clockwise / counter-clockwise face vertex orders) + void setInvertNormals( bool invert ) { mInvertNormals = invert; } + private: //! how to handle altitude of vector features AltitudeClamping mAltClamping = AltClampRelative; @@ -81,6 +86,7 @@ class _3D_EXPORT QgsPolygon3DSymbol : public QgsAbstract3DSymbol float mExtrusionHeight = 0.0f; //!< How much to extrude (0 means no walls) QgsPhongMaterialSettings mMaterial; //!< Defines appearance of objects Qt3DRender::QCullFace::CullingMode mCullingMode = Qt3DRender::QCullFace::NoCulling; //!< Front/back culling mode + bool mInvertNormals = false; }; diff --git a/src/3d/symbols/qgspolygon3dsymbol_p.cpp b/src/3d/symbols/qgspolygon3dsymbol_p.cpp index 2204a12f74e..d5894c8eb01 100644 --- a/src/3d/symbols/qgspolygon3dsymbol_p.cpp +++ b/src/3d/symbols/qgspolygon3dsymbol_p.cpp @@ -199,6 +199,7 @@ Qt3DRender::QGeometryRenderer *QgsPolygon3DSymbolEntityNode::renderer( const Qgs } mGeometry = new QgsTessellatedPolygonGeometry; + mGeometry->setInvertNormals( symbol.invertNormals() ); mGeometry->setPolygons( polygons, origin, symbol.extrusionHeight(), extrusionHeightPerPolygon ); Qt3DRender::QGeometryRenderer *renderer = new Qt3DRender::QGeometryRenderer; diff --git a/src/app/3d/qgspolygon3dsymbolwidget.cpp b/src/app/3d/qgspolygon3dsymbolwidget.cpp index 29ed2403301..6d5facc2550 100644 --- a/src/app/3d/qgspolygon3dsymbolwidget.cpp +++ b/src/app/3d/qgspolygon3dsymbolwidget.cpp @@ -32,6 +32,7 @@ QgsPolygon3DSymbolWidget::QgsPolygon3DSymbolWidget( QWidget *parent ) connect( cboAltClamping, static_cast( &QComboBox::currentIndexChanged ), this, &QgsPolygon3DSymbolWidget::changed ); connect( cboAltBinding, static_cast( &QComboBox::currentIndexChanged ), this, &QgsPolygon3DSymbolWidget::changed ); connect( cboCullingMode, static_cast( &QComboBox::currentIndexChanged ), this, &QgsPolygon3DSymbolWidget::changed ); + connect( chkInvertNormals, &QCheckBox::clicked, this, &QgsPolygon3DSymbolWidget::changed ); connect( widgetMaterial, &QgsPhongMaterialWidget::changed, this, &QgsPolygon3DSymbolWidget::changed ); connect( btnHeightDD, &QgsPropertyOverrideButton::changed, this, &QgsPolygon3DSymbolWidget::changed ); connect( btnExtrusionDD, &QgsPropertyOverrideButton::changed, this, &QgsPolygon3DSymbolWidget::changed ); @@ -70,6 +71,7 @@ void QgsPolygon3DSymbolWidget::setSymbol( const QgsPolygon3DSymbol &symbol, QgsV cboAltClamping->setCurrentIndex( ( int ) symbol.altitudeClamping() ); cboAltBinding->setCurrentIndex( ( int ) symbol.altitudeBinding() ); cboCullingMode->setCurrentIndex( _cullingModeToIndex( symbol.cullingMode() ) ); + chkInvertNormals->setChecked( symbol.invertNormals() ); widgetMaterial->setMaterial( symbol.material() ); btnHeightDD->init( QgsAbstract3DSymbol::PropertyHeight, symbol.dataDefinedProperties(), QgsAbstract3DSymbol::propertyDefinitions(), layer, true ); @@ -84,6 +86,7 @@ QgsPolygon3DSymbol QgsPolygon3DSymbolWidget::symbol() const sym.setAltitudeClamping( ( AltitudeClamping ) cboAltClamping->currentIndex() ); sym.setAltitudeBinding( ( AltitudeBinding ) cboAltBinding->currentIndex() ); sym.setCullingMode( _cullingModeFromIndex( cboCullingMode->currentIndex() ) ); + sym.setInvertNormals( chkInvertNormals->isChecked() ); sym.setMaterial( widgetMaterial->material() ); QgsPropertyCollection ddp; diff --git a/src/ui/3d/polygon3dsymbolwidget.ui b/src/ui/3d/polygon3dsymbolwidget.ui index 5ddee6e7335..f7ad21ea8c6 100644 --- a/src/ui/3d/polygon3dsymbolwidget.ui +++ b/src/ui/3d/polygon3dsymbolwidget.ui @@ -14,6 +14,46 @@ Form + + + + Culling Mode + + + + + + + + No culling + + + + + Front + + + + + Back + + + + + + + + ... + + + + + + + Height + + + @@ -45,44 +85,6 @@ - - - - ... - - - - - - - Height - - - - - - - - Vertex - - - - - Centroid - - - - - - - - - - - Qt::Horizontal - - - @@ -116,30 +118,35 @@ - - - - Culling Mode + + + + + Vertex + + + + + Centroid + + + + + + + + + + + Qt::Horizontal - - - - - No culling - - - - - Front - - - - - Back - - + + + + Invert Normals (Experimental) +