QGIS API Documentation 4.1.0-Master (9af12b5a203)
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 , mViewportSize( new Qt3DRender::QParameter( "WIN_SCALE", QSizeF( 800, 600 ), this ) )
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 addParameter( mViewportSize );
50
51 // Initialize with empty parameter.
52 mTexture2D = new Qt3DRender::QParameter( "tex0", QVariant(), this );
53 addParameter( mTexture2D );
54
55 // Blending for handling transparency
56 Qt3DRender::QBlendEquationArguments *blendState = new Qt3DRender::QBlendEquationArguments;
57 blendState->setSourceRgb( Qt3DRender::QBlendEquationArguments::SourceAlpha );
58 blendState->setDestinationRgb( Qt3DRender::QBlendEquationArguments::OneMinusSourceAlpha );
59
60 Qt3DRender::QBlendEquation *blendEquation = new Qt3DRender::QBlendEquation;
61 blendEquation->setBlendFunction( Qt3DRender::QBlendEquation::Add );
62
63 // Shader program
64 Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram( this );
65
66 const QUrl urlVert( u"qrc:/shaders/billboards.vert"_s );
67 const QUrl urlGeom( u"qrc:/shaders/billboards.geom"_s );
68
69 switch ( mode )
70 {
72 {
73 shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( urlVert ) );
74 shaderProgram->setGeometryShaderCode( Qt3DRender::QShaderProgram::loadSource( urlGeom ) );
75 break;
76 }
78 {
79 const QByteArray vertexShaderCode = Qt3DRender::QShaderProgram::loadSource( urlVert );
80 const QByteArray finalVertexShaderCode = Qgs3DUtils::addDefinesToShaderCode( vertexShaderCode, QStringList( { "TEXTURE_ATLAS" } ) );
81 shaderProgram->setVertexShaderCode( finalVertexShaderCode );
82
83 const QByteArray geomShaderCode = Qt3DRender::QShaderProgram::loadSource( urlGeom );
84 const QByteArray finalGeomShaderCode = Qgs3DUtils::addDefinesToShaderCode( geomShaderCode, QStringList( { "TEXTURE_ATLAS" } ) );
85 shaderProgram->setGeometryShaderCode( finalGeomShaderCode );
86 break;
87 }
89 {
90 const QByteArray vertexShaderCode = Qt3DRender::QShaderProgram::loadSource( urlVert );
91 const QByteArray finalVertexShaderCode = Qgs3DUtils::addDefinesToShaderCode( vertexShaderCode, QStringList( { "TEXTURE_ATLAS", "TEXTURE_ATLAS_PIXEL_OFFSETS" } ) );
92 shaderProgram->setVertexShaderCode( finalVertexShaderCode );
93
94 const QByteArray geomShaderCode = Qt3DRender::QShaderProgram::loadSource( urlGeom );
95 const QByteArray finalGeomShaderCode = Qgs3DUtils::addDefinesToShaderCode( geomShaderCode, QStringList( { "TEXTURE_ATLAS", "TEXTURE_ATLAS_PIXEL_OFFSETS" } ) );
96 shaderProgram->setGeometryShaderCode( finalGeomShaderCode );
97 break;
98 }
99 }
100 shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( u"qrc:/shaders/billboards.frag"_s ) ) );
101
102 // Render Pass
103 Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass( this );
104 renderPass->setShaderProgram( shaderProgram );
105 renderPass->addRenderState( blendState );
106 renderPass->addRenderState( blendEquation );
107
108 // without this filter the default forward renderer would not render this
109 Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
110 filterKey->setName( u"renderingStyle"_s );
111 filterKey->setValue( "forward" );
112
113 // Technique
114 Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
115 technique->addRenderPass( renderPass );
116 technique->addFilterKey( filterKey );
117 technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
118 technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
119 technique->graphicsApiFilter()->setMajorVersion( 3 );
120 technique->graphicsApiFilter()->setMinorVersion( 1 );
121
122 // Effect
123 Qt3DRender::QEffect *effect = new Qt3DRender::QEffect( this );
124 effect->addTechnique( technique );
125
126 setEffect( effect );
127}
128
130
132{
133 mSize->setValue( size );
134}
135
137{
138 return mSize->value().value<QSizeF>();
139}
140
142{
143 mViewportSize->setValue( size );
144}
145
147{
148 return mViewportSize->value().value<QSizeF>();
149}
150
152{
153 // Create texture image
154 QgsImageTexture *textureImage = new QgsImageTexture( image );
155 setTexture2DFromTextureImage( textureImage );
156
157 setSize( QSizeF( image.size().width(), image.size().height() ) );
158}
159
161{
162 // Default texture
163 const std::unique_ptr<QgsMarkerSymbol> defaultSymbol( static_cast<QgsMarkerSymbol *>( QgsSymbol::defaultSymbol( Qgis::GeometryType::Point ) ) );
164 setTexture2DFromSymbol( defaultSymbol.get(), context, selected );
165}
166
167QImage QgsPoint3DBillboardMaterial::renderSymbolToImage( const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected )
168{
169 QgsRenderContext context2D;
170 context2D.setSelectionColor( context.selectionColor() );
171 context2D.setScaleFactor( context.outputDpi() / 25.4 );
174
175 std::unique_ptr< QgsMarkerSymbol > clonedSymbol( markerSymbol->clone() );
176 clonedSymbol->startRender( context2D );
177
178 constexpr int BUFFER_SIZE_PIXELS = 2;
179
180 const QRectF bounds = markerSymbol->bounds( QPointF( 0, 0 ), context2D );
181
182 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 );
183 image.fill( Qt::transparent );
184
185 QPainter painter( &image );
186 context2D.setPainter( &painter );
187
188 clonedSymbol->renderPoint( QPointF( -bounds.left() + BUFFER_SIZE_PIXELS, -bounds.top() + BUFFER_SIZE_PIXELS ), nullptr, context2D, -1, selected );
189
190 painter.end();
191
192 clonedSymbol->stopRender( context2D );
193 return image;
194}
195
196void QgsPoint3DBillboardMaterial::setTexture2DFromSymbol( const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected )
197{
198 const QImage symbolImage = renderSymbolToImage( markerSymbol, context, selected );
199 setTexture2DFromImage( symbolImage );
200}
201
202void QgsPoint3DBillboardMaterial::setTexture2DFromTextureImage( Qt3DRender::QAbstractTextureImage *textureImage )
203{
204 // Texture2D
205 Qt3DRender::QTexture2D *texture2D = new Qt3DRender::QTexture2D( this );
206 texture2D->setGenerateMipMaps( false );
207 texture2D->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
208 texture2D->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
209 texture2D->setFormat( Qt3DRender::QAbstractTexture::SRGB8_Alpha8 );
210
211 // The textureImage gets parented to texture2D here
212 texture2D->addTextureImage( textureImage );
213
214 mTexture2D->setValue( QVariant::fromValue( texture2D ) );
215}
@ Point
Points.
Definition qgis.h:380
@ Antialiasing
Use antialiasing while drawing.
Definition qgis.h:2920
@ HighQualityImageTransforms
Enable high quality image transformations, which results in better appearance of scaled or rotated ra...
Definition qgis.h:2930
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.
static QImage renderSymbolToImage(const QgsMarkerSymbol *markerSymbol, const Qgs3DRenderContext &context, bool selected=false)
Renders a marker symbol to an image.
@ SingleTexture
Use a single repeated texture for all billboards. Billboard positions should be set using QgsBillboar...
@ AtlasTexture
Use a texture atlas, so each billboard has a different texture. Billboard positions and texture data ...
@ AtlasTextureWithPixelOffsets
Use a texture atlas, so each billboard has a different texture. Billboards have pixel-sized offsets f...
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.
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.
QgsPoint3DBillboardMaterial(Mode mode=Mode::SingleTexture)
Constructor for QgsPoint3DBillboardMaterial, using the specified mode.
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.