0%

OpenGL绘图实例九之3D绘图基础

综述

在前面我们进行了 2D 图形的绘制,接下来,我们将步入 3D 图形的世界,绘制出一个 3D 机器人,好,废话不多说,让我们一起来迈入 3D 绘图之旅吧。

基本函数

那么在绘图之前呢,我们首先要介绍几个新的函数,弄懂了这几个函数我们才能方便地绘制出我们的 3D 机器人。 那么我们介绍一下gluPerspectivegluLookAt、glPushMatrix、glPopMatrix()函数

1.void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)

参数说明: fovy,视角的大小,如果设置为 0,相当闭上眼睛,什么也看不到,如果为 180,则可以看到几乎所有的内容。一般设置为 60 即可。 aspect,就是实际窗口的纵横比,即 x/y,一般都是要按照窗口比例来,否则看到的图形和实际图形就会不一样了。 zNear,表示近处的裁面。 zFar,表示远处的裁面。 gluPerspective 这个函数指定了观察的视景体在世界坐标系中的具体大小,一般而言,其中的参数 aspect 应该与窗口的宽高比大小相同。比如说,aspect=2.0 表示在观察者的角度中物体的宽度是高度的两倍,在视口中宽度也是高度的两倍,这样显示出的物体才不会被扭曲。 详细说明 03087bf40ad162d9f337731d11dfa9ec8b13cdd1

2.void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz)

该函数定义一个视图矩阵,并与当前矩阵相乘。

第一组 eyex, eyey,eyez 相机在世界坐标的位置

第二组 centerx,centery,centerz 相机镜头对准的物体在世界坐标的位置

第三组 upx,upy,upz 相机向上的方向在世界坐标中的方向

你把相机想象成为你自己的脑袋:

第一组数据就是脑袋的位置

第二组数据就是眼睛看的物体的位置

第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)

在这里,我们就涉及到一个十分重要的概念,坐标系。 在 3D 绘图中,坐标系是右手系,如果 x 轴指向我们的右侧,那么 y 则指向上侧,z 轴指向屏幕外。如下图所示。 20150606234046 理解了上述两个函数,下面我们来用一个小例子感受一下 运行如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <glut.h>
#include <stdlib.h>


void display(void) {
//清除缓冲区颜色
glClear(GL_COLOR_BUFFER_BIT);
//定义白色
glColor3f(1.0, 1.0, 1.0);
//圆点放坐标中心
glLoadIdentity();
//从哪个地方看
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glutWireTeapot(2);
//清除缓冲区刷新
glutSwapBuffers();
}

void reshape(int w, int h) {
//定义视口大小
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
//投影显示
glMatrixMode(GL_PROJECTION);
//坐标原点在屏幕中心
glLoadIdentity();
//操作模型视景
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
//初始化
glutInit(&argc, argv);
//设置显示模式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
//初始化窗口大小
glutInitWindowSize(500, 500);
//定义左上角窗口位置
glutInitWindowPosition(100, 100);
//创建窗口
glutCreateWindow(argv[0]);
//清除颜色缓冲区
glClearColor(0.0, 0.0, 0.0, 0.0);
//显示函数
glutDisplayFunc(display);
//窗口大小改变时的响应
glutReshapeFunc(reshape);
//循环
glutMainLoop();
return 0;
}

运行结果如下 QQ截图20150606234448 在这里,我们定义了

1
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

意思就是把我们的眼睛放到了(0,0,5)的位置,茶壶放到了原点,脑袋顶朝上,即正视茶壶。 如果我们改变了几个参数的值,例如

1
gluLookAt(0.0, 0.0, 5.0, 4.0, 1.0, 0.0, 0.0, 0.0, 1.0);

眼睛位置不变,茶壶位置变为(4,1,0),脑袋顶的方向朝屏幕外侧,那么看到的效果如下。 QQ截图20150606234708 大家可以通过更改这些参数的值来对视图进行变换。

3.glPushMatrix()、glPopMatrix()

这个方法在绘制 3D 图形时依然十分有用,因为我们需要绘制好多个图形,绘制多个不一样的图形必然要经过各种矩阵变换,所以,少不了的利用平移变换放缩的功能,所以为了保证每个图形不受影响,在绘制一个新图形前我们只要调用一下 glPushMatrix 函数,保存当前的变换矩阵,然后绘制完一个图形之后再调用 glPopMatrix 函数来恢复之前的变换矩阵就可以了。 比如,绘制球体

1
2
3
4
glPushMatrix();
glTranslated(x,y,z);
glutWireSphere(R,20,20);
glPopMatrix();

在两个函数中间我们可以进行任意的变换放缩等操作,然后绘制想要的图形即可。

绘图函数

接下来我们说一下一些常用的绘图函数,直接用类库函数来绘制即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void glutWireSphere(GLdouble radius, GLint slices, GLint stacks); 线框球
void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks); 实心球
void glutWireCube(GLdouble size); 线框立方体
void glutSolidCube(GLdouble size); 实心立方体
void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings); 线框圆环
void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings); 实心圆环
void glutWireIcosahedron(void); 线框20面体
void glutSolidIcosahedron(void); 实心20面体
void glutWireOctahedron(void); 线框8面体
void glutSolidOctahedron(void); 实心8面体
void glutWireTetrahedron(void); 线框4面体
void glutSolidTetrahedron(void); 实心4面体
void glutWireDodecahedron(GLdouble radius); 线框12面体
void glutSolidDodecahedron(GLdouble radius); 实心12面体
void glutWireCone(GLdouble radius, GLdouble height, GLint slices, GLint stacks); 线框圆锥体
void glutSolidCone(GLdouble radius, GLdouble height, GLint slices, GLint stacks); 实心圆锥体
void glutWireTeapot(GLdouble size); 线框茶壶
void glutSolidTeapot(GLdouble size); 实心茶壶

利用上面的绘图函数我们便可以方便地实现各种图形的绘制。

结语

那么本节就先告一段落,本节介绍了相关的绘图函数以及几个重要的函数,为接下来我们绘制机器人做下铺垫,希望小伙伴们可以好好理解。