手记

OpenGL版太阳系Demo(二)

5、爆炸粒子系统
#include "glparticle.h"

const vec3      PARTICLE_VELOCITY  (0.0f, 2.0f, 0.0f);
const vec3      VELOCITY_VARIATION  (4.0f, 4.0f, 4.0f);
const vec3      PARTICLE_ACCELERATION  (0.0f, -5.0f, 0.0f);
const float     PARTICLE_SIZE      = 3.0f;//5.0f;
const float     SIZE_VARIATION     = 0.3f;//2.0f;
#define FRAND   (((float)rand()-(float)rand())/RAND_MAX)

class glExplosion : public glParticleSystem
{
public:
  glExplosion(int maxParticles, vec3 origin, float spread, GLuint texture);
  void  Update(float elapsedTime);
  void  Render();
  bool  IsDead() { return m_numParticles == 0; }

  void    InitializeParticle(int index);
  float   m_spread;
  GLuint  m_texture;     
};

glExplosion::glExplosion(int numParticles, vec3 origin, float spread, GLuint texture)
    : m_texture(texture), m_spread(spread), glParticleSystem(numParticles, origin)
{
    srand(timeGetTime());
    glParticleSystem::InitializeSystem();
    Emit(numParticles);
}

void glExplosion::InitializeParticle(int index)//爆炸初始化
{
    m_particleList[index].m_pos.x = m_origin.x + FRAND * m_spread;
    m_particleList[index].m_pos.y = m_origin.y + FRAND * m_spread;
    m_particleList[index].m_pos.z = m_origin.z + FRAND * m_spread;

    m_particleList[index].m_size = PARTICLE_SIZE + FRAND * SIZE_VARIATION;

    m_particleList[index].m_velocity.x = PARTICLE_VELOCITY.x + FRAND * VELOCITY_VARIATION.x;
    m_particleList[index].m_velocity.y = PARTICLE_VELOCITY.y + FRAND * VELOCITY_VARIATION.y;
    m_particleList[index].m_velocity.z = PARTICLE_VELOCITY.z + FRAND * VELOCITY_VARIATION.z;

    m_particleList[index].m_acceleration = PARTICLE_ACCELERATION;
    m_particleList[index].m_color[0] = 1.0;
    m_particleList[index].m_color[1] = 0.5f + FRAND * 0.5f;
    m_particleList[index].m_color[2] = 0.01f;
    m_particleList[index].m_color[3] = 1.0;
    m_particleList[index].m_energy = 1.5f + FRAND / 2.0f;
    m_particleList[index].m_colorDelta[0] = 0.0;
    m_particleList[index].m_colorDelta[1] = -(m_particleList[index].m_color[1] / 2.0f) / m_particleList[index].m_energy;
    m_particleList[index].m_colorDelta[2] = 0.0;
    m_particleList[index].m_colorDelta[3] = -1.0f / m_particleList[index].m_energy;
    m_particleList[index].m_sizeDelta = -m_particleList[index].m_size / m_particleList[index].m_energy;
}
void glExplosion::Update(float elapsedTime)//清除爆炸动画
{
    for (int i = 0; i < m_numParticles;)
    {
        //更新位置s=vt;
        m_particleList[i].m_pos = m_particleList[i].m_pos + m_particleList[i].m_velocity * elapsedTime;
        //更新速度v=at;
        m_particleList[i].m_velocity = m_particleList[i].m_velocity + m_particleList[i].m_acceleration * elapsedTime;
        //能量随着时间流逝
        m_particleList[i].m_energy -= elapsedTime;

        //size以及颜色随着时间变换
        m_particleList[i].m_size += m_particleList[i].m_sizeDelta * elapsedTime;
        m_particleList[i].m_color[3] += m_particleList[i].m_colorDelta[3] * elapsedTime;
        m_particleList[i].m_color[1] += m_particleList[i].m_colorDelta[1] * elapsedTime;

        //如果当前粒子的能量<=0,说明没有了
        //则将最后一个粒子放入当前位置
        if (m_particleList[i].m_energy <= 0.0)
        {
            m_particleList[i] = m_particleList[--m_numParticles];
        }
        else
        {
            ++i;
        }
    }
}

