Add API to control coefficients (strength) of ambient/diffuse/specular

contributions to phong shader
This commit is contained in:
Nyall Dawson 2024-01-04 08:04:52 +10:00
parent a98d405d9d
commit 0215bf01a3
10 changed files with 316 additions and 5 deletions

View File

@ -72,6 +72,45 @@ Returns shininess of the surface
Returns the opacity of the surface
.. versionadded:: 3.26
%End
float ambientCoefficient() const;
%Docstring
Returns the coefficient for the ambient color contribution (ie strength factor of the ambient color).
.. seealso:: :py:func:`setAmbientCoefficient`
.. seealso:: :py:func:`diffuseCoefficient`
.. seealso:: :py:func:`specularCoefficient`
.. versionadded:: 3.36
%End
float diffuseCoefficient() const;
%Docstring
Returns the coefficient for the diffuse color contribution (ie strength factor of the diffuse color).
.. seealso:: :py:func:`setDiffuseCoefficient`
.. seealso:: :py:func:`ambientCoefficient`
.. seealso:: :py:func:`specularCoefficient`
.. versionadded:: 3.36
%End
float specularCoefficient() const;
%Docstring
Returns the coefficient for the specular color contribution (ie strength factor of the specular color).
.. seealso:: :py:func:`setSpecularCoefficient`
.. seealso:: :py:func:`diffuseCoefficient`
.. seealso:: :py:func:`ambientCoefficient`
.. versionadded:: 3.36
%End
virtual QMap<QString, QString> toExportParameters() const;
@ -101,7 +140,44 @@ Sets opacity of the surface
.. versionadded:: 3.26
%End
void setAmbientCoefficient( float coefficient );
%Docstring
Sets the ``coefficient`` for the ambient color contribution (ie strength factor of the ambient color).
.. seealso:: :py:func:`ambientCoefficient`
.. seealso:: :py:func:`setDiffuseCoefficient`
.. seealso:: :py:func:`setSpecularCoefficient`
.. versionadded:: 3.36
%End
void setDiffuseCoefficient( float coefficient );
%Docstring
Sets the ``coefficient`` for the diffuse color contribution (ie strength factor of the diffuse color).
.. seealso:: :py:func:`diffuseCoefficient`
.. seealso:: :py:func:`setAmbientCoefficient`
.. seealso:: :py:func:`setSpecularCoefficient`
.. versionadded:: 3.36
%End
void setSpecularCoefficient( float coefficient );
%Docstring
Sets the ``coefficient`` for the specular color contribution (ie strength factor of the specular color).
.. seealso:: :py:func:`specularCoefficient`
.. seealso:: :py:func:`setDiffuseCoefficient`
.. seealso:: :py:func:`setAmbientCoefficient`
.. versionadded:: 3.36
%End
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context );

View File

@ -72,6 +72,45 @@ Returns shininess of the surface
Returns the opacity of the surface
.. versionadded:: 3.26
%End
float ambientCoefficient() const;
%Docstring
Returns the coefficient for the ambient color contribution (ie strength factor of the ambient color).
.. seealso:: :py:func:`setAmbientCoefficient`
.. seealso:: :py:func:`diffuseCoefficient`
.. seealso:: :py:func:`specularCoefficient`
.. versionadded:: 3.36
%End
float diffuseCoefficient() const;
%Docstring
Returns the coefficient for the diffuse color contribution (ie strength factor of the diffuse color).
.. seealso:: :py:func:`setDiffuseCoefficient`
.. seealso:: :py:func:`ambientCoefficient`
.. seealso:: :py:func:`specularCoefficient`
.. versionadded:: 3.36
%End
float specularCoefficient() const;
%Docstring
Returns the coefficient for the specular color contribution (ie strength factor of the specular color).
.. seealso:: :py:func:`setSpecularCoefficient`
.. seealso:: :py:func:`diffuseCoefficient`
.. seealso:: :py:func:`ambientCoefficient`
.. versionadded:: 3.36
%End
virtual QMap<QString, QString> toExportParameters() const;
@ -101,7 +140,44 @@ Sets opacity of the surface
.. versionadded:: 3.26
%End
void setAmbientCoefficient( float coefficient );
%Docstring
Sets the ``coefficient`` for the ambient color contribution (ie strength factor of the ambient color).
.. seealso:: :py:func:`ambientCoefficient`
.. seealso:: :py:func:`setDiffuseCoefficient`
.. seealso:: :py:func:`setSpecularCoefficient`
.. versionadded:: 3.36
%End
void setDiffuseCoefficient( float coefficient );
%Docstring
Sets the ``coefficient`` for the diffuse color contribution (ie strength factor of the diffuse color).
.. seealso:: :py:func:`diffuseCoefficient`
.. seealso:: :py:func:`setAmbientCoefficient`
.. seealso:: :py:func:`setSpecularCoefficient`
.. versionadded:: 3.36
%End
void setSpecularCoefficient( float coefficient );
%Docstring
Sets the ``coefficient`` for the specular color contribution (ie strength factor of the specular color).
.. seealso:: :py:func:`specularCoefficient`
.. seealso:: :py:func:`setDiffuseCoefficient`
.. seealso:: :py:func:`setAmbientCoefficient`
.. versionadded:: 3.36
%End
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context );

