QGIS API Documentation 4.3.0-Master (90cb4ecf9ef)
Loading...
Searching...
No Matches
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 ***************************************************************************/
16
17#include "qgs3drendercontext.h"
18#include "qgs3dutils.h"
19#include "qgsimagetexture.h"
20#include "qgsmarkersymbol.h"
21#include "qgssymbollayerutils.h"
22
23#include <QString>
24#include <QUrl>
25#include <Qt3DRender/QBlendEquation>
26#include <Qt3DRender/QBlendEquationArguments>
27#include <Qt3DRender/QEffect>
28#include <Qt3DRender/QGraphicsApiFilter>
29#include <Qt3DRender/QNoDepthMask>
30#include <Qt3DRender/QParameter>
31#include <Qt3DRender/QRenderPass>
32#include <Qt3DRender/QShaderProgram>
33#include <Qt3DRender/QTechnique>
34
35#include "moc_qgspoint3dbillboardmaterial.cpp"
36
37using namespace Qt::StringLiterals;
38
40 : mSize( new Qt3DRender::QParameter( "BB_SIZE", QSizeF( 100, 100 ), this ) )
41 , mScaleMode( scaleMode )
42{
43 // billboard materials should not cast shadows -- this causes weird unnatural effects,
44 // as the size and orientation of the billboard seen by the light camera
45 // doesn't match the size and orientation seen by the main camera
46 setCastsShadows( false );
47
48 addParameter( mSize );
49
50 switch ( mScaleMode )
51 {
53 {
54 mViewportSize = new Qt3DRender::QParameter( "WIN_SCALE", QSizeF( 800, 600 ), this );
55 addParameter( mViewportSize );
56 break;
57 }
58
60 break;
61 }
62
63 // Initialize with empty parameter.
64 mTexture2D = new Qt3DRender::QParameter( "tex0", QVariant(), this );
65 addParameter( mTexture2D );
66
67 // Blending for handling transparency
68 Qt3DRender::QBlendEquationArguments *blendState = new Qt3DRender::QBlendEquationArguments;
69 blendState->setSourceRgb( Qt3DRender::QBlendEquationArguments::SourceAlpha );
70 blendState->setDestinationRgb( Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha );
71
72 Qt3DRender::QBlendEquation *blendEquation = new Qt3DRender::QBlendEquation;
73 blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
74
75 // Shader program
76 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram( this );
77
78 const QUrl urlVert( u"qrc:/shaders/billboards.vert"_s );
79 QStringList vertexShaderDefines;
80
81 if ( attributes.testFlag( ExtraAttribute::TextureData ) )
82 {
83 vertexShaderDefines << u"TEXTURE_ATLAS"_s;
84 }
85
86 if ( attributes.testFlag( ExtraAttribute::PixelOffsets ) )
87 {
88 vertexShaderDefines << u"TEXTURE_ATLAS_PIXEL_OFFSETS"_s;
89 }
90
91 if ( attributes.testFlag( ExtraAttribute::Size ) )
92 {
93 vertexShaderDefines << u"PER_INSTANCE_SIZE"_s;
94 }
95
96 if ( attributes.testFlag( ExtraAttribute::VerticalOffset ) )
97 {
98 vertexShaderDefines << u"VERTICAL_OFFSET"_s;
99 mVerticalOffset = new Qt3DRender::QParameter( "VERT_OFFSET", 0.0, this );
100 addParameter( mVerticalOffset );
101 }
102
103 switch ( mScaleMode )
104 {
106 break;
108 vertexShaderDefines << u"PERSPECTIVE_SCALE"_s;
109 break;
110 }
111
112 const QByteArray vertexShaderCode = Qt3DRender::QShaderProgram::loadSource( urlVert );
113 const QByteArray finalVertexShaderCode = Qgs3DUtils::addDefinesToShaderCode( vertexShaderCode, vertexShaderDefines );
114 shaderProgram->setVertexShaderCode( finalVertexShaderCode );
115
116 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/billboards.frag"_s ) ) );
117
118 // Render Pass
119 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass( this );
120 renderPass->setShaderProgram( shaderProgram );
121 renderPass->addRenderState( blendState );
122 renderPass->addRenderState( blendEquation );
123
124 // without this filter the default forward renderer would not render this
125 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
126 filterKey->setName( u"renderingStyle"_s );
127 filterKey->setValue( "forward" );
128
129 // Technique
130 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
131 technique->addRenderPass( renderPass );
132 technique->addFilterKey( filterKey );
133 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
134 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
135 technique->graphicsApiFilter()->setMajorVersion( 3 );
136 technique->graphicsApiFilter()->setMinorVersion( 1 );
137
138 // Effect
139 Qt3DRender::QEffect *effect = new Qt3DRender::QEffect( this );
140 effect->addTechnique( technique );
141
142 setEffect( effect );
143}
144
146
148{
149 mSize->setValue( size );
150}
151
153{
154 return mSize->value().value<QSizeF>();
155}
156
158{
159 if ( mVerticalOffset )
160 {
161 mVerticalOffset->setValue( offset );
162 }
163}
164
166{
167 if ( mViewportSize )
168 {
169 mViewportSize->setValue( size );
170 }
171}
172
174{
175 if ( mViewportSize )
176 {
177 return mViewportSize->value().value<QSizeF>();
178 }
179 else
180 {
181 return QSizeF();
182 }
183}
184
186{
187 // Create texture image
188 QgsImageTexture *textureImage = new QgsImageTexture( image );
189 setTexture2DFromTextureImage( textureImage );
190
191 setSize( QSizeF( image.size().width(), image.size().height() ) );
192}
193
195{
196 // Default texture
197 const std::unique_ptr<QgsMarkerSymbol> defaultSymbol( static_cast<QgsMarkerSymbol *>( QgsSymbol::defaultSymbol( Qgis::GeometryType::Point ) ) );
198 setTexture2DFromSymbol( defaultSymbol.get(), context, selected );
199}
200
201QImage QgsPoint3DBillboardMaterial::renderSymbolToImage( const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected )
202{
203 QgsRenderContext context2D;
204 context2D.setSelectionColor( context.selectionColor() );
205 context2D.setScaleFactor( context.outputDpi() / 25.4 );
208
209 std::unique_ptr< QgsMarkerSymbol > clonedSymbol( markerSymbol->clone() );
210 clonedSymbol->startRender( context2D );
211
212 constexpr int BUFFER_SIZE_PIXELS = 2;
213
214 const QRectF bounds = markerSymbol->bounds( QPointF( 0, 0 ), context2D );
215
216 QImage image( static_cast< int >( std::ceil( bounds.size().width() ) ) + 2 * BUFFER_SIZE_PIXELS, static_cast< int >( std::ceil( bounds.size().height() ) ) + 2 * BUFFER_SIZE_PIXELS, QImage::Format_ARGB32_Premultiplied );
217 image.fill( Qt::transparent );
218
219 QPainter painter( &image );
220 context2D.setPainter( &painter );
221
222 clonedSymbol->renderPoint( QPointF( -bounds.left() + BUFFER_SIZE_PIXELS, -bounds.top() + BUFFER_SIZE_PIXELS ), nullptr, context2D, -1, selected );
223
224 painter.end();
225
226 clonedSymbol->stopRender( context2D );
227 return image;
228}
229
230void QgsPoint3DBillboardMaterial::setTexture2DFromSymbol( const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected )
231{
232 const QImage symbolImage = renderSymbolToImage( markerSymbol, context, selected );
233 setTexture2DFromImage( symbolImage );
234}
235
236void QgsPoint3DBillboardMaterial::setTexture2DFromTextureImage( Qt3DRender::QAbstractTextureImage *textureImage )
237{
238 // Texture2D
239 Qt3DRender::QTexture2D *texture2D = new Qt3DRender::QTexture2D( this );
240 texture2D->setGenerateMipMaps( false );
241 texture2D->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
242 texture2D->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
243 texture2D->setFormat( Qt3DRender::QAbstractTexture::SRGB8_Alpha8 );
244
245 // The textureImage gets parented to texture2D here
246 texture2D->addTextureImage( textureImage );
247
248 mTexture2D->setValue( QVariant::fromValue( texture2D ) );
249}
@ Point
Points.
Definition qgis.h:380
BillboardScaleMode
3D billboard scaling modes.
Definition qgis.h:4441
@ ViewIndependent
Billboard has a fixed pixel size on the screen, regardless of the camera distance.
Definition qgis.h:4442
@ Perspective
Billboard size is scaled with perspective distance from camera, using world units.
Definition qgis.h:4443
@ Antialiasing
Use antialiasing while drawing.
Definition qgis.h:2951
@ HighQualityImageTransforms
Enable high quality image transformations, which results in better appearance of scaled or rotated ra...
Definition qgis.h:2961
Rendering context for preparation of 3D entities.
QColor selectionColor() const
Returns color used for selected features.
double outputDpi() const
Returns DPI used for conversion between real world units (e.g.
static QByteArray addDefinesToShaderCode(const QByteArray &shaderCode, const QStringList &defines)
Inserts some define macros into a shader source code.
Holds an image that can be used as a texture in the 3D view.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
QRectF bounds(QPointF point, QgsRenderContext &context, const QgsFeature &feature=QgsFeature()) const
Returns the approximate bounding box of the marker symbol, which includes the bounding box of all sym...
void setCastsShadows(bool enabled)
Sets whether the material should cast shadows.
void useDefaultSymbol(const Qgs3DRenderContext &context, bool selected=false)
Set default symbol for the texture with context and selected parameter for rendering.
QFlags< ExtraAttribute > ExtraAttributes
static QImage renderSymbolToImage(const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected=false)
Renders a marker symbol to an image.
void setVerticalOffset(float offset)
Set the vertical offset.
QSizeF windowSize() const
Returns the size of the view port.
void setTexture2DFromImage(const QImage &image)
Set the texture2D of the billboard from an image.
~QgsPoint3DBillboardMaterial() override
QSizeF size() const
Returns the billboard size.
QgsPoint3DBillboardMaterial(ExtraAttributes attributes=ExtraAttributes(), Qgis::BillboardScaleMode scaleMode=Qgis::BillboardScaleMode::ViewIndependent)
Constructor for QgsPoint3DBillboardMaterial, using the specified additional attributes.
void setTexture2DFromSymbol(const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected=false)
Set markerSymbol for the texture with context and selected parameter for rendering.
void setViewportSize(const QSizeF size)
Set the size of the view port.
void setSize(const QSizeF size)
Set the billboard size.
Contains information about the context of a rendering operation.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected).
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
void setSelectionColor(const QColor &color)
Sets the color to use when rendering selected features.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.