QGIS API Documentation 4.1.0-Master (3fcefe620d1)
Loading...
Searching...
No Matches
qgsmetalroughtexturedmaterialsettings.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmetalroughtexturedmaterialsettings.cpp
3 --------------------------------------
4 Date : April 2026
5 Copyright : (C) 2026 by Nyall Dawson
6 Email : nyall dot dawson 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
17
18#include "qgsapplication.h"
19#include "qgsimagecache.h"
20#include "qgssymbollayerutils.h"
21
22#include <QString>
23
24using namespace Qt::StringLiterals;
25
27{
28 return u"metalroughtextured"_s;
29}
30
49
54
59
61{
62 const QgsMetalRoughTexturedMaterialSettings *otherMetal = dynamic_cast<const QgsMetalRoughTexturedMaterialSettings *>( other );
63 if ( !otherMetal )
64 return false;
65
66 return *this == *otherMetal;
67}
68
73
78
80{
81 return !mNormalTexturePath.isEmpty() || !mHeightTexturePath.isEmpty();
82}
83
84QColor QgsMetalRoughTexturedMaterialSettings::textureAverageColor( const QString &texturePath ) const
85{
86 bool fitsInCache = false;
87 QImage texture = QgsApplication::imageCache()->pathAsImage( texturePath, QSize(), true, 1.0, fitsInCache );
88 if ( texture.isNull() )
89 {
90 return QColor( 127, 127, 127 );
91 }
92
93 if ( texture.format() != QImage::Format_ARGB32 )
94 {
95 texture = texture.convertToFormat( QImage::Format_ARGB32 );
96 }
97
98 unsigned long long red = 0;
99 unsigned long long green = 0;
100 unsigned long long blue = 0;
101 unsigned long long pixelCount = 0;
102
103 // downsampling to ensure a fast computation
104 const int sampleStep = std::min( texture.width() / 5, texture.height() / 5 );
105 const int width = texture.width();
106 const int height = texture.height();
107 for ( int y = 0; y < height; y += sampleStep )
108 {
109 const QRgb *line = reinterpret_cast< const QRgb * >( texture.constScanLine( y ) );
110 for ( int x = 0; x < width; x += sampleStep )
111 {
112 const QRgb pixel = line[x];
113 red += qRed( pixel );
114 green += qGreen( pixel );
115 blue += qBlue( pixel );
116 pixelCount++;
117 }
118 }
119
120 return QColor( static_cast<int>( red / pixelCount ), static_cast<int>( green / pixelCount ), static_cast<int>( blue / pixelCount ) );
121}
122
124{
125 if ( mAverageColor.has_value() )
126 {
127 return *mAverageColor;
128 }
129
130 mAverageColor = textureAverageColor( mBaseColorTexturePath );
131 if ( !mEmissionTexturePath.isEmpty() )
132 {
133 const QColor emission = textureAverageColor( mEmissionTexturePath );
134
135 const double red = std::clamp( mAverageColor->redF() + emission.redF() * mEmissionFactor, 0.0, 1.0 );
136 const double green = std::clamp( mAverageColor->greenF() + emission.greenF() * mEmissionFactor, 0.0, 1.0 );
137 const double blue = std::clamp( mAverageColor->blueF() + emission.blueF() * mEmissionFactor, 0.0, 1.0 );
138
139 mAverageColor = QColor::fromRgbF( static_cast<float>( red ), static_cast<float>( green ), static_cast<float>( blue ) );
140 }
141
142 return *mAverageColor;
143}
144
146{
147 Q_UNUSED( baseColor );
148 QgsDebugMsgLevel( u"setColorsFromBase() has no effect for textured PBR materials"_s, 2 );
149}
150
151void QgsMetalRoughTexturedMaterialSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
152{
153 mBaseColorTexturePath = elem.attribute( u"base_color_texture_path"_s, QString() );
154 mMetalnessTexturePath = elem.attribute( u"metalness_texture_path"_s, QString() );
155 mRoughnessTexturePath = elem.attribute( u"roughness_texture_path"_s, QString() );
156 mNormalTexturePath = elem.attribute( u"normal_texture_path"_s, QString() );
157 mHeightTexturePath = elem.attribute( u"height_texture_path"_s, QString() );
158 mAmbientOcclusionTexturePath = elem.attribute( u"ambient_occlusion_texture_path"_s, QString() );
159 mEmissionTexturePath = elem.attribute( u"emission_texture_path"_s, QString() );
160 mEmissionFactor = elem.attribute( u"emission_factor"_s, QString( "1.0" ) ).toDouble();
161 mParallaxScale = elem.attribute( u"parallax_scale"_s, QString( "0.1" ) ).toDouble();
162 mTextureScale = elem.attribute( u"texture_scale"_s, QString( "1.0" ) ).toDouble();
163 mTextureRotation = elem.attribute( u"texture_rotation"_s, QString( "0.0" ) ).toDouble();
164 mTextureOffset = QgsSymbolLayerUtils::decodePoint( elem.attribute( u"texture_offset"_s ) );
165 mOpacity = elem.attribute( u"opacity"_s, u"1.0"_s ).toDouble();
166
168}
169
170void QgsMetalRoughTexturedMaterialSettings::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
171{
172 elem.setAttribute( u"base_color_texture_path"_s, mBaseColorTexturePath );
173 elem.setAttribute( u"metalness_texture_path"_s, mMetalnessTexturePath );
174 elem.setAttribute( u"roughness_texture_path"_s, mRoughnessTexturePath );
175 elem.setAttribute( u"normal_texture_path"_s, mNormalTexturePath );
176 elem.setAttribute( u"parallax_scale"_s, mParallaxScale );
177 elem.setAttribute( u"height_texture_path"_s, mHeightTexturePath );
178 elem.setAttribute( u"emission_texture_path"_s, mEmissionTexturePath );
179 elem.setAttribute( u"ambient_occlusion_texture_path"_s, mAmbientOcclusionTexturePath );
180 if ( !qgsDoubleNear( mEmissionFactor, 1.0 ) )
181 elem.setAttribute( u"emission_factor"_s, mEmissionFactor );
182 elem.setAttribute( u"texture_scale"_s, mTextureScale );
183 elem.setAttribute( u"texture_rotation"_s, mTextureRotation );
184 if ( !qgsDoubleNear( mTextureOffset.x(), 0 ) || !qgsDoubleNear( mTextureOffset.y(), 0 ) )
185 elem.setAttribute( u"texture_offset"_s, QgsSymbolLayerUtils::encodePoint( mTextureOffset ) );
186 if ( !qgsDoubleNear( mOpacity, 1 ) )
187 elem.setAttribute( u"opacity"_s, mOpacity );
188
190}
MaterialRenderingTechnique
Material rendering techniques.
Definition qgis.h:4375
@ Points
Point based rendering, requires point data.
Definition qgis.h:4379
@ Triangles
Triangle based rendering (default).
Definition qgis.h:4376
@ TrianglesFromModel
Triangle based rendering, using a model object source.
Definition qgis.h:4381
@ Lines
Line based rendering, requires line data.
Definition qgis.h:4377
@ Billboards
Flat billboard rendering.
Definition qgis.h:4383
@ TrianglesDataDefined
Triangle based rendering with possibility of datadefined color.
Definition qgis.h:4382
@ InstancedPoints
Instanced based rendering, requiring triangles and point data.
Definition qgis.h:4378
@ TrianglesWithFixedTexture
Triangle based rendering, using a fixed, non-user-configurable texture (e.g. for terrain rendering).
Definition qgis.h:4380
Abstract base class for material settings.
virtual void writeXml(QDomElement &element, const QgsReadWriteContext &) const
Writes settings to a DOM element.
virtual void readXml(const QDomElement &element, const QgsReadWriteContext &)
Reads settings from a DOM element.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
bool requiresTangents() const override
Returns true if the material requires tangents generated during triangulation.
QString type() const override
Returns the unique type name for the material.
QgsMetalRoughTexturedMaterialSettings * clone() const override
Clones the material settings.
static QgsAbstractMaterialSettings * create()
Returns a new instance of QgsMetalRoughTexturedMaterialSettings.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const override
Writes settings to a DOM element.
QColor averageColor() const override
Returns an approximate color representing the blended material color.
void setColorsFromBase(const QColor &baseColor) override
Decomposes a base color into the material's color components, and sets the material's colors accordin...
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads settings from a DOM element.
QSet< QgsAbstractMaterialSettings::Property > supportedProperties() const override
Returns the set of data-defined properties supported by this material.
bool equals(const QgsAbstractMaterialSettings *other) const override
Returns true if this settings exactly matches an other settings.
bool requiresTextureCoordinates() const override
Returns true if the material requires texture coordinates to be generated during triangulation.
static bool supportsTechnique(Qgis::MaterialRenderingTechnique technique)
Returns true if the specified technique is supported by the metal rough material.
A container for the context for various read/write operations on objects.
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7340
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:80