QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
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 }
void setSize(const QSizeF size)
Set the billboard size.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
void useDefaultSymbol(const Qgs3DMapSettings &map, bool selected=false)
Set default symbol for the texture with map and selected parameter for rendering. ...
QColor selectionColor() const
Returns color used for selected features.
3 Definition of the world
void setViewportSize(const QSizeF size)
Set the size of the view port.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:860
void setTexture2DFromSymbol(QgsMarkerSymbol *markerSymbol, const Qgs3DMapSettings &map, bool selected=false)
Set markerSymbol for the texture with map and selected parameter for rendering.
void setSelectionColor(const QColor &color)
Sets the color to use when rendering selected features.
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:297
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1454
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1409
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr)
Returns a pixmap preview for a color ramp.
double outputDpi() const
Returns DPI used for conversion between real world units (e.g.
QSizeF windowSize() const
Returns the size of the view port.
QSizeF size() const
Returns the billboard size.