首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 系统运维 >

Qt上的OpenGL 编程(10)Solar System

2012-09-06 
Qt下的OpenGL 编程(10)Solar System一、提要今天的内容是OpenGL的编程实践—太阳系的模拟!红宝书上有相应的

Qt下的OpenGL 编程(10)Solar System

一、提要
    今天的内容是OpenGL的编程实践—太阳系的模拟!
     红宝书上有相应的教程,但这里我们要实现得更全面一些。iPad上有一个很棒的应用,名字叫Solar System,我们尽量去达到它的效果。
    先来看一下最终效果:
    Qt上的OpenGL 编程(10)Solar System
Qt上的OpenGL 编程(10)Solar System
思路:
     建立9个球体,分别赋予不同的材质,再通过动画不断变换它们的位置,就可以实现模拟了。
二、有关太阳系的知识
     太阳系有一颗恒星:太阳,8颗行星:水,金,地,火,木,土,天王,海王。9颗星球的位置如下:
Qt上的OpenGL 编程(10)Solar System
    然后去搜集了解一下各个星球的自转和公转周期,脑袋里面有个概念。
    接着可以去找一些星球贴图的素材了,我在网上找到了一些资源,太阳的贴图是自己用ps绘制的,然后把它们通通添加到资源文件中,就像这样:
    Qt上的OpenGL 编程(10)Solar System
三、程序结构
    相比与之前的框架,这里添加了一个星球类,文件结构如下:
     程序还是比较清晰,直接贴代码了:
     