void glExplosion::Render()//爆炸动画
{
    glPushAttrib(GL_CURRENT_BIT);//保存现有颜色属性 glPopAttrib();//恢复前一属性

    float viewMatrix[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix);
    vec3 right(viewMatrix[0], viewMatrix[4], viewMatrix[8]);
    vec3 up(viewMatrix[1], viewMatrix[5], viewMatrix[9]);

    glDepthMask(GL_FALSE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, m_texture);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glBegin(GL_QUADS);
    for (int i = 0; i < m_numParticles; ++i)
    {
        GLfloat size = m_particleList[i].m_size / 3;
        vec3 pos = m_particleList[i].m_pos;
        glColor4fv(m_particleList[i].m_color);

        glTexCoord2f(0.0, 0.0); glVertex3fv((pos + (right + up) * -size).v);
        glTexCoord2f(1.0, 0.0); glVertex3fv((pos + (right - up) * size).v);
        glTexCoord2f(1.0, 1.0); glVertex3fv((pos + (right + up) * size).v);
        glTexCoord2f(0.0, 1.0); glVertex3fv((pos + (up - right) * size).v);
    }
    glEnd();
    //glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);
    glDepthMask(GL_TRUE);
    glPopAttrib();//恢复前一属性
}
6、由于整个系统大部分都是圆形以及像土星一样带光圈的图形,因此在opengl中,二次曲面对象最适合这种显示
void drawInit();
void drawSphere(double radius , int slices, int stack,bool texture);
void drawDisk( GLdouble            innerRadius, 
               GLdouble            outerRadius, 
               GLint               slices);
void drawDeInit();

GLUquadricObj * m_quad = NULL;

void drawInit()
{
  m_quad = gluNewQuadric();
}

void drawDeInit()
{
  gluDeleteQuadric(m_quad);
}

void drawSphere(double radius , int slices, int stack ,bool texture)
{  

  gluQuadricTexture(m_quad, true);
  gluSphere(m_quad,radius,slices,stack);
}

void drawDisk(GLdouble            innerRadius, 
    GLdouble            outerRadius, 
    GLint               slices )
{
  gluDisk(m_quad,innerRadius, 
    outerRadius, 
    slices, 
    true);
}
 7、纹理载入,使用lodepng库读取png图像,该库最大的好处是只有单独一个文件,不需要依赖zlib和libpng等库就能惊醒png读写
class glTexture
{
public:
  GLuint m_tex;
    glTexture(){m_tex=0;}

    glTexture(const char* fname,
        bool make_mipmaps=true);

    ~glTexture();

    void MakeCurrent();
};

glTexture::glTexture(const char *fname,
    bool make_mipmaps)
{

    std::vector<unsigned char> image;
    unsigned int width, height;
    unsigned int error = lodepng::decode(image, width, height, fname);

    if (error != 0)
    {
        std::cout << "error " << error << ": " << lodepng_error_text(error) << std::endl;
        return;
    }

    m_tex = 0;
    glEnable(GL_TEXTURE_2D);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    //Get a texture space and make it active
    glGenTextures(1, &m_tex);
    glBindTexture(GL_TEXTURE_2D, m_tex);

    //Set default(and fastest) texture propoties
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    //Determine if mipmaps are used
    if (make_mipmaps)
    {
        gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &image[0]);
    }
    else
    {

        double xPow2, yPow2;
        int ixPow2, iyPow2;
        int xSize2, ySize2;
        unsigned char* pData = NULL;

        GLint glMaxTexDim;
        //Get the maximum texture size
        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);
        //Get the powers of 2 that correspond to the width and height of the original
        //or of the maxmaximum texture size if widthor height is larger than the maxmaximum texture size
        if (width <= glMaxTexDim)
            xPow2 = log((double)width) / log((double)2.0);
        else
            xPow2 = log((double)glMaxTexDim) / log((double)2.0);

        if (height <= glMaxTexDim)
            yPow2 = log((double)height) / log((double)2.0);
        else
            yPow2 = log((double)glMaxTexDim) / log((double)2.0);

        //round the power of 2 up to the nearest power of 2
        ixPow2 = (int)xPow2;
        iyPow2 = (int)yPow2;

        if (xPow2 != (double)ixPow2)
            ixPow2++;
        if (yPow2 != (double)iyPow2)
            iyPow2++;
        //convert power to actual value
        xSize2 = 1 << ixPow2;
        ySize2 = 1 << iyPow2;
        //if the new sizes are different than the old ones
        //resize and scale the "RGBAImage"
        if (xSize2 != width  ySize2 != height)
        {
            pData = (unsigned char*)malloc(xSize2 * ySize2 * 4 * sizeof(unsigned char));

            if (!pData)
                return;

            gluScaleImage(GL_RGBA,
                width,
                height,
                GL_UNSIGNED_BYTE,
                &image[0],
                xSize2,
                ySize2,
                GL_UNSIGNED_BYTE,
                pData);

            width = xSize2;
            height = ySize2;
        }

        glTexImage2D(GL_TEXTURE_2D,
            0, 4, width,height,
            0, GL_RGB, GL_UNSIGNED_BYTE,pData);

        if (pData)
        {
            free(pData);
            pData = NULL;
        }
    }    
}

void glTexture::MakeCurrent()
{
    glBindTexture(GL_TEXTURE_2D, m_tex);
}

glTexture::~glTexture()
{
    glDeleteTextures(1, &m_tex);
}
8、行星结构的定义
class planet
{
public:
  float aroundRotatedSpeed;//公转
  float selfRotatedSpeed;//自转
  float radius;//行星的半径,影响绘制的大小啦
  //下面这个变量代表当前行星离父亲之间的的距离拉
  //1.太阳系以太阳为中心进行运动
  //2.除地球外其他行星相对于太阳进行自转和公转,因此对于其他行星来说,太阳就是父亲,其他行星就是儿子
  //3比较特殊的是地球,地球也是相对太阳进行自转和公转的,但是地球还有一个儿子,既月球,因此对于月球来说,他的父亲是地球,他的父亲的父亲是太阳
  //层次关系总结如下:
  //   太阳
  //      除地球和月球外的其他行星
  //      地球
  //         月球
  vec3 pos;

  glTexture *texture;
public:

  planet(const char* texname,float as,float ss,float radius,vec3 pos)
  {
    texture=new glTexture(texname,true);
    this->aroundRotatedSpeed =as;
    this->selfRotatedSpeed =ss;
    this->radius =radius;
    this->pos =pos;

  }

  ~planet()
  {
      if (!texture)
      {
          delete texture;
          texture = NULL;
      }
  }

};
9、录制与回放,采取最简单的方式,记录当前的angle,所有的星球运动都是基于当前anlge变量,因此其他运动都是当前角度的某个映射关系,因此只要记录当前的angle,就能实现录制和回放功能(其实由上述代码可见,纯粹是为了完成任务,因此采取最简洁有效方式,哈哈哈)
int angle = 0; //核心变量,所有行星的移动和转动的速度是以angle为基础的啦,改变angle旋转速度会影响所有行星的运动速度,包括角速度和距离,所有行星都是按照angle相对比例进行运动

void record()
{
    if (filesys.beginWrite("test.txt"))
    {
        filesys.writeInt(angle);
        filesys.closeFile();
    }
}

void rePlay()
{
    if (filesys.beginRead("test.txt"))
    {
        filesys.readInt(&angle);
        filesys.closeFile();
    }
}
 10、main.cpp
