diff --git a/python/3d/auto_generated/materials/qgsphongtexturedmaterialsettings.sip.in b/python/3d/auto_generated/materials/qgsphongtexturedmaterialsettings.sip.in index d9e7d025565..231118b0ff3 100644 --- a/python/3d/auto_generated/materials/qgsphongtexturedmaterialsettings.sip.in +++ b/python/3d/auto_generated/materials/qgsphongtexturedmaterialsettings.sip.in @@ -88,6 +88,13 @@ during triangulation.quiresTextureCoordinates float textureRotation() const; %Docstring Returns the texture rotation, in degrees. +%End + + float opacity() const; +%Docstring +Returns the opacity of the surface + +.. versionadded:: 3.28 %End void setAmbient( const QColor &ambient ); @@ -121,6 +128,13 @@ If the texture scale is less than 1 the texture will be stretched void setTextureRotation( float rotation ); %Docstring Sets the texture rotation in degrees +%End + + void setOpacity( float opacity ); +%Docstring +Sets opacity of the surface. + +.. versionadded:: 3.28 %End virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context ); diff --git a/src/3d/materials/qgsphongtexturedmaterialsettings.cpp b/src/3d/materials/qgsphongtexturedmaterialsettings.cpp index 9f5a37ea796..e06e822d073 100644 --- a/src/3d/materials/qgsphongtexturedmaterialsettings.cpp +++ b/src/3d/materials/qgsphongtexturedmaterialsettings.cpp @@ -20,11 +20,12 @@ #include "qgsimagecache.h" #include "qgsimagetexture.h" #include "qgsphongmaterialsettings.h" -#include #include #include #include #include +#include +#include #include @@ -71,6 +72,7 @@ void QgsPhongTexturedMaterialSettings::readXml( const QDomElement &elem, const Q mAmbient = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "ambient" ), QStringLiteral( "25,25,25" ) ) ); mSpecular = QgsSymbolLayerUtils::decodeColor( elem.attribute( QStringLiteral( "specular" ), QStringLiteral( "255,255,255" ) ) ); mShininess = elem.attribute( QStringLiteral( "shininess" ) ).toFloat(); + mOpacity = elem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.0" ) ).toFloat(); 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(); @@ -83,6 +85,7 @@ void QgsPhongTexturedMaterialSettings::writeXml( QDomElement &elem, const QgsRea elem.setAttribute( QStringLiteral( "ambient" ), QgsSymbolLayerUtils::encodeColor( mAmbient ) ); elem.setAttribute( QStringLiteral( "specular" ), QgsSymbolLayerUtils::encodeColor( mSpecular ) ); elem.setAttribute( QStringLiteral( "shininess" ), mShininess ); + elem.setAttribute( QStringLiteral( "opacity" ), mOpacity ); elem.setAttribute( QStringLiteral( "diffuse_texture_path" ), mDiffuseTexturePath ); elem.setAttribute( QStringLiteral( "texture_scale" ), mTextureScale ); elem.setAttribute( QStringLiteral( "texture-rotation" ), mTextureRotation ); @@ -113,16 +116,50 @@ Qt3DRender::QMaterial *QgsPhongTexturedMaterialSettings::toMaterial( QgsMaterial 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( 1.0 ); // QgsPhongTexturedMaterialSettings does not handle opacity + phongSettings.setOpacity( mOpacity ); phongSettings.setShininess( mShininess ); phongSettings.setSpecular( mSpecular ); Qt3DRender::QMaterial *material = phongSettings.toMaterial( technique, context ); return material; } - QgsImageTexture *textureImage = new QgsImageTexture( textureSourceImage ); - Qt3DExtras::QDiffuseSpecularMaterial *material = new Qt3DExtras::QDiffuseSpecularMaterial; + // 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/diffuseSpecular.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( "ka" ), QColor( ambient.red(), ambient.green(), ambient.blue(), opacity ) ) ); + effect->addParameter( new Qt3DRender::QParameter( QStringLiteral( "ks" ), 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 ); @@ -136,21 +173,11 @@ Qt3DRender::QMaterial *QgsPhongTexturedMaterialSettings::toMaterial( QgsMaterial texture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear ); texture->setMinificationFilter( Qt3DRender::QTexture2D::Linear ); - material->setDiffuse( QVariant::fromValue( texture ) ); - - material->setSpecular( mSpecular ); - material->setAmbient( mAmbient ); - material->setShininess( mShininess ); - material->setTextureScale( mTextureScale ); - - if ( context.isSelected() ) - { - // update the material with selection colors - // TODO : dampen the color of diffuse texture - // mat->setDiffuse( context.map().selectionColor() ); - material->setAmbient( context.selectionColor().darker() ); - } + 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; } diff --git a/src/3d/materials/qgsphongtexturedmaterialsettings.h b/src/3d/materials/qgsphongtexturedmaterialsettings.h index b01e3115cfd..8a08210d962 100644 --- a/src/3d/materials/qgsphongtexturedmaterialsettings.h +++ b/src/3d/materials/qgsphongtexturedmaterialsettings.h @@ -89,6 +89,12 @@ class _3D_EXPORT QgsPhongTexturedMaterialSettings : public QgsAbstractMaterialSe */ float textureRotation() const; + /** + * Returns the opacity of the surface + * \since QGIS 3.28 + */ + float opacity() const { return mOpacity; } + //! Sets ambient color component void setAmbient( const QColor &ambient ) { mAmbient = ambient; } @@ -113,6 +119,12 @@ class _3D_EXPORT QgsPhongTexturedMaterialSettings : public QgsAbstractMaterialSe //! Sets the texture rotation in degrees void setTextureRotation( float rotation ) { mTextureRotation = rotation; } + /** + * Sets opacity of the surface. + * \since QGIS 3.28 + */ + void setOpacity( float opacity ) { mOpacity = opacity; } + void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override; void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const override; #ifndef SIP_RUN @@ -126,6 +138,7 @@ class _3D_EXPORT QgsPhongTexturedMaterialSettings : public QgsAbstractMaterialSe return mAmbient == other.mAmbient && mSpecular == other.mSpecular && mShininess == other.mShininess && + mOpacity == other.mOpacity && mDiffuseTexturePath == other.mDiffuseTexturePath && mTextureScale == other.mTextureScale && mTextureRotation == other.mTextureRotation; @@ -135,6 +148,7 @@ class _3D_EXPORT QgsPhongTexturedMaterialSettings : public QgsAbstractMaterialSe QColor mAmbient{ QColor::fromRgbF( 0.1f, 0.1f, 0.1f, 1.0f ) }; QColor mSpecular{ QColor::fromRgbF( 1.0f, 1.0f, 1.0f, 1.0f ) }; float mShininess = 0.0f; + float mOpacity = 1.0f; QString mDiffuseTexturePath; float mTextureScale{ 1.0f }; float mTextureRotation{ 0.0f }; diff --git a/src/3d/qgs3dmapscene.cpp b/src/3d/qgs3dmapscene.cpp index 54a7d1976ec..d74e5710999 100644 --- a/src/3d/qgs3dmapscene.cpp +++ b/src/3d/qgs3dmapscene.cpp @@ -943,7 +943,7 @@ void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity ) } else { - // This handles the phong material with data defined properties. + // This handles the phong material with data defined properties and the textured case. Qt3DRender::QEffect *effect = material->effect(); if ( effect ) { diff --git a/src/3d/shaders.qrc b/src/3d/shaders.qrc index 87217cbe69a..e9a77dc41e0 100644 --- a/src/3d/shaders.qrc +++ b/src/3d/shaders.qrc @@ -1,5 +1,7 @@ + shaders/diffuseSpecular.frag + shaders/diffuseSpecular.vert shaders/instanced.frag shaders/instanced.vert shaders/light.inc.frag diff --git a/src/3d/shaders/diffuseSpecular.frag b/src/3d/shaders/diffuseSpecular.frag new file mode 100644 index 00000000000..552a6d06612 --- /dev/null +++ b/src/3d/shaders/diffuseSpecular.frag @@ -0,0 +1,23 @@ +#version 330 + +in vec3 worldPosition; +in vec3 worldNormal; +in vec2 texCoord; + +uniform vec3 eyePosition; +uniform vec4 ka; +uniform vec4 ks; +uniform float shininess; +uniform sampler2D diffuseTexture; +uniform float opacity; + +out vec4 fragColor; + +#pragma include phong.inc.frag + +void main(void) +{ + vec4 diffuseTextureColor = vec4(texture(diffuseTexture, texCoord).rgb, opacity); + vec3 worldView = normalize(eyePosition - worldPosition); + fragColor = phongFunction(ka, diffuseTextureColor, ks, shininess, worldPosition, worldView, worldNormal); +} diff --git a/src/3d/shaders/diffuseSpecular.vert b/src/3d/shaders/diffuseSpecular.vert new file mode 100644 index 00000000000..d2bc58abf0d --- /dev/null +++ b/src/3d/shaders/diffuseSpecular.vert @@ -0,0 +1,30 @@ +// copied from qt3d/src/extras/shaders/gl3/default.vert + +#version 330 + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec2 vertexTexCoord; + +out vec3 worldPosition; +out vec3 worldNormal; +out vec2 texCoord; + +uniform mat4 modelMatrix; +uniform mat3 modelNormalMatrix; +uniform mat4 modelViewProjection; + +uniform float texCoordScale; + +void main(void) +{ + // Pass through scaled texture coordinates + texCoord = vertexTexCoord * texCoordScale; + + // Transform position and normal to world space + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + worldNormal = normalize(modelNormalMatrix * vertexNormal); + + // Calculate vertex position in clip coordinates + gl_Position = modelViewProjection * vec4(vertexPosition, 1.0); +}