Introduction
This article demonstrates how to create a 3D digital Earth visualization using C++, the Qt framework, and OpenGL. We will cover setting up the project, rendering a spherical Earth, and entegrating map tile imagery.
Project Setup
To begin, create a new Qt Widgets Application project. Ensure you have the necessary development tools installed, including Qt and a C++ compiler.
Configuring the .pro File
The project file (.pro) needs to be configured to include the required libraries and define the target architecture.
QT += core gui widgets opengl
# Detect 32-bit or 64-bit architecture
greaterThan(QT_MAJOR_VERSION, 4) {
TARGET_ARCH = $${QT_ARCH}
} else {
TARGET_ARCH = $${QMAKE_HOST.arch}
}
contains(TARGET_ARCH, x86_64) {
ARCHITECTURE = x64
} else {
ARCHITECTURE = x86
}
# Link necessary OpenGL libraries
LIBS += -lopengl32 -lglu32
# For MSVC, you might need to specify library paths
win32 {
contains(ARCHITECTURE, x64) {
LIBS += -L"C:/path/to/your/qt/msvc2017_64/lib" -lfreeglut
} else {
LIBS += -L"C:/path/to/your/qt/msvc2017_32/lib" -lfreeglut
}
}
Including Headers
In you're source files, include the necessary OpenGL headers:
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QMatrix4x4>
#include <QVector>
#include <QVector3D>
#include <QOpenGLTexture>
#include <QImage>
Rendering the Earth Sphere
The Earth can be approximated as a sphere. We'll generate vertices based on latitude and longitude to form a mesh.
class EarthWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT
public:
explicit EarthWidget(QWidget *parent = nullptr);
protected:
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
private:
void generateSphere(float radius, int slices, int stacks);
void loadTexture(const QString &path);
QOpenGLShaderProgram *program;
QOpenGLVertexArrayObject vao;
QOpenGLBuffer vbo;
QOpenGLTexture *texture;
QMatrix4x4 projection;
QMatrix4x4 view;
QVector<QVector3D> vertices;
QVector<QVector2D> texCoords;
};
void EarthWidget::generateSphere(float radius, int slices, int stacks) {
vertices.clear();
texCoords.clear();
for (int i = 0; i <= stacks; ++i) {
float lat = M_PI * (-0.5 + (float)(i) / stacks);
float sinLat = sin(lat);
float cosLat = cos(lat);
for (int j = 0; j <= slices; ++j) {
float lon = 2 * M_PI * (float)(j) / slices;
float sinLon = sin(lon);
float cosLon = cos(lon);
float x = cosLat * cosLon;
float y = sinLat;
float z = cosLat * sinLon;
vertices.append(QVector3D(x * radius, y * radius, z * radius));
texCoords.append(QVector2D(1.0f - (float)(j) / slices, (float)(i) / stacks));
}
}
}
Loading Map Tiles
We'll use online map tile services to texture the sphere. Here's an example of loading a tile from a provider.
void EarthWidget::loadTexture(const QString &path) {
if (texture) {
delete texture;
}
texture = new QOpenGLTexture(QImage(path).mirrored());
texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
texture->setMagnificationFilter(QOpenGLTexture::Linear);
update();
}
Main Application
Create the main window and instantiate the Earth widget.
#include <QApplication>
#include "earthwidget.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
EarthWidget earth;
earth.resize(800, 600);
earth.show();
return app.exec();
}
Accessing Online Map Tiles
Various map tile providers offer imagery that can be used. Here are some examples of tile URLs:
- ArcGIS:
https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x} - Google Maps:
https://mt1.google.cn/vt/lyrs=s&x={x}&y={y}&z={z} - OpenStreetMap:
https://c.tile.openstreetmap.org/{z}/{x}/{y}.png - Mapbox:
https://a.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.png?access_token={your_key}
Replace {z}, {x}, and {y} with the appropriate tile coordinates and zoom level.