//全局变量声明
bool lighting = true;
fileSystem filesys;//record/replay系统使用
int frontViewOnOff;//开关变量,前视图和正视图转换
glTexture *boxtex;//天空盒纹理贴图,理论上天空盒需要六张无缝拍摄的纹理,现在就用一张贴在天空盒六个面上,简化一下
glTexture *parttex;
glExplosion * glexp = new glExplosion(1, vec3(0, 0, 0), 1.0f, 0);
bool isexp = true;
int numexp;
float px, py, pz;
glTrail* trail;

//行星系统
planet *sun; //太阳
planet *sx;  //水星
planet *jx;  //金星
planet *hx;  //火星
planet *mx;  //木星
planet *tx;  //土星
planet *twx; //天王星
planet *hwx; //海王星

planet * earth; //地球
planet * moon;  //月亮

glCamera camera(vec3(0.0f, 0.0f, 10.0f)); //摄像机初始位置,w/s键控制摄像机前后移动,a/d控制摄像机左右移动,鼠标左键按下拖动控制摄像机的pitch/yaw旋转

int angle = 0; //核心变量,所有行星的移动和转动的速度是以angle为基础的啦,改变angle旋转速度会影响所有行星的运动速度,包括角速度和距离,所有行星都是按照angle相对比例进行运动

void SetLight(bool b)
{
    float amb[4] = { 1.0, 0.8, 0.8, 1 };
    float dif[4] = { 1.0, 1.0, 1.0, 1 };
    float pos[4] = { 0, 10, 0, 1 };
    glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
    glLightfv(GL_LIGHT0, GL_SPECULAR, dif);
    glLightfv(GL_LIGHT0, GL_POSITION, pos);
    glColorMaterial(GL_FRONT, GL_DIFFUSE);

    if (b)
    {
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
    }
    else
    {
        glDisable(GL_LIGHTING);
        glDisable(GL_LIGHT0);
    }

    glShadeModel(GL_SMOOTH);
}

void init()
{
    boxtex = new glTexture("星空图.png", true);

    sun = new planet("太阳.png", 0.0f, 1.0f, 1.0f, vec3(0.0f, 0.0f, 0.0f));
    sx = new planet("水星.png", 0.5f, 0.5f, 0.2f, vec3(1.4f, 0.4f, 0.0f));
    jx = new planet("金星.png", 0.5f, 0.5f, 0.2f, vec3(3.0f, -0.4f, 0.0f));
    earth = new planet("地球.png", 1.0f, 2.0f, 0.5f, vec3(5.0f, 2.0f, 8.0f));
    moon = new planet("月亮.png", 0.5f, 0.5f, 0.2f, vec3(1.5f, 0.0f, 0.0f));
    hx = new planet("火星.png", 0.2f, 0.3f, 0.3f, vec3(7.0f, 0.0f, 0.0f));
    mx = new planet("木星.png", 0.4f, 1.0f, 0.5f, vec3(10.0f, 0.0f, 0.0f));
    tx = new planet("土星.png", -0.4f, 0.2f, 1.0f, vec3(15.0f, 1.0f, 0.0f));
    twx = new planet("天王星.png", 0.8f, 0.5f, 0.3f, vec3(17.0f, 0.0f, 0.0f));
    hwx = new planet("海王星.png", 0.6f, 0.5f, 0.4f, vec3(19.0f, 0.8f, 0.0f));

    parttex = new glTexture("particle.png");

    trail = new glTrail("spawnflash.png");
    trail->setPath(vec3(0, 0, 0));

    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);

    //初始化二次曲面对象
    drawInit();
}

void deinit()
{
    delete boxtex;
    delete sun;
    delete sx;
    delete jx;
    delete earth;
    delete moon;
    delete hx;
    delete mx;
    delete tx;
    delete twx;
    delete hwx;
    delete parttex;
    delete trail;
    delete glexp;
    drawDeInit();
}

void record()
{
    if (filesys.beginWrite("test.txt"))
    {
        filesys.writeInt(angle);
        filesys.closeFile();
    }
}

void rePlay()
{
    if (filesys.beginRead("test.txt"))
    {
        filesys.readInt(&angle);
        filesys.closeFile();
    }
}

