不使用gluSphere显示地球仪

33 篇文章 4 订阅
28 篇文章 3 订阅

思路:用一个个的四边形来近似球面,每一个四边形仅占一小块立体角。将平铺的世界地图与地球仪做如下对应--图片的左上角对应球体的theta = 0, phi = 0位置。向下则theta增加,直到180度;向右则phi增加,直到360度。theta和phi都按照10度步进。步进一次得到一个立体角,立体角的四个顶点分别位于(theta, phi), (theta + 10, phi) (theta, phi + 10) (theta + 10, phi + 10).选取这四个点构成的四边形来近似这个部分球面。这个四边形在世界地图中对应的矩形就是要贴到这个四边形上的纹理。只要把一块块的纹理与四边形对应贴好,就完成了球面绘制。

pro文件:

QT       += core gui opengl

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = glEarth3
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h
LIBS += -lopengl32 -lGLU32

h文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>

class MainWindow : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

    GLuint              m_uiTexID;
    GLfloat     *       m_pVertices;
    GLfloat     *       m_pTextures;
    int                 m_iVerticalPntQuantity;
    int                 m_iHorizontalPntQuantity;
    unsigned char *     pLoadTex(char * Image, unsigned long & bWidth, unsigned long & bHeight);
    void                vInitVerticesTextures(int iVerticalAngleStep, int iHorizontalAngleStep, int iR,
                                         GLfloat * & pVertData, GLfloat * & pTexData,
                                         int & iVerticalPntQuantity, int & iHorizontalPntQuantity);

protected:
    void        initializeGL();
    void        paintGL();
    void        resizeGL(int, int);
};

#endif // MAINWINDOW_H


cpp文件:

#include "mainwindow.h"
#include <QDir>
#include <gl/GLU.H>


#if !defined(DEG2RAD)
#define DEG2RAD (3.1415926 / 180)
#endif


MainWindow::MainWindow(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

MainWindow::~MainWindow()
{
    glDeleteTextures(1, &m_uiTexID);
    delete [] m_pTextures;
    delete [] m_pVertices;
}

void MainWindow::initializeGL()
{
    initializeOpenGLFunctions();

    unsigned long bWidth = 0;
    unsigned long bHeight = 0;

    QString qstrPath = QDir::currentPath();
    qstrPath += "/earth.bmp";
    unsigned char * pData = pLoadTex(qstrPath.toLatin1().data(), bWidth, bHeight);

        glGenTextures(1, &m_uiTexID);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, m_uiTexID);
        //这下面的两句是必要的,否则在绘制区的像素数和纹理的像素数不等时,图案不能正常显示
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, bWidth, bHeight,
                          GL_BGR_EXT, GL_UNSIGNED_BYTE, pData);
        glDisable(GL_TEXTURE_2D);

        free(pData);

    vInitVerticesTextures(10, 10, 40,
                          m_pVertices, m_pTextures, m_iVerticalPntQuantity, m_iHorizontalPntQuantity);
    glEnable(GL_DEPTH_TEST);
    //GL_FRON
}

void MainWindow::paintGL()
{
    glBindTexture(GL_TEXTURE_2D, m_uiTexID);
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2, GL_FLOAT, 0, m_pTextures);
    glVertexPointer(3, GL_FLOAT, 0, m_pVertices);
    glDrawArrays(GL_TRIANGLES, 0, m_iHorizontalPntQuantity * m_iVerticalPntQuantity * 6);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);
}

