Skip to content

Commit

Permalink
[FEATURE][3D] Billboard Rendering for Points (#31308)
Browse files Browse the repository at this point in the history
* Add button to change billboard symbol.

* Add shaders for billboards.

* Add billboard material class.

* Add sample billboard image.

* Add dummy handler for billboard.

* Add billboard geometry class.

* First working version of 3D point as billboard.

* Make selected feature bigger.

* Use default symbol preview as billboard.

* Update billboard when changes the viewport size.

* Use QgsTerrainTextureImage for adding image to texture.

* Show better quality of billboard default symbol.

* Promote QgsSymbolButton not working.

* Add QgsSymbolButton properly.

* Add seTexture2DFromSymbol.

* Use default symbol

* [On Progress] Get symbol from the QgsSymbolButton.

* [On progress] failed to change the symbol

* Fix billboard fragment shader for macOS

* Better transparency handling.

* Use size from the symbol.

* Add set layer for 3d billboard symbol.

* Set billboard size from the symbol pixel size * 20

* Use size from the image.

* [Debug] set white symbol to success kid, it work when previous billboard is success kid.

* Use store and restore symbol from Nyall.

* Remove unrelated code.

* Apply random extent to fix the bug, from Martin.

* Remove add mesh entities for billboard.

* Hide material and transformation widget for billboard.

* Remove add scene entities for billboard.

* Add selected as parameter in drawPreviewIcon.

* Add QgsMarkerSymbol to store the symbol in billboard

* Put billboard symbol in point3dsymbol serialization.

* Add billboard height in the UI.

* Set height for billboard.

* Store billboard height separately. Perhaps better to use existing transform.

* Set height of billboard to TY.

* Flipped image for billboard symbol.

* Add helper function to set billboard function.

* Generate billboard transform from general transform.

* Use static dpi for context size.

* Remove debug message.

* Use Qgs3DRenderContext for selection color and dpi from QgsApplication.

* Remove unnecessary file and code.

* Remove commented iut code.

* Add documentation of new classes.

* Fix banned keywords.

* Add missing parameter's documentation.

* Address PR review.

* Use context from readXML.

* Remove one line function.

* Fix billboard size.

* Make some functions private, remove unused function.

* Use unique_ptr for the ownership.

* Use unique_ptr for default symbol to avoid memory leak.

* Add parent to texture2D.

* Fix documentation.

* Add copy constructor.

* Fix documentation.

* Remove documentation warning.

* Fix sip error.

* Add unit test for billboard rendering.

* Set ambient to not transparent for measurement line.

* Add dpi in the Qgs3DMapSetting

* Update billboard rendering unit test.

* Remove layer from 3d point widget since it's not supported yet.

* Addressing PR review from Martin.

* Attach dom directly for the billboard symbol.

* Remove unused constructor for point3dsymbol.

* Use stroke width ratio for solving big stroke width.

* Update unit test for rendering with some stroke color.

* Fix typo.
  • Loading branch information
ismailsunni authored and wonder-sk committed Aug 27, 2019
1 parent 6567e3e commit b9978d5
Show file tree
Hide file tree
Showing 28 changed files with 986 additions and 186 deletions.
24 changes: 23 additions & 1 deletion python/3d/auto_generated/symbols/qgspoint3dsymbol.sip.in
Expand Up @@ -29,7 +29,12 @@ class QgsPoint3DSymbol : QgsAbstract3DSymbol
public:
QgsPoint3DSymbol();
%Docstring
Constructor for QgsPoint3DSymbol.
Constructor for QgsPoint3DSymbol with default QgsMarkerSymbol as the billboardSymbol
%End

QgsPoint3DSymbol( const QgsPoint3DSymbol &other );
%Docstring
Copy Constructor for QgsPoint3DSymbol
%End

virtual QString type() const;
Expand Down Expand Up @@ -69,6 +74,7 @@ Sets material used for shading of the symbol
Plane,
ExtrudedText,
Model,
Billboard,
};

