Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3D] Use QGIS material for the terrain #58134

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Sets diffuse color component
%Docstring
Sets specular color component
%End
void setShininess( float shininess );
void setShininess( double shininess );
%Docstring
Sets shininess of the surface
%End
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ A phong shading model with diffuse texture map.
QgsPhongTexturedMaterialSettings();
%Docstring
Constructor for QgsPhongTexturedMaterialSettings.
%End

QgsPhongTexturedMaterialSettings( const QgsPhongMaterialSettings &phongSettings, const QImage &diffuse );
%Docstring
Constructor for QgsPhongTexturedMaterialSettings from ``phongSettings`` and ``texture``
Texture can be either a path as a QString or a texture as a Qt3DRender.QTexture2D*.

.. versionadded:: 3.40
%End

virtual QString type() const;
Expand All @@ -57,7 +65,7 @@ Returns ambient color component
%Docstring
Returns specular color component
%End
float shininess() const;
double shininess() const;
%Docstring
Returns shininess of the surface
%End
Expand Down Expand Up @@ -90,7 +98,7 @@ during triangulation.quiresTextureCoordinates
Returns the texture rotation, in degrees.
%End

float opacity() const;
double opacity() const;
%Docstring
Returns the opacity of the surface

Expand All @@ -106,16 +114,26 @@ Sets ambient color component
%Docstring
Sets specular color component
%End
void setShininess( float shininess );
void setShininess( double shininess );
%Docstring
Sets shininess of the surface
%End

void setDiffuseTexturePath( const QString &path );
%Docstring
Sets the ``path`` of the diffuse texture.
This will reset the texture if defined.

.. seealso:: :py:func:`diffuseTexturePath`

.. seealso:: :py:func:`setDiffuseTexture`
%End

void setDiffuseTexture( const QImage &diffuse );
%Docstring
Sets the diffuse texture component of the material.

.. versionadded:: 3.40
%End

void setTextureScale( float scale );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Sets diffuse color component
%Docstring
Sets specular color component
%End
void setShininess( float shininess );
void setShininess( double shininess );
%Docstring
Sets shininess of the surface
%End
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ A phong shading model with diffuse texture map.
QgsPhongTexturedMaterialSettings();
%Docstring
Constructor for QgsPhongTexturedMaterialSettings.
%End

QgsPhongTexturedMaterialSettings( const QgsPhongMaterialSettings &phongSettings, const QImage &diffuse );
%Docstring
Constructor for QgsPhongTexturedMaterialSettings from ``phongSettings`` and ``texture``
Texture can be either a path as a QString or a texture as a Qt3DRender.QTexture2D*.

.. versionadded:: 3.40
%End

virtual QString type() const;
Expand All @@ -57,7 +65,7 @@ Returns ambient color component
%Docstring
Returns specular color component
%End
float shininess() const;
double shininess() const;
%Docstring
Returns shininess of the surface
%End
Expand Down Expand Up @@ -90,7 +98,7 @@ during triangulation.quiresTextureCoordinates
Returns the texture rotation, in degrees.
%End

float opacity() const;
double opacity() const;
%Docstring
Returns the opacity of the surface

Expand All @@ -106,16 +114,26 @@ Sets ambient color component
%Docstring
Sets specular color component
%End
void setShininess( float shininess );
void setShininess( double shininess );
%Docstring
Sets shininess of the surface
%End

void setDiffuseTexturePath( const QString &path );
%Docstring
Sets the ``path`` of the diffuse texture.
This will reset the texture if defined.

.. seealso:: :py:func:`diffuseTexturePath`

.. seealso:: :py:func:`setDiffuseTexture`
%End

void setDiffuseTexture( const QImage &diffuse );
%Docstring
Sets the diffuse texture component of the material.

.. versionadded:: 3.40
%End

void setTextureScale( float scale );
Expand Down
2 changes: 2 additions & 0 deletions src/3d/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ set(QGIS_3D_SRCS
materials/qgsphongmaterialsettings.cpp
materials/qgsphongtexturedmaterialsettings.cpp
materials/qgssimplelinematerialsettings.cpp
materials/qgstexturematerial.cpp

processing/qgs3dalgorithms.cpp
processing/qgsalgorithmtessellate.cpp
Expand Down Expand Up @@ -165,6 +166,7 @@ set(QGIS_3D_HDRS
materials/qgsphongmaterialsettings.h
materials/qgsphongtexturedmaterialsettings.h
materials/qgssimplelinematerialsettings.h
materials/qgstexturematerial.h

symbols/qgsbillboardgeometry.h
symbols/qgsline3dsymbol.h
Expand Down
2 changes: 1 addition & 1 deletion src/3d/materials/qgsphongmaterialsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class _3D_EXPORT QgsPhongMaterialSettings : public QgsAbstractMaterialSettings
//! Sets specular color component
void setSpecular( const QColor &specular ) { mSpecular = specular; }
//! Sets shininess of the surface
void setShininess( float shininess ) { mShininess = shininess; }
void setShininess( double shininess ) { mShininess = shininess; }

/**
* Sets opacity of the surface
Expand Down
179 changes: 107 additions & 72 deletions src/3d/materials/qgsphongtexturedmaterialsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,25 @@
#include "qgsimagecache.h"
#include "qgsimagetexture.h"
#include "qgsphongmaterialsettings.h"
#include "qgsterraintextureimage_p.h"
#include <Qt3DRender/QPaintedTextureImage>
#include <Qt3DRender/QTexture>
#include <Qt3DRender/QParameter>
#include <Qt3DRender/QEffect>
#include <Qt3DRender/QTechnique>
#include <Qt3DRender/QGraphicsApiFilter>
#include <QMap>


QgsPhongTexturedMaterialSettings::QgsPhongTexturedMaterialSettings( const QgsPhongMaterialSettings &phongSettings, const QImage &diffuse )
: mAmbient( phongSettings.ambient() )
, mSpecular( phongSettings.specular() )
, mShininess( phongSettings.shininess() )
, mOpacity( phongSettings.opacity() )
, mDiffuseTextureImage( diffuse )
{

}

QString QgsPhongTexturedMaterialSettings::type() const
{
return QStringLiteral( "phongtextured" );
Expand Down Expand Up @@ -71,8 +81,8 @@ void QgsPhongTexturedMaterialSettings::readXml( const QDomElement &elem, const Q
{
mAmbient = QgsColorUtils::colorFromString( elem.attribute( QStringLiteral( "ambient" ), QStringLiteral( "25,25,25" ) ) );
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();
mShininess = elem.attribute( QStringLiteral( "shininess" ) ).toDouble();
mOpacity = elem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.0" ) ).toDouble();
mDiffuseTexturePath = elem.attribute( QStringLiteral( "diffuse_texture_path" ), QString() );
mTextureScale = elem.attribute( QStringLiteral( "texture_scale" ), QString( "1.0" ) ).toFloat();
mTextureRotation = elem.attribute( QStringLiteral( "texture-rotation" ), QString( "0.0" ) ).toFloat();
Expand Down Expand Up @@ -104,79 +114,92 @@ Qt3DRender::QMaterial *QgsPhongTexturedMaterialSettings::toMaterial( QgsMaterial
case QgsMaterialSettingsRenderingTechnique::TrianglesFromModel:
case QgsMaterialSettingsRenderingTechnique::TrianglesDataDefined:
{
bool fitsInCache = false;
const QImage textureSourceImage = QgsApplication::imageCache()->pathAsImage( mDiffuseTexturePath, QSize(), true, 1.0, fitsInCache );
( void )fitsInCache;
Qt3DRender::QMaterial *material = nullptr;
QImage textureSourceImage = mDiffuseTextureImage.copy();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we doing explicit copy of the QImage here, and in QgsPhongTexturedMaterialSettings::setDiffuseTexture() ?


// No texture image was provided.
// Fallback to QgsPhongMaterialSettings.
// if mDiffuseTextureImage is not set
// Try to load texture from a path
if ( textureSourceImage.isNull() )
{
QgsPhongMaterialSettings phongSettings = QgsPhongMaterialSettings();
phongSettings.setAmbient( mAmbient );
phongSettings.setDiffuse( QColor::fromRgbF( 0.7f, 0.7f, 0.7f, 1.0f ) ); // default diffuse color from QDiffuseSpecularMaterial
phongSettings.setOpacity( mOpacity );
phongSettings.setShininess( mShininess );
phongSettings.setSpecular( mSpecular );
Qt3DRender::QMaterial *material = phongSettings.toMaterial( technique, context );
return material;
bool fitsInCache = false;
textureSourceImage = QgsApplication::imageCache()->pathAsImage( mDiffuseTexturePath, QSize(), true, 1.0, fitsInCache );
( void )fitsInCache;

// No texture image was provided.
// Fallback to QgsPhongMaterialSettings.
if ( textureSourceImage.isNull() )
{
QgsPhongMaterialSettings phongSettings = QgsPhongMaterialSettings();
phongSettings.setAmbient( mAmbient );
phongSettings.setDiffuse( QColor::fromRgbF( 0.7f, 0.7f, 0.7f, 1.0f ) ); // default diffuse color from QDiffuseSpecularMaterial
phongSettings.setOpacity( mOpacity );
phongSettings.setShininess( mShininess );
phongSettings.setSpecular( mSpecular );
material = phongSettings.toMaterial( technique, context );
}
}

// create the material based on the provided texture
if ( !material )
{
// Use a custom material because Qt3DRender::QTexture2D does not handle opacity.
material = new Qt3DRender::QMaterial;

Qt3DRender::QEffect *effect = new Qt3DRender::QEffect( material );

Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
technique->graphicsApiFilter()->setMajorVersion( 3 );
technique->graphicsApiFilter()->setMinorVersion( 3 );
Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey();
filterKey->setName( QStringLiteral( "renderingStyle" ) );
filterKey->setValue( QStringLiteral( "forward" ) );
technique->addFilterKey( filterKey );

Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass();
Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram();

//Load shader programs
const QUrl urlVert( QStringLiteral( "qrc:/shaders/default.vert" ) );
shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Vertex, Qt3DRender::QShaderProgram::loadSource( urlVert ) );
const QUrl urlFrag( QStringLiteral( "qrc:/shaders/diffuseSpecular.frag" ) );
shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Fragment, Qt3DRender::QShaderProgram::loadSource( urlFrag ) );

renderPass->setShaderProgram( shaderProgram );
technique->addRenderPass( renderPass );

int opacity = static_cast<int>( mOpacity * 255.0 );
QColor ambient = context.isSelected() ? context.selectionColor().darker() : mAmbient;
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ambientColor" ), QColor( ambient.red(), ambient.green(), ambient.blue(), opacity ) ) );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "specularColor" ), QColor( mSpecular.red(), mSpecular.green(), mSpecular.blue(), opacity ) ) );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "shininess" ), static_cast<float>( mShininess ) ) );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "opacity" ), static_cast<float>( mOpacity ) ) );

effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "texCoordScale" ), mTextureScale ) );

// Create the texture and add it to the shader
// TODO : if ( context.isSelected() ) dampen the color of diffuse texture
// with context.map().selectionColor()
QgsImageTexture *textureImage = new QgsImageTexture( textureSourceImage );
Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D();
texture->addTextureImage( textureImage );

texture->wrapMode()->setX( Qt3DRender::QTextureWrapMode::Repeat );
texture->wrapMode()->setY( Qt3DRender::QTextureWrapMode::Repeat );
texture->wrapMode()->setZ( Qt3DRender::QTextureWrapMode::Repeat );

texture->setSamples( 4 );

texture->setGenerateMipMaps( true );
texture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
texture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "diffuseTexture" ), QVariant::fromValue( texture ) ) );

effect->addTechnique( technique );
material->setEffect( effect );
}

// Use a custom material because Qt3DRender::QTexture2D does not handle opacity.
Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;

Qt3DRender::QEffect *effect = new Qt3DRender::QEffect( material );

Qt3DRender::QTechnique *technique = new Qt3DRender::QTechnique;
technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
technique->graphicsApiFilter()->setMajorVersion( 3 );
technique->graphicsApiFilter()->setMinorVersion( 3 );
Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey();
filterKey->setName( QStringLiteral( "renderingStyle" ) );
filterKey->setValue( QStringLiteral( "forward" ) );
technique->addFilterKey( filterKey );

Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass();
Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram();

//Load shader programs
const QUrl urlVert( QStringLiteral( "qrc:/shaders/default.vert" ) );
shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Vertex, Qt3DRender::QShaderProgram::loadSource( urlVert ) );
const QUrl urlFrag( QStringLiteral( "qrc:/shaders/diffuseSpecular.frag" ) );
shaderProgram->setShaderCode( Qt3DRender::QShaderProgram::Fragment, Qt3DRender::QShaderProgram::loadSource( urlFrag ) );

renderPass->setShaderProgram( shaderProgram );
technique->addRenderPass( renderPass );

int opacity = mOpacity * 255;
QColor ambient = context.isSelected() ? context.selectionColor().darker() : mAmbient;
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ambientColor" ), QColor( ambient.red(), ambient.green(), ambient.blue(), opacity ) ) );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "specularColor" ), QColor( mSpecular.red(), mSpecular.green(), mSpecular.blue(), opacity ) ) );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "shininess" ), mShininess ) );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "opacity" ), mOpacity ) );

// TODO : if ( context.isSelected() ) dampen the color of diffuse texture
// with context.map().selectionColor()
QgsImageTexture *textureImage = new QgsImageTexture( textureSourceImage );
Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D();
texture->addTextureImage( textureImage );

texture->wrapMode()->setX( Qt3DRender::QTextureWrapMode::Repeat );
texture->wrapMode()->setY( Qt3DRender::QTextureWrapMode::Repeat );
texture->wrapMode()->setZ( Qt3DRender::QTextureWrapMode::Repeat );

texture->setSamples( 4 );

texture->setGenerateMipMaps( true );
texture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
texture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );

effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "diffuseTexture" ), QVariant::fromValue( texture ) ) );
effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "texCoordScale" ), mTextureScale ) );

effect->addTechnique( technique );
material->setEffect( effect );
return material;
}

Expand All @@ -202,9 +225,21 @@ void QgsPhongTexturedMaterialSettings::addParametersToEffect( Qt3DRender::QEffec

Qt3DRender::QParameter *ambientParameter = new Qt3DRender::QParameter( QStringLiteral( "ambientColor" ), ambientColor );
Qt3DRender::QParameter *specularParameter = new Qt3DRender::QParameter( QStringLiteral( "specularColor" ), mSpecular );
Qt3DRender::QParameter *shininessParameter = new Qt3DRender::QParameter( QStringLiteral( "shininess" ), mShininess );
Qt3DRender::QParameter *shininessParameter = new Qt3DRender::QParameter( QStringLiteral( "shininess" ), static_cast<float>( mShininess ) );

effect->addParameter( ambientParameter );
effect->addParameter( specularParameter );
effect->addParameter( shininessParameter );
}

void QgsPhongTexturedMaterialSettings::setDiffuseTexturePath( const QString &path )
{
mDiffuseTextureImage = QImage();
mDiffuseTexturePath = path;
}

void QgsPhongTexturedMaterialSettings::setDiffuseTexture( const QImage &diffuse )
{
mDiffuseTextureImage = diffuse.copy();
mDiffuseTexturePath.clear();
}
Loading
Loading