void MainWindow::resizeGL(int width, int height)
{
    glViewport(0,0,width,height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-50.0, 50.0, -50.0, 50.0, -50.0, 50.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(60,0,0,0,0,0,0,0,1);
}

void MainWindow::vInitVerticesTextures(int iVerticalAngleStep, int iHorizontalAngleStep, int iR,
                                     GLfloat * & pVertData, GLfloat * & pTexData,
                                     int & iVerticalPntQuantity, int & iHorizontalPntQuantity)
{
    iVerticalPntQuantity = 180 / iVerticalAngleStep;
    iHorizontalPntQuantity = 360 / iHorizontalAngleStep;
    pVertData = new GLfloat[iVerticalPntQuantity * iHorizontalPntQuantity * 18];
    pTexData = new GLfloat[iVerticalPntQuantity * iHorizontalPntQuantity * 12];

    int iVertexNodeCount = 0, iTexNodeCount = 0;
    for(int vAngle = 0; vAngle < 180; vAngle = vAngle + iVerticalAngleStep)// 垂直方向angleSpan度一份
    {
        for(int hAngle = 0; hAngle < 360; hAngle = hAngle + iHorizontalAngleStep)// 水平方向angleSpan度一份
        {
            // 纵向横向各到一个角度后计算对应的此点在球面上的坐标
            float x0 = (float) (iR * sin(vAngle * DEG2RAD) * cos(hAngle * DEG2RAD));
            float y0 = (float) (iR * sin(vAngle * DEG2RAD) * sin(hAngle * DEG2RAD));
            float z0 = (float) (iR * cos(vAngle * DEG2RAD));
                    // Log.w("x0 y0 z0","" + x0 + "  "+y0+ "  " +z0);

            float x1 = (float) (iR * sin(vAngle * DEG2RAD) * cos((hAngle + iHorizontalAngleStep) * DEG2RAD));
            float y1 = (float) (iR * sin(vAngle * DEG2RAD) * sin((hAngle + iHorizontalAngleStep) * DEG2RAD));
            float z1 = (float) (iR * cos(vAngle * DEG2RAD));

            float x2 = (float) (iR * sin((vAngle + iVerticalAngleStep) * DEG2RAD) *
                                cos((hAngle + iHorizontalAngleStep) * DEG2RAD));
            float y2 = (float) (iR * sin((vAngle + iVerticalAngleStep) * DEG2RAD) *
                                sin((hAngle + iHorizontalAngleStep) * DEG2RAD));
            float z2 = (float) (iR * cos((vAngle + iVerticalAngleStep) * DEG2RAD));
                    // Log.w("x2 y2 z2","" + x2 + "  "+y2+ "  " +z2);
            float x3 = (float) (iR * sin((vAngle + iVerticalAngleStep) * DEG2RAD) * cos(hAngle * DEG2RAD));
            float y3 = (float) (iR * sin((vAngle + iVerticalAngleStep) * DEG2RAD) * sin(hAngle * DEG2RAD));
            float z3 = (float) (iR * cos((vAngle + iVerticalAngleStep) * DEG2RAD));
                    // Log.w("x3 y3 z3","" + x3 + "  "+y3+ "  " +z3);
                    // 将计算出来的XYZ坐标加入存放顶点坐标的ArrayList
            pVertData[iVertexNodeCount++] = x1;
                    //alVertix.add(x1);
            pVertData[iVertexNodeCount++] = y1;
                    //alVertix.add(y1);
            pVertData[iVertexNodeCount++] = z1;
                    //alVertix.add(z1);
            pVertData[iVertexNodeCount++] = x3;
                    //alVertix.add(x3);
            pVertData[iVertexNodeCount++] = y3;
                    //alVertix.add(y3);
            pVertData[iVertexNodeCount++] = z3;
                    //alVertix.add(z3);
            pVertData[iVertexNodeCount++] = x0;
                    //alVertix.add(x0);
            pVertData[iVertexNodeCount++] = y0;
                    //alVertix.add(y0);
            pVertData[iVertexNodeCount++] = z0;
                    //alVertix.add(z0);

                    // *****************************************************************
            float s0 = hAngle / 360.0f;
            float s1 = (hAngle + iHorizontalAngleStep)/360.0f ;
            float t0 = 1 - vAngle / 180.0f;
            float t1 = 1 - (vAngle + iVerticalAngleStep) / 180.0f;

            /*t0 = t0 - 0.1;
            t1 = t1 - 0.1;
            if(t0 < 0)
                t0 = t0 + 1;
            if(t1 < 0)
                t1 = t1 + 1;*/

            pTexData[iTexNodeCount++] = s1;
                    //textureVertix.add(s1);// x1 y1对应纹理坐标
            pTexData[iTexNodeCount++] = t0;
                    //textureVertix.add(t0);
            pTexData[iTexNodeCount++] = s0;
                    //textureVertix.add(s0);// x3 y3对应纹理坐标
            pTexData[iTexNodeCount++] = t1;
                    //textureVertix.add(t1);
            pTexData[iTexNodeCount++] = s0;
                    //textureVertix.add(s0);// x0 y0对应纹理坐标
            pTexData[iTexNodeCount++] = t0;
                    //textureVertix.add(t0);

                    // *****************************************************************
            pVertData[iVertexNodeCount++] = x1;
                    //alVertix.add(x1);
            pVertData[iVertexNodeCount++] = y1;
                    //alVertix.add(y1);
            pVertData[iVertexNodeCount++] = z1;
                    //alVertix.add(z1);
            pVertData[iVertexNodeCount++] = x2;
                    //alVertix.add(x2);
            pVertData[iVertexNodeCount++] = y2;
                    //alVertix.add(y2);
            pVertData[iVertexNodeCount++] = z2;
                    //alVertix.add(z2);
            pVertData[iVertexNodeCount++] = x3;
                    //alVertix.add(x3);
            pVertData[iVertexNodeCount++] = y3;
                    //alVertix.add(y3);
            pVertData[iVertexNodeCount++] = z3;
                    //alVertix.add(z3);

                    // *****************************************************************
            pTexData[iTexNodeCount++] = s1;
                    //textureVertix.add(s1);// x1 y1对应纹理坐标
            pTexData[iTexNodeCount++] = t0;
                    //textureVertix.add(t0);
            pTexData[iTexNodeCount++] = s1;
                    //textureVertix.add(s1);// x2 y3对应纹理坐标
            pTexData[iTexNodeCount++] = t1;
                    //textureVertix.add(t1);
            pTexData[iTexNodeCount++] = s0;
                    //textureVertix.add(s0);// x3 y3对应纹理坐标
            pTexData[iTexNodeCount++] = t1;
                    //textureVertix.add(t1);
                    // *****************************************************************
        }
    }

    //setWindowTitle("123");
}

unsigned char * MainWindow::pLoadTex(char * Image, unsigned long & bWidth, unsigned long & bHeight)
{
    FILE* img = NULL;
    img = fopen(Image, "rb");

    DWORD size = 0;

    fseek(img,18,SEEK_SET);
    fread(&bWidth,4,1,img);
    fread(&bHeight,4,1,img);
    fseek(img,0,SEEK_END);
    size = ftell(img) - 54;

    unsigned char *data = (unsigned char*)malloc(size);

    fseek(img,54,SEEK_SET);    // image data
    fread(data,size,1,img);

    fclose(img);

    return data;
}

假如程序员想要从另外的角度观察,只要更改gluLookAt函数的观察角度即可。

效果:


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值