static Shape shapeFromString( const QString &shape );
Expand Down Expand Up @@ -96,6 +102,15 @@ Returns a key-value dictionary of point shape properties
void setShapeProperties( const QVariantMap &properties );
%Docstring
Sets a key-value dictionary of point shape properties
%End

QgsMarkerSymbol *billboardSymbol() const;
%Docstring
Returns a symbol for billboard
%End
void setBillboardSymbol( QgsMarkerSymbol *symbol );
%Docstring
Set symbol for billboard and the ownership is transferred
%End

QMatrix4x4 transform() const;
Expand All @@ -107,6 +122,13 @@ Returns transform for individual objects represented by the symbol
Sets transform for individual objects represented by the symbol
%End

QMatrix4x4 billboardTransform() const;
%Docstring
Returns transform for billboards
%End

private:
QgsPoint3DSymbol &operator=( const QgsPoint3DSymbol & );
};


Expand Down
11 changes: 10 additions & 1 deletion python/core/auto_generated/symbology/qgssymbol.sip.in
Expand Up @@ -272,17 +272,26 @@ layer.
.. seealso:: :py:func:`setColor`
%End

void drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext = 0 );
void drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext = 0, bool selected = false );
%Docstring
Draws an icon of the symbol that occupies an area given by ``size`` using the specified ``painter``.

Optionally a custom render context may be given in order to ensure that the preview icon exactly
matches the settings from that context.

:param painter: destination painter
:param size: size of the icon
:param customContext: the context in which the rendering happens
:param selected: set to ``True`` to render the symbol in a selected state

.. seealso:: :py:func:`exportImage`

.. seealso:: :py:func:`asImage`

.. note::

Parameter selected added in QGIS 3.10

.. versionadded:: 2.6
%End

Expand Down
Expand Up @@ -177,19 +177,24 @@ Returns an icon preview for a color ramp.
.. seealso:: :py:func:`symbolPreviewPixmap`
%End

static QPixmap symbolPreviewPixmap( const QgsSymbol *symbol, QSize size, int padding = 0, QgsRenderContext *customContext = 0 );
static QPixmap symbolPreviewPixmap( const QgsSymbol *symbol, QSize size, int padding = 0, QgsRenderContext *customContext = 0, bool selected = false );
%Docstring
Returns a pixmap preview for a color ramp.

:param symbol: symbol
:param size: target pixmap size
:param padding: space between icon edge and symbol
:param customContext: render context to use when rendering symbol
:param selected: set to ``True`` to render the symbol in a selected state

.. note::

Parameter customContext added in QGIS 2.6

.. note::

Parameter selected added in QGIS 3.10

.. seealso:: :py:func:`symbolPreviewIcon`
%End

Expand Down
4 changes: 4 additions & 0 deletions src/3d/CMakeLists.txt
Expand Up @@ -33,12 +33,14 @@ SET(QGIS_3D_SRCS
processing/qgsalgorithmtessellate.cpp

symbols/qgsabstract3dsymbol.cpp
symbols/qgsbillboardgeometry.cpp
symbols/qgsline3dsymbol.cpp
symbols/qgsline3dsymbol_p.cpp
symbols/qgslinematerial_p.cpp
symbols/qgslinevertexdata_p.cpp
symbols/qgsmesh3dsymbol.cpp
symbols/qgsmesh3dsymbol_p.cpp
symbols/qgspoint3dbillboardmaterial.cpp
symbols/qgspoint3dsymbol.cpp
symbols/qgspoint3dsymbol_p.cpp
symbols/qgspolygon3dsymbol.cpp
Expand Down Expand Up @@ -77,6 +79,8 @@ SET(QGIS_3D_MOC_HDRS

processing/qgs3dalgorithms.h

symbols/qgsbillboardgeometry.h
symbols/qgspoint3dbillboardmaterial.h
symbols/qgslinematerial_p.h

terrain/qgsdemterraintileloader_p.h
Expand Down
2 changes: 1 addition & 1 deletion src/3d/chunks/qgschunkedentity_p.cpp
Expand Up @@ -173,7 +173,7 @@ void QgsChunkedEntity::update( const SceneState &state )
if ( pendingJobsCount() != oldJobsCount )
emit pendingJobsCountChanged();

qDebug() << "update: active " << mActiveNodes.count() << " enabled " << enabled << " disabled " << disabled << " | culled " << mFrustumCulled << " | loading " << mChunkLoaderQueue->count() << " loaded " << mReplacementQueue->count() << " | unloaded " << unloaded << " elapsed " << t.elapsed() << "ms";
// qDebug() << "update: active " << mActiveNodes.count() << " enabled " << enabled << " disabled " << disabled << " | culled " << mFrustumCulled << " | loading " << mChunkLoaderQueue->count() << " loaded " << mReplacementQueue->count() << " | unloaded " << unloaded << " elapsed " << t.elapsed() << "ms";
}

void QgsChunkedEntity::setShowBoundingBoxes( bool enabled )
Expand Down
11 changes: 11 additions & 0 deletions src/3d/qgs3dmapscene.cpp
Expand Up @@ -49,6 +49,7 @@
#include "qgstessellatedpolygongeometry.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayer3drenderer.h"
#include "qgspoint3dbillboardmaterial.h"

#include "qgslinematerial_p.h"

Expand Down Expand Up @@ -628,6 +629,16 @@ void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )

lm->setViewportSize( cameraController()->viewport().size() );
}
// configure billboard's viewport when the viewport is changed.
for ( QgsPoint3DBillboardMaterial *bm : newEntity->findChildren<QgsPoint3DBillboardMaterial *>() )
{
connect( mCameraController, &QgsCameraController::viewportChanged, bm, [bm, this]
{
bm->setViewportSize( mCameraController->viewport().size() );
} );

bm->setViewportSize( mCameraController->viewport().size() );
}
}

void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
Expand Down
16 changes: 16 additions & 0 deletions src/3d/qgs3dmapsettings.h
Expand Up @@ -340,6 +340,21 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
*/
void setFieldOfView( const float fieldOfView );

/**
* Sets DPI used for conversion between real world units (e.g. mm) and pixels
* \param dpi the number of dot per inch
* \since QGIS 3.10
*/
void setOutputDpi( const double dpi ) {mDpi = dpi;}


/**
* Returns DPI used for conversion between real world units (e.g. mm) and pixels
* Default value is 96
* \since QGIS 3.10
*/
double outputDpi() const { return mDpi; }

signals:
//! Emitted when the background color has changed
void backgroundColorChanged();
Expand Down Expand Up @@ -430,6 +445,7 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
QgsCoordinateTransformContext mTransformContext;
QgsPathResolver mPathResolver;
QgsMapThemeCollection *mMapThemes = nullptr; //!< Pointer to map themes (e.g. from the current project) to resolve map theme content from the name
double mDpi = 96; //!< Dot per inch value for the screen / painter
};


Expand Down
3 changes: 3 additions & 0 deletions src/3d/shaders.qrc
Expand Up @@ -6,5 +6,8 @@
<file>shaders/lines.vert</file>
<file>shaders/lines.geom</file>
<file>shaders/lines.frag</file>
<file>shaders/billboards.geom</file>
<file>shaders/billboards.frag</file>
<file>shaders/billboards.vert</file>
</qresource>
</RCC>
15 changes: 15 additions & 0 deletions src/3d/shaders/billboards.frag
@@ -0,0 +1,15 @@
#version 150 core

uniform sampler2D tex0;

in vec2 UV;
out vec4 fragColor;

void main(void)
{

fragColor = texture(tex0, UV);

if (fragColor.a < 0.5)
discard;
}
45 changes: 45 additions & 0 deletions src/3d/shaders/billboards.geom
@@ -0,0 +1,45 @@
#version 150

// input
layout (points) in;
// output
layout (triangle_strip, max_vertices = 4) out;

uniform mat4 modelViewProjection;

uniform vec2 BB_SIZE; // billboard size in pixels
uniform vec2 WIN_SCALE; // the size of the viewport in pixels

out vec2 UV;
// glsl