View File

@ -83,6 +83,9 @@ void QgsPhongMaterialSettings::readXml( const QDomElement &elem, const QgsReadWr
mSpecular = QgsColorUtils::colorFromString( elem.attribute( QStringLiteral( "specular" ), QStringLiteral( "255,255,255" ) ) );
mShininess = elem.attribute( QStringLiteral( "shininess" ) ).toFloat();
mOpacity = elem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.0" ) ).toFloat();
mAmbientCoefficient = elem.attribute( QStringLiteral( "ka" ), QStringLiteral( "1.0" ) ).toFloat();
mDiffuseCoefficient = elem.attribute( QStringLiteral( "kd" ), QStringLiteral( "1.0" ) ).toFloat();
mSpecularCoefficient = elem.attribute( QStringLiteral( "ks" ), QStringLiteral( "1.0" ) ).toFloat();
QgsAbstractMaterialSettings::readXml( elem, context );
}
@ -94,6 +97,9 @@ void QgsPhongMaterialSettings::writeXml( QDomElement &elem, const QgsReadWriteCo
elem.setAttribute( QStringLiteral( "specular" ), QgsColorUtils::colorToString( mSpecular ) );
elem.setAttribute( QStringLiteral( "shininess" ), mShininess );
elem.setAttribute( QStringLiteral( "opacity" ), mOpacity );
elem.setAttribute( QStringLiteral( "ka" ), mAmbientCoefficient );
elem.setAttribute( QStringLiteral( "kd" ), mDiffuseCoefficient );
elem.setAttribute( QStringLiteral( "ks" ), mSpecularCoefficient );
QgsAbstractMaterialSettings::writeXml( elem, context );
}
@ -139,12 +145,18 @@ void QgsPhongMaterialSettings::addParametersToEffect( Qt3DRender::QEffect *effec
Qt3DRender::QParameter *specularParameter = new Qt3DRender::QParameter( QStringLiteral( "specularColor" ), mSpecular );
Qt3DRender::QParameter *shininessParameter = new Qt3DRender::QParameter( QStringLiteral( "shininess" ), mShininess );
Qt3DRender::QParameter *opacityParameter = new Qt3DRender::QParameter( QStringLiteral( "opacity" ), mOpacity );
Qt3DRender::QParameter *kaParameter = new Qt3DRender::QParameter( QStringLiteral( "ka" ), mAmbientCoefficient );
Qt3DRender::QParameter *kdParameter = new Qt3DRender::QParameter( QStringLiteral( "kd" ), mDiffuseCoefficient );
Qt3DRender::QParameter *ksParameter = new Qt3DRender::QParameter( QStringLiteral( "ks" ), mSpecularCoefficient );
effect->addParameter( ambientParameter );
effect->addParameter( diffuseParameter );
effect->addParameter( specularParameter );
effect->addParameter( shininessParameter );
effect->addParameter( opacityParameter );
effect->addParameter( kaParameter );
effect->addParameter( kdParameter );
effect->addParameter( ksParameter );
}
QByteArray QgsPhongMaterialSettings::dataDefinedVertexColorsAsByte( const QgsExpressionContext &expressionContext ) const
@ -247,6 +259,9 @@ Qt3DRender::QMaterial *QgsPhongMaterialSettings::constantColorMaterial( const Qg
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ambientColor" ), context.isSelected() ? context.selectionColor().darker() : mAmbient ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "diffuseColor" ), context.isSelected() ? context.selectionColor() : mDiffuse ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "specularColor" ), mSpecular ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ka" ), mAmbientCoefficient ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "kd" ), mDiffuseCoefficient ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ks" ), mSpecularCoefficient ) );
if ( mOpacity < 1.0f )
{
@ -300,6 +315,9 @@ Qt3DRender::QMaterial *QgsPhongMaterialSettings::dataDefinedMaterial() const
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "shininess" ), mShininess ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "opacity" ), mOpacity ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ka" ), mAmbientCoefficient ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "kd" ), mDiffuseCoefficient ) );
eff->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ks" ), mSpecularCoefficient ) );
if ( mOpacity < 1.0f )
{

View File

@ -71,6 +71,39 @@ class _3D_EXPORT QgsPhongMaterialSettings : public QgsAbstractMaterialSettings
*/
float opacity() const { return mOpacity; }
/**
* Returns the coefficient for the ambient color contribution (ie strength factor of the ambient color).
*
* \see setAmbientCoefficient()
* \see diffuseCoefficient()
* \see specularCoefficient()
*
* \since QGIS 3.36
*/
float ambientCoefficient() const { return mAmbientCoefficient; }
/**
* Returns the coefficient for the diffuse color contribution (ie strength factor of the diffuse color).
*
* \see setDiffuseCoefficient()
* \see ambientCoefficient()
* \see specularCoefficient()
*
* \since QGIS 3.36
*/
float diffuseCoefficient() const { return mDiffuseCoefficient; }
/**
* Returns the coefficient for the specular color contribution (ie strength factor of the specular color).
*
* \see setSpecularCoefficient()
* \see diffuseCoefficient()
* \see ambientCoefficient()
*
* \since QGIS 3.36
*/
float specularCoefficient() const { return mSpecularCoefficient; }
QMap<QString, QString> toExportParameters() const override;
//! Sets ambient color component
@ -88,7 +121,38 @@ class _3D_EXPORT QgsPhongMaterialSettings : public QgsAbstractMaterialSettings
*/
void setOpacity( float opacity ) { mOpacity = opacity; }
/**
* Sets the \a coefficient for the ambient color contribution (ie strength factor of the ambient color).
*
* \see ambientCoefficient()
* \see setDiffuseCoefficient()
* \see setSpecularCoefficient()
*
* \since QGIS 3.36
*/
void setAmbientCoefficient( float coefficient ) { mAmbientCoefficient = coefficient; }
/**
* Sets the \a coefficient for the diffuse color contribution (ie strength factor of the diffuse color).
*
* \see diffuseCoefficient()
* \see setAmbientCoefficient()
* \see setSpecularCoefficient()
*
* \since QGIS 3.36
*/
void setDiffuseCoefficient( float coefficient ) { mDiffuseCoefficient = coefficient; }
/**
* Sets the \a coefficient for the specular color contribution (ie strength factor of the specular color).
*
* \see specularCoefficient()
* \see setDiffuseCoefficient()
* \see setAmbientCoefficient()
*
* \since QGIS 3.36
*/
void setSpecularCoefficient( float coefficient ) { mSpecularCoefficient = coefficient; }
void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override;
void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const override;
@ -113,7 +177,10 @@ class _3D_EXPORT QgsPhongMaterialSettings : public QgsAbstractMaterialSettings
mDiffuse == other.mDiffuse &&
mOpacity == other.mOpacity &&
mSpecular == other.mSpecular &&
mShininess == other.mShininess;
mShininess == other.mShininess &&
mAmbientCoefficient == other.mAmbientCoefficient &&
mDiffuseCoefficient == other.mDiffuseCoefficient &&
mSpecularCoefficient == other.mSpecularCoefficient;
}
private:
@ -121,6 +188,11 @@ class _3D_EXPORT QgsPhongMaterialSettings : public QgsAbstractMaterialSettings
QColor mDiffuse{ QColor::fromRgbF( 0.7f, 0.7f, 0.7f, 1.0f ) };
QColor mSpecular{ QColor::fromRgbF( 1.0f, 1.0f, 1.0f, 1.0f ) };
float mShininess = 0.0f;
float mAmbientCoefficient = 1.0f;
float mDiffuseCoefficient = 1.0f;
float mSpecularCoefficient = 1.0f;
float mOpacity = 1.0f;
//! Constructs a material from shader files

