VC++下,使用OpenGL实现星系运行的模拟
编程实现:太阳的顺时针自转,地球绕太阳公转,地球自转,给地球加上卫星,卫星绕着地球公转。
(1)相关算法及原理描述:
1. 平移变换
平移变换函数如下:
void glTranslated(GLdouble x,GLdouble y,GLdouble z);
void glTranslatef(GLfloat x,GLfloat y,GLfloat z);
三个参数就是目标分别沿三个轴的正向平移的偏移量。这个函数表示用这三个偏移量生成的矩阵乘以当前矩阵。当参数是(0.0,0.0,0.0)时,生成的矩阵是单位矩阵,此时对物体没有影响。
2. 旋转变换
旋转变换函数如下:
void glRotated(GLdouble angle,GLdouble x,GLdouble y,GLdouble z );
void glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);
函数中第一个参数是表示目标沿从原点到指定点(x,y,z)的方向矢量逆时针旋转的角度,后三个参数则是指定旋转方向矢量的坐标。这个函数表示用这四个参数生成的矩阵完成乘法。当角度参数是0.0时,表示对物体没有影响。
3. 缩放变换
缩放变换函数如下:
void glScaled(GLdouble x,GLdouble y,GLdouble z);
void glScalef(GLfloat x,GLfloat y,GLfloat z);
三个参数值就是目标分别沿三个轴向缩放的比例因子。这个函数用这三个比例因子生成的矩阵完成乘法。这个函数能完成沿相应的轴对目标进行拉伸、压缩和反射三项功能。当参数是(1.0,1.0,1.0)时,对物体没有影响。当其中某个参数为负值时,表示将对目标进行相应轴的反射变换,且这个参数不为1.0,则还要进行相应轴的缩放变换。最好不要令三个参数值都为零,这将导致目标沿三轴都缩为零。
通过上述的高级矩阵函数,可以很方便地实现变换,但是这里存在一个问题:在调用函数时,修改的是当前的模型视图矩阵。新的矩阵随后将成为当前的模型视图矩阵并影响此后绘制的图形。这样模型视图矩阵函数在调用时,就会有造成效果的积累,请看下面一段代码:
//沿x轴正向移动10个单位
glTranslatef(10.0f, 0.0f, 0.0f);
glutSolidSphere(1.0f, 15, 15);
//沿y轴正向移动10个单位
glTranslatef(0.0f,10.0f, 0.0f);
glutSolidSphere(1.0f);
要消除效果积累一种简单的方法就是把模型矩阵复位,即通过给模型视图矩阵加载上单位矩阵来复位原点。下面的代码把单位矩阵加载到模型视图矩阵中:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
第一个函数用于指定当前操作的矩阵,其函数原型如下:
glMatrixMode(GLenummode);
其中参数mode用于确定将哪个矩阵堆栈用于矩阵操作,它的取值有:GL_MODELVIEW(模型视图矩阵堆栈),GL_PROJECTION(投影矩阵堆栈)和GL_TEXTURE(纹理矩阵堆栈)。一旦设置了当前操作矩阵,它就将保持为活动的矩阵,直到重新修改它为止。
第二个函数glLoadIdentity()的作用就是给当前操作矩阵加载上单位矩阵。
(2)程序设计:
1.添加头文件:
#include"gl/glut.h" // 将相关头文件包含在程序中
2,初始化函数:void init( ) ,代码如下:
void init( )
{
glClearColor (1.0,1.0, 1.0, 0.0); //将显示窗口的背景颜色设定为白色.
glShadeModel(GL_FLAT); //设置阴影模式为平面明暗模式
}
3.加上绘制函数:void display( ) ,代码如下:
void display( )
{
glClear(GL_COLOR_BUFFER_BIT); // 清理显示窗口.
glColor3f (1.0,0.0, 0.0); // 设置绘图颜色为红色.
glPushMatrix(); //把矩阵压入堆栈
//第一个参数表示目标沿从原点到指定点(x,y,z)的方向矢量逆时针旋转的角度,后三个参数则是 //指定旋转方向矢量的坐标。
glRotatef((GLfloat) sun_rotation, 0.0, -1.0, 2.0); //地球自转轴的偏转角度
glRotatef(30, 1.0,0.0, 0.0); //距离X轴偏转30度
// glutWireSphere中第1、2、3个参数分别表示半径,经度线数、纬度线数
glutWireSphere(1.0,20, 16); // 按给定的参数值绘制太阳
glPopMatrix();
glColor3f (0.0,0.0, 1.0); // 设置绘图颜色为蓝色.
glPushMatrix();
glRotatef((GLfloat)earth_revolution,0.0, 0.0, 1.0); // 地球公转轴的偏转角度
glTranslatef(2.0,0.0, 0.0); // 通过平移变换,产生太阳和地球之间的距离
glPushMatrix();
glRotatef((GLfloat)earth_rotation,0.0, -1.0, 2.0); //地球自转轴的偏转角度
glRotatef(10, 1.0,0.0, 0.0); // 距离X轴偏转10度
glutWireSphere(0.25,10, 8); // 按给定的参数值绘制地球
//绘制卫星
glTranslatef(0.5,0.0, 0.0); // 通过平移变换,产生卫星和地球之间的距离
glRotatef((GLfloat)planet_revolution,0.0, -1.0, 2.0); //卫星公转的偏转角度
glRotatef(10, 1.0,0.0, 0.0); // 距离X轴偏转10度
glutWireSphere(0.15,10, 8); // 按给定的参数值绘制卫星
glPopMatrix();
glPopMatrix();
glutSwapBuffers(); // 刷新命令缓冲区
}
void reshape (intw, int h)
{
glViewport (0, 0,(GLsizei) w, (GLsizei) h); 设置视区尺寸
// 重置坐标系统,使投影变换复位
glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
//创建透视投影矩阵,4个参数分别表示:y方向上可见区域的夹角;纵横比为x(宽度)/y(高度);//从观察者到近修剪平面的距离;从观察者到远修剪平面的距离
gluPerspective(60.0,(GLfloat) w/(GLfloat) h, 1.0, 20.0);
// 重置坐标系统,使投影变换复位
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//定义视景转换,前3个参数表示视点的空间位置;中间3个参数表示参考点的空间位置;最后3
//个参数表示向上向量的方向
gluLookAt (0.0,0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
5.加上键盘响应函数:vvoid keyboard (unsignedchar key, int x, int y),代码如下:
void keyboard(unsigned char key, int x, int y) //定义键盘按键操作
{
switch (key) {
case 'w':
//按键盘w则卫星顺时针自转,每次旋转角度为20度
planet_revolution= (planet_revolution + 10) % 360;
//地球逆时针自转,每次旋转角度为10度
earth_rotation =(earth_rotation - 10) % 360;
//地球绕着太阳逆时针公转,每次旋转角度为5度
earth_revolution =(earth_revolution + 3) % 360;
//太阳逆时针自转,每次旋转角度为10度
sun_rotation =(sun_rotation - 10) % 360;
glutPostRedisplay();
break;
default:
break;
}
}
6.添加主函数:void main( ) ,代码如下:
void main( )
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // 设置OpenGL窗口的显示模式
glutInitWindowSize(500, 500); //设置显示窗口的宽和高
glutInitWindowPosition(100, 100); //设置显示窗口左上角坐标
glutCreateWindow("The model of galaxy"); // 创建显示窗口
init (); //初始化
glutDisplayFunc(display); //将图形发送至显示窗口
glutReshapeFunc(reshape); // 为当前窗口设置窗口再整形回调函数
glutKeyboardFunc(keyboard);//接收键盘操作
glutMainLoop(); //显示初始图形并使程序进入检查鼠标或键盘等设备输入的无穷循环中
}
(3)程序调试、测试与运行结果分析:

