Skip to content

Commit 1a62581

Browse files
wonder-sknyalldawson
authored andcommitted
Add subtle shading of globe for better depth perception
1 parent 969fa6b commit 1a62581

File tree

6 files changed

+214
-3
lines changed

6 files changed

+214
-3
lines changed

src/3d/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ set(QGIS_3D_SRCS
6262
lights/qgspointlightsettings.cpp
6363

6464
materials/qgsabstractmaterialsettings.cpp
65+
materials/qgsglobematerial.cpp
6566
materials/qgsgoochmaterialsettings.cpp
6667
materials/qgsmaterial.cpp
6768
materials/qgsmaterialregistry.cpp
@@ -177,6 +178,7 @@ set(QGIS_3D_HDRS
177178
lights/qgspointlightsettings.h
178179

179180
materials/qgsabstractmaterialsettings.h
181+
materials/qgsglobematerial.h
180182
materials/qgsgoochmaterialsettings.h
181183
materials/qgsmaterial.h
182184
materials/qgsmaterialregistry.h

src/3d/materials/qgsglobematerial.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/***************************************************************************
2+
qgsglobematerial.cpp
3+
--------------------------------------
4+
Date : April 2025
5+
Copyright : (C) 2025 by Martin Dobias
6+
Email : wonder dot sk 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+
16+
#include <QUrl>
17+
18+
#include <Qt3DRender/QEffect>
19+
#include <Qt3DRender/QGraphicsApiFilter>
20+
#include <Qt3DRender/QParameter>
21+
#include <Qt3DRender/QRenderPass>
22+
#include <Qt3DRender/QShaderProgram>
23+
#include <Qt3DRender/QTechnique>
24+
#include <Qt3DRender/QTexture>
25+
26+
#include "qgsglobematerial.h"
27+
#include "moc_qgsglobematerial.cpp"
28+
29+
///@cond PRIVATE
30+
QgsGlobeMaterial::QgsGlobeMaterial( QNode *parent )
31+
: QgsMaterial( parent )
32+
, mTextureParameter( new Qt3DRender::QParameter( QStringLiteral( "diffuseTexture" ), new Qt3DRender::QTexture2D ) )
33+
, mDiffuseTextureScaleParameter( new Qt3DRender::QParameter( QStringLiteral( "texCoordScale" ), 1.0f ) )
34+
, mGL3Technique( new Qt3DRender::QTechnique( this ) )
35+
, mGL3RenderPass( new Qt3DRender::QRenderPass( this ) )
36+
, mGL3Shader( new Qt3DRender::QShaderProgram( this ) )
37+
, mFilterKey( new Qt3DRender::QFilterKey( this ) )
38+
{
39+
init();
40+
}
41+
42+
QgsGlobeMaterial::~QgsGlobeMaterial() = default;
43+
44+
45+
void QgsGlobeMaterial::init()
46+
{
47+
connect( mTextureParameter, &Qt3DRender::QParameter::valueChanged, this, &QgsGlobeMaterial::handleTextureChanged );
48+
49+
Qt3DRender::QEffect *effect = new Qt3DRender::QEffect();
50+
51+
effect->addParameter( mTextureParameter );
52+
effect->addParameter( mDiffuseTextureScaleParameter );
53+
54+
mGL3Shader->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/globe.frag" ) ) ) );
55+
mGL3Shader->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/default.vert" ) ) ) );
56+
57+
mGL3Technique->graphicsApiFilter()->setApi( Qt3DRender::QGraphicsApiFilter::OpenGL );
58+
mGL3Technique->graphicsApiFilter()->setMajorVersion( 3 );
59+
mGL3Technique->graphicsApiFilter()->setMinorVersion( 1 );
60+
mGL3Technique->graphicsApiFilter()->setProfile( Qt3DRender::QGraphicsApiFilter::CoreProfile );
61+
62+
mFilterKey->setParent( this );
63+
mFilterKey->setName( QStringLiteral( "renderingStyle" ) );
64+
mFilterKey->setValue( QStringLiteral( "forward" ) );
65+
66+
mGL3Technique->addFilterKey( mFilterKey );
67+
mGL3RenderPass->setShaderProgram( mGL3Shader );
68+
mGL3Technique->addRenderPass( mGL3RenderPass );
69+
effect->addTechnique( mGL3Technique );
70+
71+
setEffect( effect );
72+
}
73+
74+
void QgsGlobeMaterial::setTexture( Qt3DRender::QAbstractTexture *texture )
75+
{
76+
mTextureParameter->setValue( QVariant::fromValue( texture ) );
77+
}
78+
79+
Qt3DRender::QAbstractTexture *QgsGlobeMaterial::texture() const
80+
{
81+
return mTextureParameter->value().value<Qt3DRender::QAbstractTexture *>();
82+
}
83+
84+
void QgsGlobeMaterial::handleTextureChanged( const QVariant &var )
85+
{
86+
emit textureChanged( var.value<Qt3DRender::QAbstractTexture *>() );
87+
}
88+
89+
///@endcond PRIVATE

src/3d/materials/qgsglobematerial.h

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/***************************************************************************
2+
qgsglobematerial.h
3+
--------------------------------------
4+
Date : April 2025
5+
Copyright : (C) 2025 by Martin Dobias
6+
Email : wonder dot sk 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+
16+
#ifndef QGSGLOBEMATERIAL_H
17+
#define QGSGLOBEMATERIAL_H
18+
19+
#include "qgis_3d.h"
20+
#include "qgsmaterial.h"
21+
22+
#include <QObject>
23+
24+
#define SIP_NO_FILE
25+
26+
// adapted from Qt's qtexturematerial.h
27+
namespace Qt3DRender
28+
{
29+
30+
class QFilterKey;
31+
class QAbstractTexture;
32+
class QTechnique;
33+
class QParameter;
34+
class QShaderProgram;
35+
class QRenderPass;
36+
37+
} // namespace Qt3DRender
38+
39+
///@cond PRIVATE
40+
41+
/**
42+
* \ingroup qgis_3d
43+
* \brief A material for globe mesh rendering - essentially an unlit texture material with some extras
44+
* \since QGIS 3.44
45+
*/
46+
class _3D_EXPORT QgsGlobeMaterial : public QgsMaterial
47+
{
48+
Q_OBJECT
49+
Q_PROPERTY( Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged )
50+
51+
public:
52+
/**
53+
* Constructor for QgsTextureMaterial, with the specified \a parent node.
54+
*/
55+
explicit QgsGlobeMaterial( Qt3DCore::QNode *parent = nullptr );
56+
~QgsGlobeMaterial() override;
57+
58+
Qt3DRender::QAbstractTexture *texture() const;
59+
60+
public Q_SLOTS:
61+
62+
/**
63+
* Sets the diffuse component of the material.
64+
* Ownership is transferred to the material.
65+
*/
66+
void setTexture( Qt3DRender::QAbstractTexture *texture );
67+
68+
Q_SIGNALS:
69+
void textureChanged( Qt3DRender::QAbstractTexture *texture );
70+
71+
private:
72+
void init();
73+
74+
void handleTextureChanged( const QVariant &var );
75+
76+
Qt3DRender::QParameter *mTextureParameter = nullptr;
77+
Qt3DRender::QParameter *mDiffuseTextureScaleParameter = nullptr;
78+
Qt3DRender::QTechnique *mGL3Technique = nullptr;
79+
Qt3DRender::QRenderPass *mGL3RenderPass = nullptr;
80+
Qt3DRender::QShaderProgram *mGL3Shader = nullptr;
81+
Qt3DRender::QFilterKey *mFilterKey = nullptr;
82+
};
83+
84+
///@endcond PRIVATE
85+
86+
#endif // QGSGLOBEMATERIAL_H

src/3d/qgsglobechunkedentity.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ typedef Qt3DCore::QGeometry Qt3DQGeometry;
4040
#include <Qt3DRender/QGeometryRenderer>
4141
#include <Qt3DRender/QTexture>
4242
#include <Qt3DRender/QTextureImage>
43-
#include <Qt3DExtras/QTextureMaterial>
4443

4544
#include "qgs3dmapsettings.h"
4645
#include "qgs3dutils.h"
@@ -50,6 +49,7 @@ typedef Qt3DCore::QGeometry Qt3DQGeometry;
5049
#include "qgsdistancearea.h"
5150
#include "qgseventtracing.h"
5251
#include "qgsgeotransform.h"
52+
#include "qgsglobematerial.h"
5353
#include "qgsraycastingutils_p.h"
5454
#include "qgsterraintextureimage_p.h"
5555
#include "qgsterraintexturegenerator_p.h"
@@ -200,7 +200,7 @@ static Qt3DCore::QEntity *makeGlobeMesh( double lonMin, double lonMax, double la
200200
texture->setMinificationFilter( Qt3DRender::QTexture2D::Linear );
201201
texture->setMagnificationFilter( Qt3DRender::QTexture2D::Linear );
202202

203-
Qt3DExtras::QTextureMaterial *material = new Qt3DExtras::QTextureMaterial( entity );
203+
QgsGlobeMaterial *material = new QgsGlobeMaterial( entity );
204204
material->setTexture( texture );
205205

206206
QgsGeoTransform *geoTransform = new QgsGeoTransform( entity );
@@ -429,7 +429,7 @@ class QgsGlobeMapUpdateJob : public QgsChunkQueueJob
429429
, mTextureGenerator( textureGenerator )
430430
{
431431
// extract our terrain texture image from the 3D entity
432-
QVector<Qt3DExtras::QTextureMaterial *> materials = node->entity()->componentsOfType<Qt3DExtras::QTextureMaterial>();
432+
QVector<QgsGlobeMaterial *> materials = node->entity()->componentsOfType<QgsGlobeMaterial>();
433433
Q_ASSERT( materials.count() == 1 );
434434
QVector<Qt3DRender::QAbstractTextureImage *> texImages = materials[0]->texture()->textureImages();
435435
Q_ASSERT( texImages.count() == 1 );

src/3d/shaders.qrc

+1
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,6 @@
3737
<file>shaders/default.vert</file>
3838
<file>shaders/texture.frag</file>
3939
<file>shaders/texture.vert</file>
40+
<file>shaders/globe.frag</file>
4041
</qresource>
4142
</RCC>

src/3d/shaders/globe.frag

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#version 330 core
2+
3+
in vec3 worldPosition;
4+
in vec3 worldNormal;
5+
in vec2 texCoord;
6+
7+
out vec4 fragColor;
8+
9+
uniform mat4 inverseViewMatrix;
10+
uniform sampler2D diffuseTexture;
11+
12+
void main()
13+
{
14+
// general idea of the fragment shader: for better 3d perception, we are darkening
15+
// the globe's texture a bit towards the edges of the ellipsoid. We use camera's
16+
// view direction and normal vector of the globe's geometry: the larger the angle
17+
// between them, the darker the color should be.
18+
19+
vec3 cameraWorldPos = vec3(inverseViewMatrix[3]);
20+
vec3 viewDir = normalize(cameraWorldPos - worldPosition);
21+
22+
// note: the constants below are just artistic choices to get decently looking shading
23+
24+
// we apply shading only when we're far from the globe, so that closer
25+
// views do not get the globe's texture darkened (e.g. when looking towards horizon)
26+
float distFromCamera = length(cameraWorldPos - worldPosition);
27+
float shadingFactor = smoothstep(2e5, 5e5, distFromCamera);
28+
29+
// dot product of the normal and the view direction is the cosine of the angle between them
30+
float diff = max(dot(worldNormal, viewDir), 0.0);
31+
32+
fragColor = texture(diffuseTexture, texCoord) * (0.3 + 0.7 * mix(1.0, diff, shadingFactor));
33+
}

0 commit comments

Comments
 (0)