View File

@ -21,5 +21,6 @@ void main(void)
vec3 worldView = normalize(eyePosition - worldPosition);
fragColor = phongFunction(ambientColor, diffuseTextureColor, specularColor,
shininess,
1.0, 1.0, 1.0,
worldPosition, worldView, worldNormal);
}

View File

@ -6,6 +6,9 @@ vec4 phongFunction(const in vec4 ambient,
const in vec4 diffuse,
const in vec4 specular,
const in float shin,
const in float ka,
const in float kd,
const in float ks,
const in vec3 worldPosition,
const in vec3 worldView,
const in vec3 worldNormal)
@ -15,9 +18,9 @@ vec4 phongFunction(const in vec4 ambient,
adsModel(worldPosition, worldNormal, worldView, shin, diffuseColor, specularColor);
// Combine spec with ambient+diffuse for final fragment color
vec3 color = ambient.rgb
+ diffuseColor * diffuse.rgb
+ specularColor * specular.rgb;
vec3 color = ka * ambient.rgb
+ kd * diffuseColor * diffuse.rgb
+ ks * specularColor * specular.rgb;
return vec4(color, diffuse.a);
}

View File

@ -7,6 +7,9 @@ in vec3 worldNormal;
uniform float shininess;
uniform float opacity;
uniform float ka;
uniform float kd;
uniform float ks;
uniform vec3 ambientColor;
uniform vec3 diffuseColor;
uniform vec3 specularColor;
@ -23,6 +26,7 @@ void main(void)
vec4(diffuseColor, opacity),
vec4(specularColor, opacity),
shininess,
ka, kd, ks,
worldPosition,
worldView,
worldNormal);