/*-----------------------------------------Filename:   nehewidget.cpp-----------------------------------------//opengl渲染窗口类-----------------------------------------  */#include "nehewidget.h"NeHeWidget::NeHeWidget(QWidget *parent) :    QGLWidget(parent){    xRot = yRot = zRot = 0.0;    zoom = -5.0;    xSpeed = ySpeed = 0.0;    fpsFont=QFont("Times", 20);    colorSpan=0;    fpsSpan=50;    timer = new QTimer(this);        timer->start(fpsSpan);    connect(timer,SIGNAL(timeout()),this,SLOT(updateGL()));    mySphere=gluNewQuadric();        eyeX=0.0;    eyeY=0.0;    eyeZ=190.0;    //夜空参数设置    GLfloat  sky_ambient[]={0.0,0.0,0.0,1.0};    GLfloat  sky_diffuse[]={0.0,0.0,0.0,1.0};    GLfloat  sky_specular[]={0.0,0.0,0.0,1.0};    GLfloat  sky_shininess=0.0;    GLfloat  sky_radious=290.0;    // GLfloat sky_rotSpeed= (GLfloat)360/58/100;    sky=new Star(0,sky_radious,0,0,0,0,sky_ambient,sky_diffuse,sky_specular,sky_shininess);        //太阳参数设置    GLfloat  sun_ambient[]={0.0,0.0,0.0,1.0};    GLfloat  sun_diffuse[]={0.0,0.0,0.0,1.0};    GLfloat  sun_specular[]={0.0,0.0,0.0,1.0};    GLfloat  sun_shininess=20.0;    GLfloat  sun_radious=10.0;    GLfloat sun_rotSpeed= (GLfloat)360/58/100;    sun=new Star(1,sun_radious,0,0,0,sun_rotSpeed,sun_ambient,sun_diffuse,sun_specular,sun_shininess);        //水星    GLfloat  mercury_ambient[]={0.0,0.0,0.0,1.0};    GLfloat  mercury_diffuse[]={0.5,0.5,0.5,1.0};    GLfloat  mercury_specular[]={0.0,0.0,0.0,1.0};    GLfloat  mercury_shininess=20.0;    GLfloat  mercury_radious=0.7;    GLfloat mecury_revSpeed=(GLfloat)360/88;    GLfloat mecury_rotSpeed= (GLfloat)360/58/100;    mercury=new Star(2,mercury_radious,15.2,0,mecury_revSpeed,mecury_rotSpeed,mercury_ambient,mercury_diffuse,mercury_specular,mercury_shininess);        //金星    GLfloat  venus_ambient[]={0.0,0.0,0.0,1.0};    GLfloat  venus_diffuse[]={0.8,0.8,0.8,1.0};    GLfloat  venus_specular[]={0.0,0.0,0.0,1.0};    GLfloat  venus_shininess=20.0;    GLfloat  venus_radious=1.24;    GLfloat venus_revSpeed=(GLfloat)360/224;    GLfloat venus_rotSpeed= (GLfloat)360/243/100;    venus=new Star(3,venus_radious,19.2,0,venus_revSpeed,venus_rotSpeed,venus_ambient,venus_diffuse,venus_specular,venus_shininess);        //地球    GLfloat  earth_ambient[]={0.1,0.1,0.1,1.0};    GLfloat  earth_diffuse[]={0.4,0.4,0.8,1.0};    GLfloat  earth_specular[]={0.0,0.0,0.0,1.0};    GLfloat  earth_shininess=20.0;    GLfloat  earth_radious=1.24;    GLfloat earth_revSpeed=(GLfloat)360/365;    GLfloat earth_rotSpeed= (GLfloat)360/1/100;    earth=new Star(4,earth_radious,26,0,earth_revSpeed,earth_rotSpeed,earth_ambient,earth_diffuse,earth_specular,earth_shininess);        //火星    GLfloat  mars_ambient[]={0.1,0.1,0.1,1.0};    GLfloat  mars_diffuse[]={0.6, 0.6, 0.6, 1.0};    GLfloat  mars_specular[]={0.0,0.0,0.0,1.0};    GLfloat  mars_shininess=20.0;    GLfloat  mars_radious=1.0;    GLfloat mars_revSpeed=(GLfloat)360/687;    GLfloat mars_rotSpeed= (GLfloat)360/1/100;    mars=new Star(5,mars_radious,31,0,mars_revSpeed,mars_rotSpeed,mars_ambient,mars_diffuse,mars_specular,mars_shininess);        //木星    GLfloat  jupiter_ambient[]={0.0, 0.0, 0.0,1.0};    GLfloat  jupiter_diffuse[]={0.6, 0.6, 0.6, 1.0};    GLfloat  jupiter_specular[]={0.0,0.0,0.0,1.0};    GLfloat  jupiter_shininess=20.0;    GLfloat  jupiter_radious=4.0;    GLfloat jupiter_revSpeed=(GLfloat)360/4329;    GLfloat jupiter_rotSpeed= (GLfloat)360/0.3/100;    jupiter=new Star(6,jupiter_radious,43,0,jupiter_revSpeed,jupiter_rotSpeed,jupiter_ambient,jupiter_diffuse,jupiter_specular,jupiter_shininess);    //土星    GLfloat  saturn_ambient[]={0.0, 0.0, 0.0,1.0};    GLfloat  saturn_diffuse[]={0.6, 0.6, 0.6, 1.0};    GLfloat  saturn_specular[]={0.0,0.0,0.0,1.0};    GLfloat  saturn_shininess=20.0;    GLfloat  saturn_radious=3.5;    GLfloat saturn_revSpeed=(GLfloat)360/10768;    GLfloat saturn_rotSpeed= (GLfloat)360/1.4/100;    saturn=new Star(7,saturn_radious,56.5,0,saturn_revSpeed,saturn_rotSpeed,saturn_ambient,saturn_diffuse,saturn_specular,saturn_shininess);        }NeHeWidget::~NeHeWidget(){}void NeHeWidget::loadGLTextures(QString filename, int id){    QImage tex, buf;    if ( !buf.load(filename ) )    {        //如果载入不成功,自动生成一个128*128的32位色的绿色图片。        qWarning("Could not read image file!");        QImage dummy( 128, 128,QImage::Format_RGB32 );        dummy.fill( Qt::green );        buf = dummy;    }    //转换成纹理类型    tex = QGLWidget::convertToGLFormat( buf );    //创建纹理    glGenTextures( 1, &texture[id] );    //使用来自位图数据生成的典型纹理,将纹理名字texture[0]绑定到纹理目标上    glBindTexture( GL_TEXTURE_2D, texture[id] );    glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0,                  GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );}void NeHeWidget::drawStar(Star *s){    glPushMatrix();    //公转    glRotatef(s->revAngle,0.0,0.0,1.0);    glTranslatef(s->disX, s->disY, 0.0);    //自转    glRotatef(s->rotAngle,0.0,0.0,1.0);    gluSphere(mySphere, s->radious, 32, 16);    //设置材质属性    glMaterialfv(GL_BACK, GL_AMBIENT, s->ambient);    glMaterialfv(GL_BACK, GL_DIFFUSE, s->diffuse);    glMaterialfv(GL_BACK, GL_SPECULAR, s->specular);    glMaterialf(GL_BACK, GL_SHININESS, s->shinniness);    //    glPopMatrix();}void NeHeWidget::setMaterial(Star *s){    }void NeHeWidget::initializeGL(){    //载入纹理    loadGLTextures( ":/data/sun.jpg",sun->texId);    loadGLTextures( ":/data/mercury.bmp",mercury->texId);    loadGLTextures( ":/data/venus.jpg",venus->texId);    loadGLTextures( ":/data/earth2.jpg",earth->texId);    loadGLTextures( ":/data/mars.bmp",mars->texId);    loadGLTextures( ":/data/saturn.jpg",saturn->texId);    loadGLTextures( ":/data/jupiter.bmp",jupiter->texId);    loadGLTextures( ":/data/sky.jpg",sky->texId);    //loadGLTextures( ":/data/neptune.bmp",neptune->texId);        // 启用阴影平滑    glShadeModel( GL_SMOOTH );    // 黑色背景    glClearColor( 0.0, 0.0, 0.0, 0.0 );    // 设置深度缓存    glClearDepth( 1.0 );    // 启用深度测试    glEnable( GL_DEPTH_TEST );    //启用纹理    glEnable( GL_TEXTURE_2D );    // 所作深度测试的类型    glDepthFunc( GL_LEQUAL );    // 告诉系统对透视进行修正    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );    //    开启剔除操作效果    //glEnable(GL_CULL_FACE);    // 使用平滑法线    gluQuadricNormals(mySphere, GL_SMOOTH);    // 使用纹理    gluQuadricTexture(mySphere, GL_TRUE);    // 设置球纹理映射    }void NeHeWidget::paintGL(){        // 清除屏幕和深度缓存    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );    //glRotatef( yRot, 0.0,  0.0,  1.0 );    glColor3f(1.0,1.0,1.0);    glBindTexture(GL_TEXTURE_2D, texture[sky->texId]);    drawStar(sky);        glBindTexture(GL_TEXTURE_2D, texture[sun->texId]);    drawStar(sun);        glBindTexture(GL_TEXTURE_2D, texture[mercury->texId]);    drawStar(mercury);        glBindTexture(GL_TEXTURE_2D, texture[venus->texId]);    drawStar(venus);        glBindTexture(GL_TEXTURE_2D, texture[earth->texId]);    drawStar(earth);        glBindTexture(GL_TEXTURE_2D, texture[mars->texId]);    drawStar(mars);        glBindTexture(GL_TEXTURE_2D, texture[jupiter->texId]);    drawStar(jupiter);        glBindTexture(GL_TEXTURE_2D, texture[saturn->texId]);    drawStar(saturn);            //旋转速度    yRot += 0.4;    sun->rotate();    mercury->revolute();    mercury->rotate();    venus->revolute();    venus->rotate();    earth->revolute();    earth->rotate();    mars->revolute();    mars->rotate();    jupiter->revolute();    jupiter->rotate();    saturn->revolute();    saturn->rotate();    glLoadIdentity();    gluLookAt (eyeX, eyeY, eyeZ, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0);    // gluLookAt (80.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0);    glFlush();    //fps的字体颜色    glColor3f(0.0f,0.0f,1.0f);    //计算FPS    calFrequency();    }// 重置OpenGL窗口大小void NeHeWidget::resizeGL(int width, int height){    // 防止窗口大小变为0    if ( height == 0 )    {        height = 1;    }    // 重置当前的视口    glViewport( 0, 0, (GLint)width, (GLint)height );    // 选择投影矩阵    glMatrixMode( GL_PROJECTION );    // 重置投影矩阵    glLoadIdentity();    // 设置视口的大小    gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 600.0 );    // 选择模型观察矩阵    glMatrixMode( GL_MODELVIEW );    glLoadIdentity();}void NeHeWidget::speedUp(){    fpsSpan+=1;    qDebug()<<fpsSpan;    timer->setInterval(fpsSpan);    //timer->start(fpsSpan);    updateGL();}void NeHeWidget::speedDown(){    if(fpsSpan>1) fpsSpan-=1;    else fpsSpan=1;    qDebug()<<fpsSpan;    timer->setInterval(fpsSpan);    updateGL();}void NeHeWidget::eyeXup(){    eyeX+=1;}void NeHeWidget::eyeXdown(){    // if(eyeX>10) eyeX-=1;    //else eyeX=10;    eyeX-=1;}void NeHeWidget::eyeZup(){    eyeZ+=1;}void NeHeWidget::eyeZdown(){    // if(eyeX>10) eyeX-=1;    //else eyeX=10;    eyeZ-=1;}void NeHeWidget::zoomOut(){    zoom+= 0.2;        updateGL();}void NeHeWidget::zoomIn(){    zoom -= 0.2;    updateGL();}void NeHeWidget::calFrequency(){    static  QString tmp="";    static float framesPerSecond=0.0f;//fps的数值    static float frames    = 0.0f;       // 用于存储渲染的帧数    static float lastTime   = 0.0f;       // 前一秒的时刻    float currentTime =  glutGet(GLUT_ELAPSED_TIME)* 0.001f;//程序运行的时间    ++frames;    if( currentTime - lastTime > 1.0f )//,每秒刷新一次    {        framesPerSecond=frames;        tmp.setNum(framesPerSecond);        lastTime = currentTime;        frames= 0;    }    renderText(100,100,"FPS: "+tmp,fpsFont);//最终结果在窗口中渲染}
/*-----------------------------------------Filename:   mainwindow.h-----------------------------------------//主窗口类-----------------------------------------  */#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QtGui/QMainWindow>#include <QKeyEvent>#include "nehewidget.h"class MainWindow : public QMainWindow{    Q_OBJECT    public:    MainWindow(QWidget *parent = 0);    ~MainWindow();protected:    bool fullscreen;    //处理键盘事件    void keyPressEvent( QKeyEvent *e );private:    NeHeWidget *neheWidget ;};#endif // MAINWINDOW_H


