QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgspoint3dbillboardmaterial.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspoint3dbillboardmaterial.h
3  --------------------------------------
4  Date : Jul 2019
5  Copyright : (C) 2019 by Ismail Sunni
6  Email : imajimatika at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include <Qt3DRender/QParameter>
16 #include <Qt3DRender/QShaderProgram>
17 #include <Qt3DRender/QRenderPass>
18 #include <Qt3DRender/QTechnique>
19 #include <Qt3DRender/QGraphicsApiFilter>
20 #include <Qt3DRender/QEffect>
21 #include <Qt3DRender/QBlendEquationArguments>
22 #include <Qt3DRender/QBlendEquation>
23 #include <Qt3DRender/QNoDepthMask>
24 
25 #include "qgslogger.h"
28 #include "qgsmarkersymbollayer.h"
29 #include "qgssymbollayerutils.h"
30 #include "qgssettings.h"
31 #include "qgs3dmapsettings.h"
32 
34  : mSize( new Qt3DRender::QParameter( "BB_SIZE", QSizeF( 100, 100 ), this ) )
35  , mViewportSize( new Qt3DRender::QParameter( "WIN_SCALE", QSizeF( 800, 600 ), this ) )
36 {
37  addParameter( mSize );
38  addParameter( mViewportSize );
39 
40  // Initialize with empty parameter.
41  mTexture2D = new Qt3DRender::QParameter( "tex0", QVariant(), this );
42  addParameter( mTexture2D );
43 
44  // Blending for handling transparency
45  Qt3DRender::QBlendEquationArguments *blendState = new Qt3DRender::QBlendEquationArguments;
46  blendState->setSourceRgb( Qt3DRender::QBlendEquationArguments::SourceAlpha );
47  blendState->setDestinationRgb( Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha );
48 
49  Qt3DRender::QBlendEquation *blendEquation = new Qt3DRender::QBlendEquation;
50  blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
51 
52  // Shader program
53  Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram( this );
54  shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/billboards.vert" ) ) ) );
55  shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/billboards.frag" ) ) ) );
56  shaderProgram->setGeometryShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/billboards.geom" ) ) ) );
57 
58  // Render Pass
59  Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass( this );
60  renderPass->setShaderProgram( shaderProgram );
61  renderPass->addRenderState( blendState );
62  renderPass->addRenderState( blendEquation );
63 
64  // without this filter the default forward renderer would not render this
65  Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
66  filterKey->setName( QStringLiteral( "renderingStyle" ) );
67  filterKey->setValue( "forward" );
68 
69  // Technique
70  Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
71  technique->addRenderPass( renderPass );
72  technique->addFilterKey( filterKey );
73  technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
74  technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
75  technique->graphicsApiFilter()->setMajorVersion( 3 );
76  technique->graphicsApiFilter()->setMinorVersion( 1 );
77 
78  // Effect
79  Qt3DRender::QEffect *effect = new Qt3DRender::QEffect( this );
80  effect->addTechnique( technique );
81 
82  setEffect( effect );
83 }
84 
85 void QgsPoint3DBillboardMaterial::setSize( const QSizeF size )
86 {
87  mSize->setValue( size );
88 }
89 
91 {
92  return mSize->value().value<QSizeF>();
93 }
94 
96 {
97  mViewportSize->setValue( size );
98 }
99 
101 {
102  return mViewportSize->value().value<QSizeF>();
103 }
104 
105 void QgsPoint3DBillboardMaterial::setTexture2DFromImage( QImage image, double size )
106 {
107  // Create texture image
108  QgsRectangle randomExtent = QgsRectangle( rand(), rand(), rand(), rand() );
109  QgsTerrainTextureImage *billboardTextureImage = new QgsTerrainTextureImage( image, randomExtent, QStringLiteral( "billboard material." ) );
110 
111  setTexture2DFromTextureImage( billboardTextureImage );
112  setSize( QSizeF( size + size, size + size ) );
113 }
114 
116 {
117  // Default texture
118  std::unique_ptr< QgsMarkerSymbol> defaultSymbol( static_cast<QgsMarkerSymbol *>( QgsSymbol::defaultSymbol( QgsWkbTypes::PointGeometry ) ) );
119  setTexture2DFromSymbol( defaultSymbol.get(), map, selected );
120 }
121 
123 {
124  QgsRenderContext context;
125  context.setSelectionColor( map.selectionColor() );
126  context.setScaleFactor( map.outputDpi() / 25.4 );
127  double pixelSize = context.convertToPainterUnits( markerSymbol->size( context ), markerSymbol->sizeUnit() );
128 
129  // This number is an max estimation ratio between stroke width and symbol size.
130  double strokeRatio = 0.5;
131  // Minimum extra width, just in case the size is small, but the stroke is quite big.
132  // 10 mm is quite big based on Raymond's experiece.
133  // 10 mm has around 37 pixel in 96 dpi, round up become 40.
134  double minimumExtraSize = 40;
135  double extraPixel = minimumExtraSize > pixelSize * strokeRatio ? minimumExtraSize : pixelSize * strokeRatio;
136  int pixelWithExtra = std::ceil( pixelSize + extraPixel );
137  QPixmap symbolPixmap = QgsSymbolLayerUtils::symbolPreviewPixmap( markerSymbol, QSize( pixelWithExtra, pixelWithExtra ), 0, &context, selected );
138  QImage symbolImage = symbolPixmap.toImage();
139  QImage flippedSymbolImage = symbolImage.mirrored();
140  setTexture2DFromImage( flippedSymbolImage, pixelWithExtra );
141 }
142 
143 void QgsPoint3DBillboardMaterial::setTexture2DFromTextureImage( Qt3DRender::QAbstractTextureImage *textureImage )
144 {
145  // Texture2D
146  Qt3DRender::QTexture2D *texture2D = new Qt3DRender::QTexture2D( this );
147  texture2D->setGenerateMipMaps( false );
148  texture2D->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
149  texture2D->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
150 
151  // The textureImage gets parented to texture2D here
152  texture2D->addTextureImage( textureImage );
153 
154  mTexture2D->setValue( QVariant::fromValue( texture2D ) );
155 }
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:287
QgsSymbol::defaultSymbol
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:301
Qgs3DMapSettings::selectionColor
QColor selectionColor() const
Returns color used for selected features.
Definition: qgs3dmapsettings.cpp:362
Qgs3DMapSettings::outputDpi
double outputDpi() const
Returns DPI used for conversion between real world units (e.g.
Definition: qgs3dmapsettings.h:359
QgsPoint3DBillboardMaterial::setViewportSize
void setViewportSize(const QSizeF size)
Set the size of the view port.
Definition: qgspoint3dbillboardmaterial.cpp:95
QgsMarkerSymbol::size
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1597
QgsPoint3DBillboardMaterial::setTexture2DFromSymbol
void setTexture2DFromSymbol(QgsMarkerSymbol *markerSymbol, const Qgs3DMapSettings &map, bool selected=false)
Set markerSymbol for the texture with map and selected parameter for rendering.
Definition: qgspoint3dbillboardmaterial.cpp:122
qgssymbollayerutils.h
qgsmarkersymbollayer.h
QgsRenderContext
Definition: qgsrendercontext.h:57
qgspoint3dbillboardmaterial.h
QgsRectangle
Definition: qgsrectangle.h:41
QgsPoint3DBillboardMaterial::QgsPoint3DBillboardMaterial
QgsPoint3DBillboardMaterial()
Definition: qgspoint3dbillboardmaterial.cpp:33
QgsSymbolLayerUtils::symbolPreviewPixmap
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *shape=nullptr)
Returns a pixmap preview for a color ramp.
Definition: qgssymbollayerutils.cpp:767
QgsMarkerSymbol
Definition: qgssymbol.h:917
qgsterraintextureimage_p.h
Qt3DRender
Definition: qgs3dmapscene.h:25
Qgs3DMapSettings
Definition: qgs3dmapsettings.h:51
QgsRenderContext::setSelectionColor
void setSelectionColor(const QColor &color)
Sets the color to use when rendering selected features.
Definition: qgsrendercontext.h:516
qgs3dmapsettings.h
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:141
qgssettings.h
QgsPoint3DBillboardMaterial::setSize
void setSize(const QSizeF size)
Set the billboard size.
Definition: qgspoint3dbillboardmaterial.cpp:85
QgsMarkerSymbol::sizeUnit
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1642
qgslogger.h
QgsRenderContext::setScaleFactor
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:460
QgsPoint3DBillboardMaterial::useDefaultSymbol
void useDefaultSymbol(const Qgs3DMapSettings &map, bool selected=false)
Set default symbol for the texture with map and selected parameter for rendering.
Definition: qgspoint3dbillboardmaterial.cpp:115
QgsPoint3DBillboardMaterial::windowSize
QSizeF windowSize() const
Returns the size of the view port.
Definition: qgspoint3dbillboardmaterial.cpp:100
QgsPoint3DBillboardMaterial::size
QSizeF size() const
Returns the billboard size.
Definition: qgspoint3dbillboardmaterial.cpp:90