View File

@ -2,6 +2,9 @@
uniform vec3 eyePosition;
uniform float shininess;
uniform float ka;
uniform float kd;
uniform float ks;
in vec3 worldPosition;
in vec3 worldNormal;
@ -19,5 +22,13 @@ out vec4 fragColor;
void main(void)
{
vec3 worldView = normalize(eyePosition - worldPosition);
fragColor = phongFunction(vs_in.ambient,vs_in.diffuse,vs_in.specular, shininess, worldPosition, worldView, worldNormal);
fragColor = phongFunction(
vs_in.ambient,
vs_in.diffuse,
vs_in.specular,
shininess,
ka, kd, ks,
worldPosition,
worldView,
worldNormal);
}

View File

@ -75,6 +75,7 @@ class TestQgs3DRendering : public QgsTest
void testTerrainShading();
void testEpsg4978LineRendering();
void testExtrudedPolygons();
void testPhongShading();
void testExtrudedPolygonsDataDefined();
void testExtrudedPolygonsGoochShading();
void testExtrudedPolygonsMetalRoughShading();
@ -452,6 +453,55 @@ void TestQgs3DRendering::testExtrudedPolygons()
QGSVERIFYIMAGECHECK( "polygon3d_extrusion_opacity", "polygon3d_extrusion_opacity", img2, QString(), 40, QSize( 0, 0 ), 2 );
}
void TestQgs3DRendering::testPhongShading()
{
const QgsRectangle fullExtent = mLayerDtm->extent();
std::unique_ptr< QgsVectorLayer > buildings = std::make_unique< QgsVectorLayer >( testDataPath( "/3d/buildings.shp" ), "buildings", "ogr" );
QVERIFY( buildings->isValid() );
QgsPhongMaterialSettings materialSettings;
materialSettings.setAmbient( QColor( 0, 100, 0 ) );
materialSettings.setDiffuse( QColor( 255, 0, 255 ) );
materialSettings.setSpecular( QColor( 0, 255, 255 ) );
materialSettings.setShininess( 2 );
materialSettings.setAmbientCoefficient( 0.3 );
materialSettings.setDiffuseCoefficient( 0.8 );
materialSettings.setSpecularCoefficient( 0.7 );
QgsPolygon3DSymbol *symbol3d = new QgsPolygon3DSymbol;
symbol3d->setMaterialSettings( materialSettings.clone() );
symbol3d->setExtrusionHeight( 10.f );
QgsVectorLayer3DRenderer *renderer3d = new QgsVectorLayer3DRenderer( symbol3d );
buildings->setRenderer3D( renderer3d );
Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setExtent( fullExtent );
map->setLayers( QList<QgsMapLayer *>() << buildings.get() );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( {defaultLight.clone() } );
QgsFlatTerrainGenerator *flatTerrain = new QgsFlatTerrainGenerator;
flatTerrain->setCrs( map->crs() );
map->setTerrainGenerator( flatTerrain );
QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );
scene->cameraController()->setLookingAtPoint( QgsVector3D( 0, 0, 250 ), 300, 45, 0 );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
Qgs3DUtils::captureSceneImage( engine, scene );
QImage img = Qgs3DUtils::captureSceneImage( engine, scene );
QGSVERIFYIMAGECHECK( "phong_shading", "phong_shading", img, QString(), 40, QSize( 0, 0 ), 2 );
}
void TestQgs3DRendering::testExtrudedPolygonsDataDefined()
{
QgsPropertyCollection propertyColection;

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB