九大行星运行
基于opengl实现
background类实现背景加载
/*backgrounbd.h*/
#pragma once
#include "windows.h"
#include <gl/GL.h>
// 宇宙背景
class background
{
public :
void Init();
void draw();
background();
virtual ~background();
private :
// 纹理
GLuint m_uText;
};
/*backgrounbd.cpp*/
#include "background.h"
#include <gl\GLAux.h>
#include "io.h"
#pragma warning(disable : 4996)
background::background()
: m_uText(0)
{
}
background::~background()
{
glDeleteTextures(1, &m_uText);
}
void background::Init()
{
if (access("tex\\bk.bmp", 0) == -1)
return;
AUX_RGBImageRec* irec = auxDIBImageLoad("tex\\bk.bmp");
// 加载贴图
glGenTextures(1, &m_uText);
glBindTexture(GL_TEXTURE_2D, m_uText);
glTexImage2D(GL_TEXTURE_2D, 0, 3, irec->sizeX, irec->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, irec->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); // 线形滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
//释放资源
if (irec)
{
if (irec->data)
free(irec->data);
free(irec);
}
}
void background::draw()
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDepthMask(FALSE);
glEnable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 1, 0, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, m_uText);
glBegin(GL_POLYGON);
glColor3f(1, 1, 1);
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(1, 0);
glTexCoord2f(1, 1);
glVertex2f(1, 1);
glTexCoord2f(0, 1);
glVertex2f(0, 1);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glDepthMask(TRUE);
}
camera类实现移动
/*camera.h*/
#pragma once
//相机类的声明
class camera
{
public:
camera();
virtual ~camera();
// 更新相机位置
void update();
// 响应键盘消息
void keyfunc(int key);
// 响应鼠标消息
void mousefunc(int button, int state, int x, int y);
void motion(int x, int y);
private:
// 是否左键按下
bool m_leftkey;
// 是否右键按下
bool m_rigtkey;
// 上一次x坐标
int m_px;
// 上一次y坐标
int m_py;
// x轴移动
int m_dx;
// y轴移动
int m_dy;
// z轴移
int m_dz;
// x轴旋转
int m_rx;
// y轴旋转
int m_ry;
};
/*camera.cpp*/
#include "camera.h"
#include "glut.h"
#include "stdio.h"
camera::camera()
: m_leftkey(false), m_rigtkey(false),
m_dx(0), m_dy(0), m_dz(0),
m_rx(25), m_ry(2)
{
}
camera::~camera()
{
}
//响应键盘输入
void camera::keyfunc(int key)
{
switch (key)
{
case 'A' :
case 'a' :
{
m_dx += 50;
}
break;
case 'D' :
case 'd' :
{
m_dx -= 50;
}
break;
case 'W' :
case 'w' :
{
m_dz += 50;
}
break;
case 'S' :
case 's' :
{
m_dz -= 50;
}
break;
default :
break;
}
}
//响应鼠标输入
void camera::mousefunc(int button, int state, int x, int y)
{
switch (button)
{
case 0 :
m_leftkey = !state;
break;
case 1 :
break;
case 2 :
m_rigtkey = !state;
break;
default :
break;
}
m_px = x;
m_py = y;
}
void camera::motion(int x, int y)
{
if (m_leftkey)
{
m_dx += x - m_px;
m_dy += m_py - y;
}
if (m_rigtkey)
{
m_ry += (m_px - x) / 5;
m_rx += (y - m_py) / 5;
}
m_px = x;
m_py = y;
}
void camera::update()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,4000, 0,0,0, 0,1,0);
glTranslatef(m_dx, m_dy, m_dz);
glRotatef(m_rx, 1, 0 ,0);
glRotatef(m_ry, 0, 1, 0);
}
planet类实现星球运行
/*planet.h*/
#pragma once
// 星球类
#include "windows.h"
#include <gl/GL.h>
#include "vector"
#include "math.h"
using namespace std;
// 位置结构
struct point
{
float x;
float y;
float z;
//构造函数
point(float _x = 0, float _y = 0, float _z = 0)
: x(_x), y(_y), z(_z)
{
}
// 单位化,即变为该方向的单位向量)
void normalize()
{
float len = sqrtf(x * x + y * y + z * z); //计算距离
//归一化,即用分量除长度
x /= len;
y /= len;
z /= len;
}
};
// 星体
class planet
{
public :
planet(point _pos, point _axes_rev, float _size, float _rev_speed, float _rota_speed, bool _sun, const char texname[]);
virtual ~planet();
// 公转,自转角度更新
void update(float timepass);
// 绘制
void draw();
// 加入附属星体,比如8/9大行星都是太阳的附属星体,月亮是地球的附属星体
void add_secondary(planet* p);
private :
// 附属星体列表
vector<planet*> m_secondary;
// 位置
point m_pos;
// 大小
float m_size;
// 是否是太阳
bool m_sun;
// 公转速度
float m_rev_speed;
// 自转速度
float m_rota_speed;
// 公转角度
float m_revolution;
// 自转角度
float m_rotation;
// 自转轴
point m_axes;
// 公转轴
point m_axes_rev;
// 和太阳的距离
float m_distance2sun;
// 纹理
GLuint m_tex;
};
/*planet.cpp*/
#include "planet.h"
#include "glut.h"
#include <string.h>
#include <stdio.h>
#include "io.h"
#include <gl\GLAux.h>
#include "math.h"
#pragma warning(disable : 4996)
planet::planet(point _pos, point _axes_rev, float _size, float _rev_speed, float _rota_speed, bool _sun, const char texname[])
: m_pos(_pos), m_axes_rev(_axes_rev), m_size(_size), m_sun(_sun), m_tex(0),
m_rev_speed(_rev_speed), m_rota_speed(_rota_speed),
m_revolution(0),m_rotation(0), m_distance2sun(_pos.x),
m_axes((float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX)
{
m_axes.normalize();
if (access(texname, 0) == -1)
return;
// 加载贴图
AUX_RGBImageRec* irec = auxDIBImageLoad(texname);
glGenTextures(1, &m_tex);
glBindTexture(GL_TEXTURE_2D, m_tex);
glTexImage2D(GL_TEXTURE_2D, 0, 3, irec->sizeX, irec->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, irec->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
if (irec)
{
if (irec->data)
free(irec->data);
free(irec);
}
}
planet::~planet()
{
for (size_t i = 0; i < m_secondary.size(); ++i)
delete[] m_secondary[i];
}
// 绘制球体函数
void draw_sphere()
{
static GLuint uList = 0;
int x=0;
int i=0;
if (uList == 0)
{
// 构建球体网格
point** vs = new point*[37];
for (int i = 0; i <= 36; ++i)
vs[i] = new point[37];
for (x = 0; x <= 36; ++x)
{
float ax = 3.141592654f * x * 10 / 180.f;
point s = point(0, -sinf(ax), cosf(ax) );
for (int y = 0; y <= 36; ++y)
{
point& v = vs[x][y];
float ay = 3.141592654f * y * 10 / 180.f;
v.x = s.x * cosf(ay) + s.z * sinf(ay);
v.y = s.y;
v.z = s.x * -sinf(ay) + s.z * cosf(ay);
}
}
// 创建显示列表
uList = glGenLists(1);
glNewList(uList, GL_COMPILE);
glBegin(GL_QUADS);
glColor3f(1, 1, 1);
for (x = 0; x < 36; ++x)
{
for (int y = 0; y < 36; ++y)
{
point& a = vs[x][y];
point& b = vs[x][y + 1];
point& c = vs[x + 1][y + 1];
point& d = vs[x + 1][y];
point na = a;
point nb = b;
point nc = c;
point nd = d;
na.normalize();
nb.normalize();
nc.normalize();
nd.normalize();
const float scal = 0.8f;
glTexCoord2f((a.x * scal + 1) / 2, (a.y * scal + 1) / 2);
glNormal3f(na.x, na.y, na.z);
glVertex3f(a.x, a.y, a.z);
glTexCoord2f((b.x * scal + 1) / 2, (b.y * scal + 1) / 2);
glNormal3f(nb.x, nb.y, nb.z);
glVertex3f(b.x, b.y, b.z);
glTexCoord2f((c.x * scal + 1) / 2, (c.y * scal + 1) / 2);
glNormal3f(nc.x, nc.y, nc.z);
glVertex3f(c.x, c.y, c.z);
glTexCoord2f((d.x * scal + 1) / 2, (d.y * scal + 1) / 2);
glNormal3f(nd.x, nd.y, nd.z);
glVertex3f(d.x, d.y, d.z);
}
}
glEnd();
glEndList();
for (i = 0; i <= 36; ++i)
delete[] vs[i];
delete vs;
}
glCallList(uList);
}
void draw_circle()
{
static GLuint uList = 0;
if (uList == 0)
{
// 创建显示列表
uList = glGenLists(1);
glNewList(uList, GL_COMPILE);
glBegin(GL_LINE_STRIP);
glColor3f(0.5, 0.5, 0.5);
for (int x = 0; x <= 36; ++x)
{
float ay = 3.141592654f * x * 10 / 180.f;
point v;
v.x = sinf(ay);
v.y = 0;
v.z = cosf(ay);
glVertex3f(v.x, v.y, v.z);
}
glEnd();
glEndList();
}
glCallList(uList);
}
//更新自传角度和公转角度
void planet::update(float timepass)
{
m_revolution += timepass * m_rev_speed;
m_rotation += timepass * m_rota_speed;
for (size_t i = 0; i < m_secondary.size(); ++i)
m_secondary[i]->update(timepass);
}
void planet::draw()
{
if (m_sun)
{
// 绘制各个附属太阳的行星的轨道
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
for (size_t i = 0; i < m_secondary.size(); ++i)
{
glPushMatrix();
glScalef(m_secondary[i]->m_distance2sun, m_secondary[i]->m_distance2sun, m_secondary[i]->m_distance2sun);
draw_circle();
glPopMatrix();
}
glEnable(GL_TEXTURE_2D);
}
else
glEnable(GL_LIGHTING);
// 绘制星体
glPushMatrix();
glRotatef(m_revolution, m_axes_rev.x, m_axes_rev.y, m_axes_rev.z);
glTranslatef(m_pos.x, m_pos.y, m_pos.z);
glPushMatrix();
glRotatef(m_rotation, m_axes.x, m_axes.y, m_axes.z);
glScalef(m_size, m_size, m_size);
glBindTexture(GL_TEXTURE_2D, m_tex);
draw_sphere();
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
// 绘制附属星体
for (size_t i = 0; i < m_secondary.size(); ++i)
m_secondary[i]->draw();
glPopMatrix();
glDisable(GL_LIGHTING);
}
void planet::add_secondary(planet* p)
{
m_secondary.push_back(p);
}
主函数
#include <stdio.h>
#include <gl\GLAux.h>
#include "glut.h"
#include "math.h"
#include "camera.h"
#include "planet.h"
#include "background.h"
#pragma comment(lib, "glaux.lib")
// 窗口大小
#define VIEWWEIGHT 600
#define VIEWHIGHT 500
// 相机
camera cameraobj;
// 宇宙背景
background bk;
// 太阳
planet* solar = 0;
void Display(void)
{
static DWORD ptime = GetTickCount();
DWORD ntime = GetTickCount();
glClear(GL_DEPTH_BUFFER_BIT);
// 更新相机
cameraobj.update();
// 绘制背景
bk.draw();
// 绘制太阳及其附属行星
if (solar)
{
solar->update((float)(ntime - ptime) / 1000.f);
glEnable(GL_TEXTURE_2D);
solar->draw();
glDisable(GL_TEXTURE_2D);
}
ptime = ntime;
glutSwapBuffers();
}
void Run()
{
Display();
}
void KeyboardFunc(unsigned char key,int x, int y)
{
cameraobj.keyfunc(key);
}
void Init()
{
glShadeModel(GL_SMOOTH);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
// 初始化光照
glEnable(GL_NORMALIZE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
float amb[4]={0.2,0.2,0.2,1}; //
float dif[4]={1.0,1.0,1.0,1}; //方向向量
float pos[4]={0,0,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);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, TRUE);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, dif);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, dif);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, dif);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128);
// 初始化背景
bk.Init();
// 初始化太阳系
solar = new planet(point(0, 0, 0), point(0, 1, 0), 300, 0, 10, true, "tex\\sun.bmp");
solar->add_secondary(new planet(point(400, 0, 0), point(0, 1, 0), 40, 10, 20, false, "tex\\p1.bmp"));
solar->add_secondary(new planet(point(580, 0, 0), point(0, 1, 0), 60, 20, 30, false, "tex\\p2.bmp"));
planet* ear = new planet(point(750, 0, 0), point(0, 1, 0), 55, 30, 40, false, "tex\\ear.bmp");
ear->add_secondary(new planet(point(100, 0, 0), point(1, 1, 0), 10, 200, 40, false, "tex\\moon.bmp"));
solar->add_secondary(ear);
solar->add_secondary(new planet(point(890, 0, 0), point(0, 1, 0), 50, 35, 25, false, "tex\\p4.bmp"));
solar->add_secondary(new planet(point(1200, 0, 0), point(0, 1, 0), 120, 15, 50, false, "tex\\p5.bmp"));
solar->add_secondary(new planet(point(1500, 0, 0), point(0, 1, 0), 100, 50, 30, false, "tex\\p6.bmp"));
solar->add_secondary(new planet(point(1800, 0, 0), point(0, 1, 0), 90, 20, 35, false, "tex\\p7.bmp"));
solar->add_secondary(new planet(point(2050, 0, 0), point(0, 1, 0), 90, 40, 20, false, "tex\\p8.bmp"));
#if 0
printf("太阳系模拟程序\n\n");
printf("键盘 A : 左移\n");
printf("键盘 D : 右移\n");
printf("键盘 W : 前移\n");
printf("键盘 S : 后移\n");
printf("鼠标左键 : 平移\n");
printf("鼠标右键 : 旋转\n");
#endif
}
void UnInit()
{
if (solar)
delete solar;
}
void Reshape(int w,int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,GLfloat(w)/h,1,50000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
}
void MouseFunc(int button, int state, int x, int y)
{
cameraobj.mousefunc(button, state, x, y);
}
void MotionFunc(int x, int y)
{
cameraobj.motion(x, y);
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(VIEWWEIGHT, VIEWHIGHT);
glutCreateWindow("太阳系");
glutDisplayFunc(&Display);
glutIdleFunc(&Run);
glutReshapeFunc(&Reshape);
glutKeyboardFunc(&KeyboardFunc);
glutMouseFunc(&MouseFunc); //注册鼠标响应函数
glutMotionFunc(&MotionFunc);
Init();
glutMainLoop(); //主消息循环
UnInit();
return 0;
}