void main (void)
{

vec4 P = gl_in[0].gl_Position;
P /= P.w;

vec2 size = BB_SIZE / WIN_SCALE;

gl_Position = P;
gl_Position.xy += vec2(-0.5,-0.5) * size;
UV = vec2(0,0);
EmitVertex();

gl_Position = P;
gl_Position.xy += vec2(0.5,-0.5) * size;
UV = vec2(1,0);
EmitVertex();

gl_Position = P;
gl_Position.xy += vec2(-0.5,+0.5) * size;
UV = vec2(0,1);
EmitVertex();

gl_Position = P;
gl_Position.xy += vec2(+0.5,+0.5) * size;
UV = vec2(1,1);
EmitVertex();

EndPrimitive();
}
10 changes: 10 additions & 0 deletions src/3d/shaders/billboards.vert
@@ -0,0 +1,10 @@
#version 150

uniform mat4 modelViewProjection;

in vec3 vertexPosition;

void main(void)
{
gl_Position = modelViewProjection * vec4(vertexPosition, 1);
}
61 changes: 61 additions & 0 deletions src/3d/symbols/qgsbillboardgeometry.cpp
@@ -0,0 +1,61 @@
/***************************************************************************
qgsbillboardgeometry.cpp
--------------------------------------
Date : Jul 2019
Copyright : (C) 2019 by Ismail Sunni
Email : imajimatika at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include <QVector3D>

#include "qgsbillboardgeometry.h"

QgsBillboardGeometry::QgsBillboardGeometry( Qt3DCore::QNode *parent )
: Qt3DRender::QGeometry( parent )
, mPositionAttribute( new Qt3DRender::QAttribute( this ) )
, mVertexBuffer( new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this ) )
{

mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
mPositionAttribute->setBuffer( mVertexBuffer );
mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
mPositionAttribute->setVertexSize( 3 );
mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );

addAttribute( mPositionAttribute );

}

void QgsBillboardGeometry::setPoints( const QVector<QVector3D> &vertices )
{
QByteArray vertexBufferData;
vertexBufferData.resize( vertices.size() * 3 * sizeof( float ) );
float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
int idx = 0;
for ( const auto &v : vertices )
{
rawVertexArray[idx++] = v.x();
rawVertexArray[idx++] = v.y();
rawVertexArray[idx++] = v.z();
}

mVertexCount = vertices.count();
mVertexBuffer->setData( vertexBufferData );

emit countChanged( mVertexCount );

}

int QgsBillboardGeometry::count() const
{
return mVertexCount;
}


56 changes: 56 additions & 0 deletions src/3d/symbols/qgsbillboardgeometry.h
@@ -0,0 +1,56 @@
/***************************************************************************
qgsbillboardgeometry.h
--------------------------------------
Date : Jul 2019
Copyright : (C) 2019 by Ismail Sunni
Email : imajimatika at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSBILLBOARDGEOMETRY_H
#define QGSBILLBOARDGEOMETRY_H

#include <QObject>
#include <Qt3DRender/QGeometry>
#include <Qt3DRender/QBuffer>
#include <Qt3DRender/QAttribute>


/**
* \ingroup 3d
* Geometry of the billboard rendering for points in 3D map view.
*
* \since QGIS 3.10
*/
class QgsBillboardGeometry : public Qt3DRender::QGeometry
{
Q_OBJECT

Q_PROPERTY( int count READ count NOTIFY countChanged )
public:
//! Constructor of QgsBillboardGeometry.
QgsBillboardGeometry( Qt3DCore::QNode *parent = nullptr );

//! Set the points for the billboard with \a vertices.
void setPoints( const QVector<QVector3D> &vertices );

//! Returns the number of points.
int count() const;

signals:
//! Signal when the number of points changed.
void countChanged( int count );

private:
Qt3DRender::QAttribute *mPositionAttribute = nullptr;
Qt3DRender::QBuffer *mVertexBuffer = nullptr;
int mVertexCount = 0;
};

#endif // QGSBILLBOARDGEOMETRY_H

0 comments on commit b9978d5

Please sign in to comment.