static void DrawEarthAndMoon(planet *earth, planet *moon)
{
    glPushMatrix();//地球公转+自转(围绕太阳)
    earth->texture->MakeCurrent();

    glRotatef(angle*earth->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f);
    glTranslatef(earth->pos.x, earth->pos.y, earth->pos.z);
    glRotatef(angle*earth->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
    drawSphere(earth->radius, 20, 20, true);

    glPushMatrix();//月球公转+自转(围绕地球)
    moon->texture->MakeCurrent();
    glRotatef(angle*moon->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f);
    glTranslatef(moon->pos.x, moon->pos.y, moon->pos.z);
    glRotatef(angle*moon->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
    drawSphere(moon->radius, 20, 20, true);
    glPopMatrix();

    glPopMatrix();
}
static void DrawOtherPlanet(planet * p)
{
    glPushMatrix();
    p->texture->MakeCurrent();
    glRotatef(angle*p->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f);
    glTranslatef(p->pos.x, p->pos.y, p->pos.z);
    glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
    drawSphere(p->radius, 20, 20, true);
    glPopMatrix();
}

static void DrawTrail(planet * p)
{
    glPushMatrix();
    glRotatef(angle*p->aroundRotatedSpeed*2.0f, 0.0f, 1.0f, 0.0f);
    glTranslatef(p->pos.x + 0.4f, p->pos.y + 0.3, p->pos.z);
    glPushMatrix();
    glRotatef(-90.0f, 0.0f, 1.0f, 0.0f);
    trail->draw(camera.pos);
    glPopMatrix();
    glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
    drawSphere(p->radius, 20, 20, true);
    glPopMatrix();
}

static void DrawOtherPlanet2(planet * p)
{
    glPushMatrix();
    p->texture->MakeCurrent();

    glRotatef(angle*p->aroundRotatedSpeed, 0.0f, 1.0f, 0.0f);

    glTranslatef(p->pos.x, p->pos.y, p->pos.z);

    glRotatef(angle*p->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);

    drawSphere(p->radius, 20, 20, true);

    glPushMatrix();
    glRotatef(85, 1.0f, 0.0f, 0.0f);

    drawDisk(1.5, 3, 20);

    glPopMatrix();
    glPopMatrix();

}
void DrawJX()
{
    glPushMatrix();
    jx->texture->MakeCurrent();

    glRotatef(angle*jx->aroundRotatedSpeed * 2, 1.0, 1.0, 1.0);

    glTranslatef(5.0f, 0.0, 0.0f);
    glRotatef(angle*jx->aroundRotatedSpeed * 2, 0.0f, 0.0f, 1.0f);

    drawSphere(jx->radius, 20, 20, true);
    glPopMatrix();
}
void DrawHX()
{
    glPushMatrix();
    hx->texture->MakeCurrent();

    glRotatef(angle*hx->aroundRotatedSpeed * 2, -1.0, -1.0, 0.0);

    glTranslatef(5.0f, 0.0, 0.0f);

    glRotatef(angle*hx->aroundRotatedSpeed * 2, 0.0f, 0.0f, 1.0f);

    drawSphere(hx->radius, 20, 20, true);

    glPopMatrix();

}
void testdraw1(planet *p)
{
    glPushMatrix();
    p->texture->MakeCurrent();

    glRotatef(45, 1.0, 0.0, 0.0);
    glRotatef(angle*p->aroundRotatedSpeed * 2, 0.0f, 1.0f, 0.0f);

    glTranslatef(5.0f, 0, 0.0f);
    glRotatef(angle*p->aroundRotatedSpeed * 2, 0.0f, 0.0f, 1.0f);

    drawSphere(p->radius, 20, 20, true);
    glPopMatrix();
}

void DrawSolarSystem(planet *sun)
{
    sun->texture->MakeCurrent();

    SetLight(lighting);
    glTranslatef(sun->pos.x, sun->pos.y, sun->pos.z);
    glRotatef(angle*sun->selfRotatedSpeed, 0.0f, 1.0f, 0.0f);
    drawSphere(sun->radius, 50, 50, true);
    DrawEarthAndMoon(earth, moon);//地月绘制
    DrawOtherPlanet(sx);
    DrawOtherPlanet(jx);
    DrawOtherPlanet(twx);
    DrawOtherPlanet(hwx);
    //带光圈绘制
    DrawOtherPlanet2(mx);
    DrawOtherPlanet2(tx);
    DrawTrail(jx);
}

void myKeyboardFunc(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 27:        //ESC
        exit(0);    //退出系统
        break;
    case 'w'://摄像机向前运动

        camera.pos -= camera.forward*0.5;
        glutPostRedisplay();
        break;
    case 's'://摄像机向后运动
        camera.pos += camera.forward*0.5;

        glutPostRedisplay();
        break;
    case 'a'://摄像机向左运动

        camera.pos -= camera.right *0.5;
        glutPostRedisplay();
        break;
    case 'd'://摄像机向右运动

        camera.pos += camera.right*0.5;
        glutPostRedisplay();
        break;
    case 'f'://正视图和顶视图切换

        frontViewOnOff ^= 1;
        glutPostRedisplay();
        break;
    case 'r'://记录
        record();
        glutPostRedisplay();
        break;
    case 'p'://回放
        rePlay();
        glutPostRedisplay();
        break;
    case 'l'://灯源开关
        lighting = !lighting;
        glutPostRedisplay();
        break;
    }

}

void myReshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, GLfloat(w) / h, 0.1, 1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glShadeModel(GL_SMOOTH);
}