/*-----------------------------------------Filename:   mainwindow.cpp-----------------------------------------//主窗口类-----------------------------------------  */#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent)    : QMainWindow(parent){    neheWidget = new NeHeWidget();    fullscreen = true;    setGeometry(100,100,1000,768);    setWindowTitle(tr("NeHe's OpenGL Framework"));    setCentralWidget(neheWidget);}MainWindow::~MainWindow(){    }void MainWindow::keyPressEvent(QKeyEvent *e){    switch ( e->key() )    {    case Qt::Key_F2:        fullscreen = !fullscreen;        if ( fullscreen )        {            showFullScreen();        }        else        {            showNormal();        }        neheWidget->updateGL();        break;    case Qt::Key_Escape:        close();        break;    case Qt::Key_PageUp:        neheWidget->zoomOut();        break;    case Qt::Key_PageDown:        neheWidget->zoomIn();        break;    case Qt::Key_Down:        neheWidget->speedUp();        break;    case Qt::Key_Up:        neheWidget->speedDown();        break;    case Qt::Key_W:        neheWidget->eyeXup();        break;    case Qt::Key_S:        neheWidget->eyeXdown();        break;    case Qt::Key_E:        neheWidget->eyeZup();        break;    case Qt::Key_D:        neheWidget->eyeZdown();        break;    }}


//main函数#include <QtGui/QApplication>#include "mainwindow.h"int main(int argc, char *argv[]){    QApplication a(argc, argv);    MainWindow w;    glutInit(&argc, argv);    w.show();        return a.exec();}

四。程序中未完善的地方

这个程序应该只能算是一个大致的框架,还是有很多地方可以改进,比如:添加天王星,海王星,冥王星,添加每个星球的倾角,添加月球....

有兴趣的同学可以继续完善,我们可以继续讨论。

参考资料

1.      《 OpenGL Reference Manual 》, OpenGL 参考手册

2.      《 OpenGL 编程指南》(《 OpenGL Programming Guide 》), Dave Shreiner , Mason Woo , Jackie Neider , Tom Davis 著,徐波译,机械工业出版社

3.         《win32 OpenGL编程 》   一个大牛的博客     http://blog.csdn.net/vagrxie/article/category/628716/3

 

热点排行