目录
- 第一章 计算机图形学概论
- 第二章 图形变换
- 第三章 图形建模
-
- 绘制二维几何体
- 绘制奥运五环
- 绘制贝塞尔曲线
运行环境:
系统:
m
a
c
O
S
B
i
g
S
u
r
11.0.1
macOS\ Big\ Sur \ 11.0.1
macOS Big Sur 11.0.1
IDE:
X
c
o
d
e
V
e
r
s
i
o
n
12.2
(
12
B
45
b
)
Xcode\ Version\ 12.2\ (12B45b)
Xcode Version 12.2 (12B45b)
采用的OpenGL第三方库:
G
L
U
T
GLUT
GLUT
第一章 计算机图形学概论
调用OpenGL提供的茶壶、圆柱、圆锥等基本几何体的接口函数,通过直接调用接口函数简化程序,从而达到测试链接的目的。
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #ifdef __APPLE__ /* Defined before OpenGL and GLUT includes to avoid deprecation messages */ #define GL_SILENCE_DEPRECATION #include <OpenGL/gl.h> #include <GLUT/glut.h> #else #include <GL/gl.h> #include <GL/glut.h> #include <GL/glaux.h> #endif using namespace std; void init(){<!-- --> glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0); } void display(){<!-- --> glClear(GL_COLOR_BUFFER_BIT); //清楚屏幕所有内容 // glutWireTeapot(0.8); // glutSolidCube(1); gluLookAt(1.0,1.0,0.5,0.5,0.0,0.0,0.0,1.0,0.0); // //确定了一个可用于为摄像机定位和定向的矩阵,涉及的参数包括摄像机的位置(视点eye),被观察点(点at)以及所期望的up方向。 glutWireCube(1); // gluSphere(<#GLUquadric *quad#>, <#GLdouble radius#>, <#GLint slices#>, <#GLint stacks#>); // gluCylinder(<#GLUquadric *quad#>, <#GLdouble base#>, <#GLdouble top#>, <#GLdouble height#>, <#GLint slices#>, <#GLint stacks#>); glFlush(); } void myReshape(GLsizei w, GLsizei h){<!-- --> //重置窗口大小 glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); //选择投影矩阵 glLoadIdentity(); //重置投影矩阵 if (w <= h) {<!-- --> //需要根据画的对象的大小不同比例来修改参数,为了将实际坐标转化成-1到1之间的值。 ? glOrtho(-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, 1.50*(GLfloat)h/(GLfloat)w, -10.0, 10.0); } else {<!-- --> ? glOrtho(-1.5*(GLfloat)h/(GLfloat)w, 1.50*(GLfloat)h/(GLfloat)w, -1.5, 1.5, -10.0, 10.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char ** argv) {<!-- --> glutInit(&argc, argv); // single是单焕存 glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500, 500); glutInitWindowPosition(0, 0); glutCreateWindow("zhongguo"); init(); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutMainLoop(); return 0; } |
运行结果:
正方体:
茶壶:
第二章 图形变换
采用OpenGL变换技术实现了从三维空间到二维计算机屏幕图形的转换。
下面C++代码为三角形变换:
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 | // 没有写出的函数 则和第一章对应的函数相同 void myinit (void) {<!-- --> glShadeModel (GL_FLAT); } void drawTriangle(){<!-- --> // glBegin(GL_TRIANGLES); //实心填充 glBegin(GL_LINE_LOOP); //只画线 glVertex2f(0.0, 1.0); //范围在-1到1,线条画了,但在屏幕外面 glVertex2f(1.0, -1.0); glVertex2f(-1.0, -1.0); glEnd(); } void CALLBACK display(){<!-- --> glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glColor3f(1.0, 0.0, 0.0); drawTriangle(); glLoadIdentity(); glTranslatef(-0.5, 0.0, 0.0); glColor3f(0.0, 1.0, 0.0); drawTriangle(); glLoadIdentity(); glScalef(1.5, 0.5, 1.0); glColor3f(0.0, 0.0, 1.0); drawTriangle(); glLoadIdentity(); glRotatef(90.0, 0.0, 0.0, 1.0); glColor3f(1.0, 0.0, 1.0); drawTriangle(); glLoadIdentity(); glScalef(1.0, -0.5, 1.0); glColor3f(1.0, 1.0, 0.0); drawTriangle(); glFlush(); } |
第三章 图形建模
绘制二维几何体
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | // 没有写出的函数 则和第一章对应的函数相同 // 如果没有显示图形可能是坐标没有归一化到-1和1范围内,可以调整reshape函数的参数。 void CALLBACK display(){<!-- --> glColor3f(1.0, 1.0, 0.0); draw_my_obj(); glFlush(); } void CALLBACK draw_my_obj(){<!-- --> // 画点 glBegin(GL_POINTS); glColor3f(1.0,1.0,1.0); glVertex2f(-1.0,15.0); glColor3f(1.0,1.0,0.0); glVertex2f(1.0,15.0); glColor3f(0.0,1.0,1.0); glVertex2f(3.0,15.0); glEnd(); // 画不闭合折线 glBegin(GL_LINE_STRIP); glColor3f(1.0,0.0,0.0); glVertex2f(-3.0,9.0); glVertex2f(2.0,6.0); glVertex2f(3.0,9.0); glVertex2f(-2,6.0); glVertex2f(-3.0,9.0); glEnd(); // 画闭合折线 glBegin(GL_LINE_LOOP); glColor3f(0.0,0.0,1.0); glVertex2f(7.0,7.0); glVertex2f(9.0,9.0); glVertex2f(10.0,8.0); glVertex2f(11.0,9.0); glVertex2f(13.0,7.0); glVertex2f(11.0,5.0); glVertex2f(10.0,6.0); glVertex2f(9.0,5.0); glEnd(); // 画填充多边形 glBegin(GL_POLYGON); glColor3f(1.0,1.0,0.2); glVertex2f(-10.0,4.0); glVertex2f(-8.0,4.0); glVertex2f(-6.0,1.0); glVertex2f(-8.0,-2.0); glVertex2f(-10.0,-2.0); glVertex2f(-12.0,1.0); glEnd(); // 画线型连续填充三角形串 glBegin(GL_TRIANGLE_STRIP); glVertex2f(-1.0,-8.0); glVertex2f(-2.5,-5.0); glColor3f(0.8,0.8,0.0); glVertex2f(1.0,-7.0); glColor3f(0.0,0.8,0.8); glVertex2f(2.0,-4.0); glColor3f(0.8,0.0,0.8); glVertex2f(4.0,-6.0); glEnd(); // 画扇形连续填充三角形串 glBegin(GL_TRIANGLE_FAN); glVertex2f(8.0,-6.0); glVertex2f(10.0,-3.0); glColor3f(0.8,0.2,0.5); glVertex2f(12.5,-4.5); glColor3f(0.2,0.5,0.8); glVertex2f(13.0,-7.5); glColor3f(0.8,0.5,0.2); glVertex2f(10.5,-9.0); glEnd(); } |
绘制奥运五环
采用双缓冲方式,避免屏幕的闪烁。双缓冲的使用:
-
在调用 glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);。这里将我们惯用的GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用 双缓冲而非单缓冲。
-
调用 glutDisplayFunc(display)注册 回调函数时, 在回调函数中所有绘制操作完成后调用glutSwapBuffers()交换两个缓冲区指针。
-
调用 glutIdleFunc注册一个空闲时绘制操作函数, 注册的这个函数再调用display函数。
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | #ifdef __APPLE__ /* Defined before OpenGL and GLUT includes to avoid deprecation messages */ #define GL_SILENCE_DEPRECATION #include <OpenGL/gl.h> #include <GLUT/glut.h> #else #include <GL/gl.h> #include <GL/glut.h> #include <GL/glaux.h> #endif using namespace std; GLfloat z = -5.0f; // Depth Into The Screen GLUquadricObj *quadric = gluNewQuadric(); //二次几何体定义变量 int myinit(void) {<!-- --> glEnable(GL_TEXTURE_2D); // Enable Texture Mapping glShadeModel(GL_SMOOTH); glClearColor (0.0, 0.0, 0.0, 0.0); // 启用深度测试,格局坐标的远近自动隐藏被遮住的图形 glEnable(GL_DEPTH_TEST); // 指定深度缓冲比较值,如果输入的深度值小于参考值,则配合上面一条语句使用 glDepthFunc(GL_LESS); glClearDepth(1.0f); // Depth Buffer Setup glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations return 1; } //圆环函数 void DrawQuadric(float x, float y, float z) {<!-- --> glPushMatrix(); glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glPopMatrix(); } void myReshape(GLsizei w, GLsizei h){<!-- --> //重置窗口大小 glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0, 30.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -3.6); } // 显示函数,采用堆栈的方式 void display(){<!-- --> glClearColor(1,1,1,0); // set background color as white // 清楚颜色缓冲区和深度缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // 设置单位矩阵 glTranslatef(0.0f,0.0f,z); glLoadIdentity(); glRotatef(1,1.0f,0.0f,0.0f); glPushMatrix(); // 绘制蓝色圆环 glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glColor4f(0,0,1,0.7); glTranslatef(-2.4f,1.0f,z); // 圆盘绘制函数: 二次几何体、圆盘内径、圆盘外径、沿z轴细分数目、圆盘横截面上的细分数目 gluDisk(quadric,1.0f,1.2,32,32); glPopMatrix(); glPushMatrix(); // 绘制黄色圆环 glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glColor4f(1,1,0,0.7); glTranslatef(-1.2f,0.0f,z); gluDisk(quadric,1.0f,1.2,32,32); glPopMatrix(); glPushMatrix(); //绘制黑色圆环 glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glColor4f(0,0,0,0.7); glTranslatef(0.1f,1.0f,z); gluDisk(quadric,1.0f,1.2,32,32); glPopMatrix(); glPushMatrix(); //绘制绿色圆环 glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glColor4f(0,1,0,0.7); glTranslatef(1.4f,0.0f,z); gluDisk(quadric,1.0f,1.2,32,32); glPopMatrix(); glPushMatrix(); //绘制红色圆环 glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glColor4f(1,0,0,0.7); glTranslatef(2.6f,1.0f,z); gluDisk(quadric,1.0f,1.2,32,32); glPopMatrix(); glFlush(); glutSwapBuffers(); // 交换前后缓冲,实现双缓冲 } int main(int argc, char ** argv){<!-- --> glutInit(&argc, argv); // double 用双缓冲 glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA); glutInitWindowSize(500, 300); glutInitWindowPosition(0, 0); glutCreateWindow("五环"); myinit(); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutMainLoop(); return 0; } |
运行结果:
绘制贝塞尔曲线
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #ifdef __APPLE__ /* Defined before OpenGL and GLUT includes to avoid deprecation messages */ #define GL_SILENCE_DEPRECATION #include <OpenGL/gl.h> #include <GLUT/glut.h> #else #include <GL/gl.h> #include <GL/glut.h> #include <GL/glaux.h> #endif using namespace std; // 定义顶点 4*3 分别表示四个贝塞尔控制点的三维坐标 GLfloat ctrlpoints[4][3] = {<!-- --> {<!-- --> -5.0, -0.0, 0.0}, {<!-- --> -3.0, 3.0, 0.0}, {<!-- --> 3.0, 3.0, 0.0 }, {<!-- --> 5.0, 0.0, 0.0 } }; // 初始化函数 void myinit(void) {<!-- --> // 设置屏幕背景色为黑色 glClearColor(0.0, 0.0, 0.0, 1.0); // glMap1f(<#GLenum target#>, <#GLfloat u1#>, <#GLfloat u2#>, <#GLint stride#>, <#GLint order#>, <#const GLfloat *points#>) // target:指定控制顶点的意义,并确定了points应该提供多少值 // u1和u2参数表示变量u的变化范围 // stride表示每个存储块之间单精度或双精度浮点数的数量 // order参数的值就是控制点的数量 // points参数海子乡第一个控制点的第一个坐标 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); glEnable(GL_MAP1_VERTEX_3); // 启用求值器 } void CALLBACK display(void) {<!-- --> glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINE_STRIP); // 采用不闭合折线绘制方式 // 分30个小段绘制,分段越细则绘制的贝塞尔曲线越精确,但是程序所消耗的时间也会相应加长 for (int i = 0; i <= 30; i++) {<!-- --> glEvalCoord1f((GLfloat) i/30.0); } glEnd(); /* 显示控制点 */ glPointSize(5.0); glColor3f(1.0, 1.0, 0.0); glBegin(GL_POINTS); for (int i = 0; i < 4; i++){<!-- --> glVertex3fv(&ctrlpoints[i][0]); //使用数组方式传递参数 } glEnd(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) {<!-- --> glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) {<!-- --> glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); } else {<!-- --> glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char ** argv){<!-- --> glutInit(&argc, argv); // double 用双缓冲 glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA); glutInitWindowSize(500, 300); glutInitWindowPosition(0, 0); glutCreateWindow("Bezier Curves"); myinit(); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutMainLoop(); return 0; } |
大部分代码来源于清华大学出版社《OpenGl图形编程项目实战》一书配套源码(可以到官网下载),经过修改可以在
M
a
c
O
S
MacOS
MacOS上运行,且抛弃了原来代码使用的已经deprecated的
G
L
/
g
l
a
u
x
.
h
GL/glaux.h
GL/glaux.h库,直接使用
G
L
U
T
GLUT
GLUT库。