Skip to content

Commit

Permalink
arrows for 3D mesh layer dataset rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
vcloarec authored and PeterPetrik committed Mar 11, 2020
1 parent d16ee22 commit 42bc065
Show file tree
Hide file tree
Showing 23 changed files with 690 additions and 78 deletions.
1 change: 1 addition & 0 deletions images/images.qrc
Expand Up @@ -710,6 +710,7 @@
<file>themes/default/mesh/Sigma.svg</file>
<file>themes/default/mesh/SingleTop.svg</file>
<file>themes/default/mesh/SingleBottom.svg</file>
<file>themes/default/mesh/arrow.png</file>
<file>themes/default/mActionNew3DMap.svg</file>
<file>themes/default/mActionNewMap.svg</file>
<file>themes/default/mActionNext.svg</file>
Expand Down
Binary file added images/themes/default/mesh/arrow.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/3d/mesh/qgsmesh3dentity_p.cpp
Expand Up @@ -67,7 +67,7 @@ void QgsMeshDataset3dEntity::applyMaterial()
if ( datasetIndex.isValid() )
mSymbol.setColorRampShader( rendererSettings.scalarSettings( datasetIndex.group() ).colorRampShader() );
}
QgsMesh3dMaterial *material = new QgsMesh3dMaterial( mSymbol, QgsMesh3dMaterial::ScalarDataSet );
QgsMesh3dMaterial *material = new QgsMesh3dMaterial( layer(), mMapSettings.origin(), mSymbol, QgsMesh3dMaterial::ScalarDataSet );
addComponent( material );
}

Expand All @@ -93,7 +93,7 @@ void QgsMesh3dTerrainTileEntity::buildGeometry()

void QgsMesh3dTerrainTileEntity::applyMaterial()
{
QgsMesh3dMaterial *material = new QgsMesh3dMaterial( mSymbol, QgsMesh3dMaterial::ZValue );
QgsMesh3dMaterial *material = new QgsMesh3dMaterial( layer(), mMapSettings.origin(), mSymbol, QgsMesh3dMaterial::ZValue );
addComponent( material );
}

Expand Down
2 changes: 0 additions & 2 deletions src/3d/mesh/qgsmesh3dgeometry_p.cpp
Expand Up @@ -354,8 +354,6 @@ void QgsMeshDataset3dGeometry::init()

QgsTriangularMesh triangularMesh = *layer->triangularMesh();

//Extract data from render cache

if ( verticaleMagnitude.count() != triangularMesh.vertices().count() ||
scalarMagnitude.count() != triangularMesh.vertices().count() )
return;
Expand Down
170 changes: 165 additions & 5 deletions src/3d/mesh/qgsmesh3dmaterial_p.cpp
Expand Up @@ -28,6 +28,10 @@
#include <Qt3DRender/QBuffer>
#include <QByteArray>

#include "qgsmeshlayer.h"
#include "qgsmeshlayerutils.h"
#include "qgstriangularmesh.h"

class ColorRampTextureGenerator: public Qt3DRender::QTextureImageDataGenerator
{

Expand All @@ -50,7 +54,6 @@ class ColorRampTextureGenerator: public Qt3DRender::QTextureImageDataGenerator
QList<QgsColorRampShader::ColorRampItem> colorItemList = mColorRampShader.colorRampItemList();
int size = colorItemList.count() ;

//dataPtr->setWidth( colorItemList.count() );
dataPtr->setWidth( size );
dataPtr->setHeight( 1 );
dataPtr->setDepth( 1 );
Expand Down Expand Up @@ -142,13 +145,101 @@ class ColorRampTexture: public Qt3DRender::QAbstractTextureImage
};


QgsMesh3dMaterial::QgsMesh3dMaterial( const QgsMesh3DSymbol &symbol, MagnitudeType magnitudeType ):
class ArrowsTextureGenerator: public Qt3DRender::QTextureImageDataGenerator
{
public:
ArrowsTextureGenerator( const QVector<QgsVector> &vectors, const QSize &size, bool fixedSize, double maxVectorLength ):
mVectors( vectors ), mSize( size ), mFixedSize( fixedSize ), mMaxVectorLength( maxVectorLength )
{}

Qt3DRender::QTextureImageDataPtr operator()() override
{
Qt3DRender::QTextureImageDataPtr dataPtr = Qt3DRender::QTextureImageDataPtr::create();
dataPtr->setFormat( QOpenGLTexture::RG32F );
dataPtr->setTarget( QOpenGLTexture::Target2D );
dataPtr->setPixelFormat( QOpenGLTexture::RG );
dataPtr->setPixelType( QOpenGLTexture::Float32 );

QByteArray data;

dataPtr->setWidth( mSize.width() );
dataPtr->setHeight( mSize.height() );
dataPtr->setDepth( 1 );
dataPtr->setFaces( 1 );
dataPtr->setLayers( 1 );
dataPtr->setMipLevels( 1 );

if ( mSize.isValid() )
{
data.resize( 2 * mSize.width()*mSize.height()*sizeof( float ) );
float *fptr = reinterpret_cast<float *>( data.data() );
for ( int i = 0; i < mSize.width()*mSize.height(); ++i )
{
if ( mFixedSize )
*fptr++ = 1;
else
*fptr++ = mVectors.at( i ).length() / mMaxVectorLength;

*fptr++ = mVectors.at( i ).angle();
}
}

dataPtr->setData( data, sizeof( float ) ); //size is the size of the type, here float
return dataPtr;
}

bool operator ==( const Qt3DRender::QTextureImageDataGenerator &other ) const override
{
const ArrowsTextureGenerator *otherFunctor = functor_cast<ArrowsTextureGenerator>( &other );
if ( !otherFunctor )
return false;

return ( otherFunctor->mVectors == mVectors &&
otherFunctor->mSize == mSize &&
otherFunctor->mFixedSize == mFixedSize );
}

private:
const QVector<QgsVector> mVectors;
const QSize mSize;
const bool mFixedSize;
const double mMaxVectorLength;

QT3D_FUNCTOR( ArrowsTextureGenerator )
};


class ArrowsGridTexture: public Qt3DRender::QAbstractTextureImage
{
public:
ArrowsGridTexture( const QVector<QgsVector> &vectors, const QSize &size, bool fixedSize, double maxVectorLength ):
mVectors( vectors ), mSize( size ), mFixedSize( fixedSize ), mMaxVectorLength( maxVectorLength )
{}

protected:
Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const override
{
return Qt3DRender::QTextureImageDataGeneratorPtr( new ArrowsTextureGenerator( mVectors, mSize, mFixedSize, mMaxVectorLength ) );
}

private:
const QVector<QgsVector> mVectors;
const QSize mSize;
const bool mFixedSize;
const double mMaxVectorLength;
};


QgsMesh3dMaterial::QgsMesh3dMaterial( QgsMeshLayer *layer, const QgsVector3D &origin, const QgsMesh3DSymbol &symbol, MagnitudeType magnitudeType ):
mSymbol( symbol ),
mMagnitudeType( magnitudeType )
mMagnitudeType( magnitudeType ),
mOrigin( origin )
{
Qt3DRender::QEffect *eff = new Qt3DRender::QEffect( this );

configure();
configureArrows( layer );

eff->addTechnique( mTechnique );
setEffect( eff );
}
Expand Down Expand Up @@ -176,8 +267,6 @@ void QgsMesh3dMaterial::configure()
colorRampTexture->setMagnificationFilter( Qt3DRender::QTexture1D::Linear );
}



// Create and configure technique
mTechnique = new Qt3DRender::QTechnique();
mTechnique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
Expand Down Expand Up @@ -220,3 +309,74 @@ void QgsMesh3dMaterial::configure()
mTechnique->addParameter( new Qt3DRender::QParameter( "isScalarMagnitude", ( mMagnitudeType == QgsMesh3dMaterial::ScalarDataSet ) ) );
}

void QgsMesh3dMaterial::configureArrows( QgsMeshLayer *layer )
{
if ( !layer )
return;

QgsMeshDatasetIndex datasetIndex = layer->rendererSettings().activeVectorDataset();

mTechnique->addParameter( new Qt3DRender::QParameter( "arrowsSpacing", float( mSymbol.arrowsSpacing() ) ) ) ;
QColor arrowsColor = layer->rendererSettings().vectorSettings( datasetIndex.group() ).color();
mTechnique->addParameter( new Qt3DRender::QParameter( "arrowsColor", QVector4D( arrowsColor.redF(), arrowsColor.greenF(), arrowsColor.blueF(), 1.0f ) ) ) ;

QgsMeshDatasetGroupMetadata meta = layer->dataProvider()->datasetGroupMetadata( datasetIndex );

QVector<QgsVector> vectors;
QSize gridSize;
QgsPointXY minCorner;
Qt3DRender::QParameter *arrowsEnabledParameter = new Qt3DRender::QParameter( "arrowsEnabled", false );
if ( mMagnitudeType != MagnitudeType::ScalarDataSet || !mSymbol.arrowsEnabled() )
arrowsEnabledParameter->setValue( false );
else
{
arrowsEnabledParameter->setValue( true );
int maxSize = mSymbol.maximumTextureSize();
// construct grid
QgsRectangle gridExtent = layer->triangularMesh()->extent();
gridSize = QSize( maxSize, maxSize );
double xSpacing = mSymbol.arrowsSpacing();
double ySpacing = mSymbol.arrowsSpacing();
// check the size of the grid and adjust the spacing if needed
int desiredXSize = int( gridExtent.width() / xSpacing );
if ( desiredXSize > maxSize )
xSpacing = gridExtent.width() / maxSize;
else
gridSize.setWidth( desiredXSize );

int desiredYSize = int( gridExtent.height() / ySpacing );
if ( desiredYSize > maxSize )
ySpacing = gridExtent.height() / maxSize;
else
gridSize.setHeight( desiredYSize );

double xMin = gridExtent.xMinimum() + ( gridExtent.width() - gridSize.width() * xSpacing ) / 2;
double yMin = gridExtent.yMinimum() + ( gridExtent.height() - gridSize.height() * ySpacing ) / 2;
minCorner = QgsPointXY( xMin, yMin );

vectors = QgsMeshLayerUtils::griddedVectorValues(
layer,
datasetIndex,
xSpacing,
ySpacing,
gridSize,
minCorner );
}

mTechnique->addParameter( arrowsEnabledParameter ) ;

Qt3DRender::QTexture2D *arrowsGridTexture = new Qt3DRender::QTexture2D( this );
arrowsGridTexture->addTextureImage( new ArrowsGridTexture( vectors, gridSize, mSymbol.arrowsFixedSize(), meta.maximum() ) );
arrowsGridTexture->setMinificationFilter( Qt3DRender::QTexture2D::Nearest );
arrowsGridTexture->setMagnificationFilter( Qt3DRender::QTexture2D::Nearest );

Qt3DRender::QTexture2D *arrowTexture = new Qt3DRender::QTexture2D( this );
Qt3DRender::QTextureImage *arrowTextureImage = new Qt3DRender::QTextureImage( this );
arrowTextureImage->setSource( QStringLiteral( "qrc:/images/themes/default/mesh/arrow.png" ) );
arrowTexture->addTextureImage( arrowTextureImage );
arrowTexture->setMinificationFilter( Qt3DRender::QTexture2D::Nearest );
arrowTexture->setMagnificationFilter( Qt3DRender::QTexture2D::Nearest );
mTechnique->addParameter( new Qt3DRender::QParameter( "arrowTexture", arrowTexture ) );
mTechnique->addParameter( new Qt3DRender::QParameter( "arrowsGridTexture", arrowsGridTexture ) ) ;
mTechnique->addParameter( new Qt3DRender::QParameter( "arrowsMinCorner", QVector2D( minCorner.x() - mOrigin.x(), -minCorner.y() + mOrigin.y() ) ) ) ;
}
6 changes: 5 additions & 1 deletion src/3d/mesh/qgsmesh3dmaterial_p.h
Expand Up @@ -23,6 +23,7 @@
#include <Qt3DRender/QRenderPassFilter>
#include <Qt3DRender/QTechnique>

#include "qgs3dmapsettings.h"
#include "qgsmesh3dsymbol.h"
#include "qgscolorrampshader.h"

Expand All @@ -37,6 +38,7 @@
// version without notice, or even be removed.
//

class QgsMeshLayer;

/**
* \ingroup 3d
Expand Down Expand Up @@ -64,14 +66,16 @@ class QgsMesh3dMaterial : public Qt3DRender::QMaterial
};

//! Constructor
QgsMesh3dMaterial( const QgsMesh3DSymbol &symbol, MagnitudeType magnitudeType = ZValue );
QgsMesh3dMaterial( QgsMeshLayer *layer, const QgsVector3D &origin, const QgsMesh3DSymbol &symbol, MagnitudeType magnitudeType = ZValue );

private:
QgsMesh3DSymbol mSymbol;
Qt3DRender::QTechnique *mTechnique;
MagnitudeType mMagnitudeType = ZValue;
QgsVector3D mOrigin;

void configure();
void configureArrows( QgsMeshLayer *layer );
};

///@endcond
Expand Down
23 changes: 22 additions & 1 deletion src/3d/qgs3dmapscene.cpp
Expand Up @@ -30,6 +30,8 @@
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DLogic/QFrameAction>

#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QTimer>

#include "qgsaabb.h"
Expand Down Expand Up @@ -553,7 +555,14 @@ void Qgs3DMapScene::addLayerEntity( QgsMapLayer *layer )
}
else if ( layer->type() == QgsMapLayerType::MeshLayer && renderer->type() == QLatin1String( "mesh" ) )
{
static_cast<QgsMeshLayer3DRenderer *>( renderer )->setLayer( static_cast<QgsMeshLayer *>( layer ) );
QgsMeshLayer3DRenderer *meshRenderer = static_cast<QgsMeshLayer3DRenderer *>( renderer );
meshRenderer->setLayer( static_cast<QgsMeshLayer *>( layer ) );

// Before entity creation, set the maximum texture size
// Not very clean, but for now, only place found in the workflow to do that simple
QgsMesh3DSymbol *sym = new QgsMesh3DSymbol( *meshRenderer->symbol() );
sym->setMaximumTextureSize( maximumTextureSize() );
meshRenderer->setSymbol( sym );
}

Qt3DCore::QEntity *newEntity = renderer->createEntity( mMap );
Expand Down Expand Up @@ -651,6 +660,18 @@ void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
}
}

int Qgs3DMapScene::maximumTextureSize() const
{
QSurface *surface = mEngine->surface();
QOpenGLContext context;
context.create();
context.makeCurrent( surface );
QOpenGLFunctions openglFunctions( &context );
GLint size;
openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
return int( size );
}

void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
{
mEntityCameraViewCenter = new Qt3DCore::QEntity;
Expand Down
1 change: 1 addition & 0 deletions src/3d/qgs3dmapscene.h
Expand Up @@ -135,6 +135,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
void updateScene();
bool updateCameraNearFarPlanes();
void finalizeNewEntity( Qt3DCore::QEntity *newEntity );
int maximumTextureSize() const;

private:
const Qgs3DMapSettings &mMap;
Expand Down
7 changes: 7 additions & 0 deletions src/3d/qgsabstract3dengine.h
Expand Up @@ -22,6 +22,7 @@

class QColor;
class QRect;
class QSurface;

namespace Qt3DCore
{
Expand Down Expand Up @@ -72,6 +73,12 @@ class _3D_EXPORT QgsAbstract3DEngine : public QObject
* Only one image request can be active at a time.
*/
virtual void requestCaptureImage() = 0;
/**
* Returns the surface of the engine
*
* \since QGIS 3.14
*/
virtual QSurface *surface() const = 0;

signals:
//! Emitted after a call to requestCaptureImage() to return the captured image.
Expand Down
6 changes: 6 additions & 0 deletions src/3d/qgsoffscreen3dengine.cpp
Expand Up @@ -17,6 +17,7 @@

#include <QOffscreenSurface>
#include <QSurfaceFormat>
#include <QOpenGLFunctions>

#include <Qt3DCore/QAspectEngine>
#include <Qt3DLogic/QLogicAspect>
Expand Down Expand Up @@ -229,6 +230,11 @@ QSize QgsOffscreen3DEngine::size() const
return mSize;
}

QSurface *QgsOffscreen3DEngine::surface() const
{
return mOffscreenSurface;
}

void QgsOffscreen3DEngine::requestCaptureImage()
{
if ( mReply )
Expand Down
1 change: 1 addition & 0 deletions src/3d/qgsoffscreen3dengine.h
Expand Up @@ -75,6 +75,7 @@ class _3D_EXPORT QgsOffscreen3DEngine : public QgsAbstract3DEngine
Qt3DRender::QRenderSettings *renderSettings() override;
Qt3DRender::QCamera *camera() override;
QSize size() const override;
QSurface *surface() const override;

void requestCaptureImage() override;

Expand Down
5 changes: 5 additions & 0 deletions src/3d/qgswindow3dengine.cpp
Expand Up @@ -74,3 +74,8 @@ QSize QgsWindow3DEngine::size() const
{
return mWindow3D->size();
}

QSurface *QgsWindow3DEngine::surface() const
{
return mWindow3D;
}
1 change: 1 addition & 0 deletions src/3d/qgswindow3dengine.h
Expand Up @@ -57,6 +57,7 @@ class _3D_EXPORT QgsWindow3DEngine : public QgsAbstract3DEngine
Qt3DRender::QRenderSettings *renderSettings() override;
Qt3DRender::QCamera *camera() override;
QSize size() const override;
QSurface *surface() const override;

private:
//! 3D window with all the 3D magic inside
Expand Down

1 comment on commit 42bc065

@telwertowski
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MacOS needs
#include <QVector2D>

~/qgis/QGIS/src/3d/mesh/qgsmesh3dmaterial_p.cpp:381:76: error:
invalid use of incomplete type 'QVector2D'
...QVector2D( minCorner.x() - mOrigin.x(), -minCorner.y() + mOrigin.y() ) ...

Please sign in to comment.