学习于OpenGL入门、OpenGL编程指南、gluPerspective
#include "pch.h"
#include
#include
#include
#include
const GLdouble Pi = 3.1415926536;
/*
太阳半径69600km
地球半径6378km
月球半径1739km
地球到太阳的距离约为1.5亿km=150000000km
月亮到地球的距离约为 380000km
*/
/*修改不至于比例差距太大
太阳半径69600000km(放大100倍)
地球半径15945000km(放大 2500 倍)
月球半径4345000km (放大 2500 倍)
地球到太阳的距离约为1.5亿km=150000000km(保持不变)
月亮到地球的距离约为 38000000km(放大 100 倍)
*/
/*
假设三个天体都是球体,都处于同一平面
假设每个月都是30天,一年12个月,共有360天
太阳中心为原点,天体轨迹所在的平面表示了 X 轴与 Y 轴决定的平面,
且每年第一天,地球在 X 轴正方向上,月亮在地球的正 X 轴方向。
*/
static int day = 200;
double CalFrequency() {
static int count;
static double save;
static clock_t last, current;
double timegap;
++count;
if (count <= 50)
return save;
count = 0;
last = current;
current = clock();
timegap = (current - last) / (double)CLK_TCK;
save = 50.0 / timegap;
return save;
}
void myDisplay(void)
{
double FPS = CalFrequency();
printf("FPS = %f\n", FPS);
//glEnable(GL_DEPTH_TEST); //启动深度测试
//glClear清除 GL_COLOR_BUFFER_BIT 表示清除颜色,GL_DEPTH_BUFFER_BIT表示清空深度缓冲
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
/**************第一步确立可视空间*****************/
glMatrixMode(GL_PROJECTION);//操作投影矩阵
glLoadIdentity(); //将当前矩阵设置为单位矩阵
//为了透视效果,使用gluPerspective设置可视空间,设定视角为75(可修改)
//窗口大小为(400,400),所以高宽比为1.0。
//最近可视距离为1.0。最远可视距离为200000000*2=400000000
gluPerspective(75,1,1, 400000000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*
gluLookAt();前三个参数表示了观察点的位置,中间三个参数表示了观察目标的参数,
最后三个参数表示从(0,0,0)到(x,y,z)的直线,他表示观察者认为上的方向
观察目标设置为太阳中心,选择Z轴正方向为上方向,将地球半径取整200000000
*/
gluLookAt(0, -200000000, 200000000, 0, 0,0, 0, 0, 1);
/****************绘制红色的太阳**************************/
glColor3f(1.0f,0.0f,0.0f);
glutSolidSphere(69600000, 20, 20);//球体半径,薄片数值,堆数值(后面两个都是描述球体精确度的)
//绘制蓝色的地球
glColor3f(0.0f,0.0f,1.0f);
//今年已经经过的天数已知为 day,则地球转过的角度为 day/一年的天数*360 度。 前面已经假定每年都是 360 天
// 注意地球公转是“自西向东”的,因此是饶着 Z 轴负方向进行逆时针旋转
glRotatef(day / 360.0*360.0, 0.0f, 0.0f, -1.0f);
//glTranslatef(地球轨道半径, 0, 0);
glTranslatef(150000000, 0.0f, 0.0f);
glutSolidSphere(15945000, 20, 20);
//绘制黄色的月亮
glColor3f(1.0f,1.0f,0.0f);
/*
在绘制地球是,坐标已经旋转过的,现在的旋转是在以前的基础上进行旋转的,所以要处理差值
可以在绘制地球前用glPushMatrix保存矩阵,绘制完地球后用glPopMatrix恢复矩阵。
再设计一个跟地球位置无关的月亮位置公式绘制月亮
*/
glRotatef(day / 30.0*360.0 - day / 360.0*360.0, 0.0f, 0.0f, -1.0f);
glTranslatef(38000000, 0.0f, 0.0f);
glutSolidSphere(4345000, 20, 20);
/* OpenGL 把三维坐标中的物体绘制到二维屏幕,绘制的顺序是按照代码的顺序来进行的。
因此 后绘制的物体会遮住先绘制的物体,即使后绘制的物体在先绘制的物体的“后面”也是如此。*/
glFlush();
glutSwapBuffers();
}
void myIdle(void) { /* 新的函数,在空闲时调用,作用是把日期往后移动一天并重新绘制,达到动画效果 */
++day;
if (day >= 360)
day = 0;
myDisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv); /*glutInit,对 GLUT 进行初始化,这个函数必须在其它的 GLUT 使用之前调用一次。 */
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); // 设置显示方式,使用RGB颜色 GLUT_DOUBLE 双缓冲
glutInitWindowPosition(100, 100); /*设置窗口在屏幕中的位置*/
glutInitWindowSize(400, 400); /*设置窗口的大小*/
glutCreateWindow("太阳,地球和月亮"); // 改了窗口标题
glutDisplayFunc(&myDisplay);
glutIdleFunc(&myIdle);
glutMainLoop(); /*进行一个消息循环*/
return 0;
}
void gluPerspective(
GLdouble fovy, //角度
GLdouble aspect,//视景体的宽高比
GLdouble zNear,//沿z轴方向的两裁面之间的距离的近处
GLdouble zFar //沿z轴方向的两裁面之间的距离的远处
)
这个函数指定了观察的视景体(frustum为锥台的意思,通常译为视景体)在世界坐标系中的具体大小。
(1)参数fovy,指定视景体的视野的角度,以度数为单位,y轴的上下方向(Specifies the field of view angle, in degrees, in the y direction.)
(2)参数aspect,应该与窗口的宽高比大小相同。比如说,aspect=2.0表示在观察者的角度中物体的宽度是高度的两倍,在视口中宽度也是高度的两倍,这样显示出的物体才不会被扭曲。(Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).)
(3)参数zNear,指定观察者到视景体的最近的裁剪面的距离(必须为正数)
(Specifies the distance from the viewer to the near clipping plane (always positive).)
(4)参数zFar,指定观察者到视景体的最远的裁剪面的距离(必须为正数)
(Specifies the distance from the viewer to the far clipping plane (always positive).)
由gluPerspective产生的矩阵是与当前矩阵与指定的矩阵相乘得到的,就好像是调用glMatrix()产生的矩阵一样。为了使透视矩阵替代当前矩阵,在调用gluPerspective之前要先调用glLoadidentity()这个函数(就是把当前矩阵s设置为单位矩阵)。