void creatExplosion(float x, float y, float z, int num, float spread)
{
    if (glexp != NULL) { delete glexp; glexp = NULL; }
    glexp = new glExplosion(num, vec3(0, 0, 0), spread, parttex->m_tex);
    px = x, pz = z, py = y;
    isexp = false;
    numexp = 0;
}

void  drawExplosion()
{
    glPushMatrix();
    glTranslatef(px, py, pz);
    if (isexp == false)
    {
        glexp->Render();
        isexp = true;
    }
    if (isexp)
    {
        glexp->Update(0.03f);
        isexp = false;
    }
    glPopMatrix();
}

void myDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT  GL_DEPTH_BUFFER_BIT);

    camera.update();

    //如果顶视图的话,沿着x轴旋转90度
    glRotatef(frontViewOnOff*90.0f, 1.0f, 0.0f, 0.0f);

    //绘制天空盒
    glDrawSkyBox(boxtex, 0.0f, 0.0f, 0.0f, 1000.0f, 1000.0f, 1000.0f);

    DrawJX();
    DrawHX();
    DrawSolarSystem(sun);

    if (numexp > 100)
    {
        creatExplosion(1.0f, 1.0f, 1.0f, 100, 1.5f);
    }

    drawExplosion();

    angle += 2;
    numexp++;

    glutSwapBuffers();
}

void myTimerFunc(int val)
{
    myDisplay();
    glutTimerFunc(25, myTimerFunc, 0);
}

int  main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA  GLUT_DOUBLE  GLUT_DEPTH);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(800, 600);
    glutCreateWindow("太阳系 w/s/a/d控制摄像机运动 r/录制 p/回放 f/切换正顶视图 l/光源开关");
    init();
    glutDisplayFunc(&myDisplay);
    glutReshapeFunc(&myReshape);
    glutKeyboardFunc(&myKeyboardFunc);
    glutTimerFunc(25, myTimerFunc, 0);
    glutMainLoop();
    deinit();
    return 0;
}
 11、源码下载以及参考文档

完整的源代码可以到 https://github.com/jackyblf/SolarSystem-openGL- 进行下载。

源码中包含了billboardingtut.pdf的文档,讲解了所有的billboard类型以及适用范围,基于opengl描述。强烈推荐这篇文档

4人推荐
随时随地看视频
慕课网APP