因为可能要做太阳系,所以通过此程序先了解一下,顺便学习以下知识。没有列出来的,代码里如果有注释的话,也要看一下。
学习要点
理解glMatrixMode()设置的几种变换。
了解gluPerspective()和gluLookAt()的参数,清楚他们该如何使用的。理解OpenGL下的三维座标的展示,观察一个物体的角度。
理解深度缓冲区。
了解怎么用glutSolidSphere()画一个圆。
关于旋转和平移的用法,glRotatef(),glTranslatef()。
相关学习资料
要点简单解析
其实就是注释里写的,解释的比较简单,主要是函数参数解释,详细解释和深入理解还得看其他的文章。
投影变换
glMatrixMode(GL_PROJECTION);
gluPerspective(75, 1, 1, 2000);
在投影变换下才能设置。透视投影空间, 近大远小的那种感觉。
参数:
眼睛睁开的角度,实际窗口的纵横比,眼睛距离近处的距离,远处的裁面(即后面两个参数表示眼睛能看的多远)。
函数设置投视角设为75度, 在y轴方向上以角度为单位的视野, 度数越大离的越远看的越小。
模型变换
在模型变换下可以对矩阵进行变换,移动旋转缩放等。
glMatrixMode(GL_MODELVIEW);
gluLookAt(0, -200, 200, 0, 0, 0, 0, 0, 1)
参数:每三个参数表示一个座标
eye眼睛在世界座标系的位置,center眼睛看的那个点的座标,up观察者本身的方向,比如正立还是倒立异或某一个角度在看。
函数表示在(0, -200, -200)的位置正着向(0, 0, 0)点看去。
深度缓冲区
opengl默认是没有开启深度检测的,也就是说, 后绘制的物体覆盖先绘制的物体。
当开启更新深度缓冲区的功能,也就是,如果通过比较后,深度值发生变化了,会进行更新深度缓冲区的操作。启动后,OpenGL就可以跟踪在Z轴上的像素,这样,它只会再那个像素前方没有东西时,才会绘制这个像素。
#include<Windows.h>
#include<GL\glut.h>
//太阳、地球和月亮
//假设每个月都是30天
//一年12个月,共是360天
static int day = 200; // day的变化:从0到359
void myDisplay(void)
{
/*用来开启更新深度缓冲区的功能,也就是,如果通过比较后深度值发生变化了,
会进行更新深度缓冲区的操作。启动它,OpenGL就可以跟踪再Z轴上的像素,
这样,它只会再那个像素前方没有东西时,才会绘画这个像素。*/
glEnable(GL_DEPTH_TEST);
/*opengl默认是没有开启深度检测的,也就是说,
后绘制的物体覆盖先绘制的物体(颜色缓冲区中,先绘制的物体 被 后绘制的物体 覆盖)。*/
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION); //投影变换
glLoadIdentity(); //调用单位矩阵
//投视角设为75度, 在y轴方向上以角度为单位的视野, 度数越大离的越远看的越小
//参数 眼睛睁开的角度 实际窗口的纵横比 眼睛距离近处的距离 远处的裁面(即眼睛能看的多远)
gluPerspective(75, 1, 1, 2000); //透视投影空间, 近大远小
glMatrixMode(GL_MODELVIEW); //模型变换
glLoadIdentity();
//eye眼睛在世界座标系的位置,
//center眼睛看的那个点的座标,
//up观察者本身的方向,比如正立还是倒立异或某一个角度在看
gluLookAt(0, -200, 200, 0, 0, 0, 0, 0, 1);
//绘制红色的“太阳”
glColor3f(1.0f, 0.0f, 0.0f);
glutSolidSphere(69.6, 100, 100);
//绘制蓝色的“地球”
glColor3f(0.0f, 0.0f, 1.0f);
glRotatef(day / 360.0*360.0, 0.0f, 0.0f, -1.0f);
//相对当前所在屏幕位置移动
glTranslatef(150, 0.0f, 0.0f);
glutSolidSphere(15.945, 100, 100);
//绘制黄色的“月亮”
glColor3f(1.0f, 1.0f, 0.0f);
glRotatef(day / 30.0*360.0 - day / 360.0*360.0, 0.0f, 0.0f, -1.0f);
glRotatef(day / 30.0*360.0, 0.0f, 0.0f, -1.0f);
glTranslatef(38, 0.0f, 0.0f);
glutSolidSphere(4.345, 100, 100);
//glFlush(); //这句加不加好像都行,因为用的是双缓冲区
glutSwapBuffers();
}
void myIdle(void)
{
Sleep(50);
++day;
if (day >= 360)
day = 0;
myDisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowPosition(200, 100);
glutInitWindowSize(600, 600);
glutCreateWindow("平移旋转");
glutDisplayFunc(&myDisplay);
//如果不存在其他尚未完成的,就执行这个函数(当没有窗口事件到达时,就执行这个回调函数
glutIdleFunc(&myIdle);
glutMainLoop();
return 0;
}