图形系统
光栅图像
也称为图像、位图、点阵图、像素图,以像素数组的形式存贮在帧缓冲区中
基本图元
点
- 设置点大小 glPointSize(Glfloat size);
- 设置点绘制模式 glBegin(GL_POINTS); glEnd();
- 设置点位置 glVertex3f(Glfloat x, Glfloat y, Glfloat z);
- 设置点颜色 glColor3f(Glfloat r, Glfloat g, Glfloat b);
- 光滑(反走样) glEnable (GL_POINT_SMOOTH); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
直线
设置线的宽度 glLineWidth(Glfloat width)
设置直线绘制模式 glBegin(GL_LINES); 两两连线 glBegin(GL_LINE_STRIP);持续连线 glBegin(GL_LINE_LOOP);首尾也相连
点画线(虚线) glEnable(GL_LINE_STIPPLE); glLineStipple(GLint factor, GLushort pattern);
光滑(反走样)
glEnable (GL_LINE_SMOOTH); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
三角形
设置三角型绘制模式
glBegin(GL_TRIANGLES);
GL_TRIANGLE_STRIP; 三角带
GL_TRIANGLE_FAN; 三角扇
着色模式 glShadeModel(GL_FLAT); glShadeModel(GL_SMOOTH);
背面消除 glEnable(GL_CULL_FACE); glFrontFace(GL_CCW) GL_CW
多边形模式 glPolygonMode(GL_BACK,GL_LINE); GL_BACK/GL_FRONT/GL_FRONT_AND_BACK GL_LINE/GL_POINT/GL_FILL
坐标系
使用OpenGL方式定义坐标系:右手坐标系
世界坐标系
最大的坐标系,描述其他坐标系的参考框架
物体(模型)坐标系
与特定物体相关
随着物体运动而运动
惯性坐标系
物体坐标系到世界坐标系转换的中间阶段
位置与物体坐标系一致,方向与世界坐标系一致
物体坐标系转世界坐标系:以惯性坐标系为媒介,旋转至惯性坐标系后平移至世界坐标系
深度缓冲
- 显示模式设置为深度缓冲区 glutInitDisplayMode(GLUT_DEPTH);
- 设置深度缓冲区允许位 glEnable(GL_DEPTH_TEST);
- 每帧绘制前清除深度缓冲区 glClear(GL_DEPTH_BUFFER_BIT);
四种变换
模型变换和视点变换本质上是一致的,对一个的变换相当于对另一个反方向变换
模型视点变换:通过模型变换从局部坐标系转换为世界坐标系,再通过视点变换从世界坐标系转换为视口坐标系
控制模型
glTranslatef(mx,my,mz);
glRotatef(rx,1,0,0);
glRotatef(ry,0,1,0);
glRotatef(rz,0,0,1);
glScalef(sx,sy,sz);
控制视点
glRotatef(-rz,0,0,1); glRotatef(-ry,0,1,0); glRotatef(-rx,1,0,0); glTranslatef(-mx,-my,-mz);
控制
控制键盘
glutKeyboardFunc(&myKeyboardFunc);
矩阵
列向量只可以右乘矩阵(结果仍为列向量),用在OpenGL、多数图形学书籍中。
向量可由三个线性无关的基向量的线性组合表示
由基向量构成的矩阵就是坐标系
空间变换
两种变换等价,将物体变换一个量相当于将原始坐标系变换一个相反的量
在实际的3D对象绘制过程中,实质上是进行的坐标系的变换,以节省大量的计算时间。
变换物体:物体上所有点变换到新位置,坐标改变
变换坐标系:物体上的点没有移动,在新的坐标系中描述(计算量小,速度快)
坐标系变换理解
- 正向:
- 逆向:
在坐标系M下的a向量表示为 Ma 其在坐标系N下表示为 b= N-1Ma(Ma=Nb)
旋转
旋转的正方向:由右手定则判定,拇指向上,四指弯曲。拇指方向是坐标轴正方向,四指弯曲方向则为旋转正方向
方位
通过与相对已知方位(源方位)的旋转来表述,旋转的量称作角位移
初始方位:自旋转角度为0,方向为(0,0,-1)(z轴负向),此时欧拉角为(0,0,0)
欧拉角
角位移分解为绕三个相互垂直的轴的三个旋转组成的序列
- heading/yaw 偏航 h (y轴)
- pitch 俯仰/ 纵摇 p(x轴)
- bank/roll 倾侧/翻滚 b(z轴)
初始方位角为(0,0,-1),转动为0
取值范围限定 h,b在-180到180,p在-90到90
四元数
包括一个标量和一个3D向量,代表一角位移:绕n转θ角,q与-q代表相同的角位移
单位四元数
共轭四元数:向量部分变负
q*=[w v]*=[w -v]
四元数的逆:共轭除以模的平方
qq-1=[1,0]
四元数乘法
满足结合律,不满足交换律
四元数乘的模等于模的乘积,单位四元数的乘仍然是单位四元数
四元数乘积的逆等于各四元数逆反顺序相乘
扩展3d点(x,y,z)到四元数空间为p=[0,(x,y,z)]
设q为单位化四元数,n为旋转轴,θ为旋转角。则p绕n旋转θ公式为:
若q为一般形式的四元数,可通过标准化转换求得旋转轴和旋转角度
连续旋转:先转a,再转b,等于执行ba旋转
新乘法
在新四元数乘法定义下:先a旋转,再b旋转,等于执行一次ab旋转。乘法顺序与旋转顺序相同。
四元数的差:一个方位到另一个方位的角位移
四元数点乘:对于单位四元数a,b有-1<=a*b<=1,其点乘越大,则a、b所代表的角位移越相似
θ为a、b之差d的夹角,则
四元数对数
记α为θ/2,定义:
四元数指数
四元数数乘:标量值直接乘以四元数中每个分量,满足交换律
四元数的幂:表示角位移的t倍
四元数插值
Slerp插值
开始四元数q0和结束四元数q1,差值参数t,0≤t ≤1,slerp(q0,q1,t)返回q0到q1间的方位
简化
- 四元数加法(实部实部相加,虚部虚部相加),要考虑两个四元数w方向是否相同。如果相反则改为相减。
- k0+k1≠1,因此插值后的四元数模不为1,需要单位化后使用
Squad插值
实现多个方位角之间的平滑序列,不介绍
视点控制
glRotated(-m_hpb[2],0,0,1); //b 绕z轴转 glRotated(-m_hpb[1],1,0,0); //p 绕x轴转 glRotated(-m_hpb[0],0,1,0); //h 绕y轴转 glTranslated(-m_pos.x,-m_pos.y,-m_pos.z); 视点位置记录在m_pos,视点方位角在m_hpb
包围盒
AABB(axially aligned bounding box)
- 对变换后物体重新计算AABB
- 对AABB做和物体相同变换(不保证轴对齐,非AABB)
光照
- 启动光照 glEnable(GL_LIGHTING); glEnable(GL_LIGHT0);
- 创建光源 glLight{if}[v](GLenum light , GLenum pname, TYPE param) Pname: GL_AMBIENT 环境反射 GL_DIFFUSE 漫反射 GL_SPECULAR 镜面反射 GL_POSITION 当第w位为0时表示平行光源,为1表示点光源
纹理
特殊效果
OpenGL内部矩阵
GL_MODELVIEW(模型视图矩阵)
把空间点从模型坐标系最终变换到眼坐标系下,包括视图矩阵和模型矩阵的两个矩阵的乘积,在绘制对象的时候执行变换,把glBegin和glEnd之间的顶点乘以当前模型视图矩阵得到眼坐标系下的空间坐标。
GL_PROJECTION(投影矩阵)
把眼空间坐标系下的视锥体内点转变到矩形规范体(裁剪坐标系)内的点坐标。便于后续操作。转换后的坐标范围是(-1,-1,-1)~(1,1,1)。范围外点不在视锥体内,要被裁剪掉,包括透视投影或者平行投影两类。
裁剪坐标=投影矩阵*眼坐标 投影结果:x∈[-1,1] y∈[-1,1] z∈[-1,1] z转换到0~1区间后存入深度缓冲:z’=(z+1)*0.5
GL_TEXTURE(纹理矩阵)
OpenGL函数
glReadPixels
glutInitDisplayMode(unsigned int mode);
设置初始显示模式
值 | 对应宏定义 | 意义 |
---|---|---|
GLUT_RGB | 0x0000 | 指定 RGB 颜色模式的窗口 |
GLUT_RGBA | 0x0000 | 指定 RGBA 颜色模式的窗口 |
GLUT_INDEX | 0x0001 | 指定颜色索引模式的窗口 |
GLUT_SINGLE | 0x0000 | 指定单缓存窗口 |
GLUT_DOUBLE | 0x0002 | 指定双缓存窗口 |
GLUT_ACCUM | 0x0004 | 窗口使用累加缓存 |
GLUT_ALPHA | 0x0008 | 窗口的颜色分量包含 alpha 值 |
GLUT_DEPTH | 0x0010 | 窗口使用深度缓存 |
GLUT_STENCIL | 0x0020 | 窗口使用模板缓存 |
GLUT_MULTISAMPLE | 0x0080 | 指定支持多样本功能的窗口 |
GLUT_STEREO | 0x0100 | 指定立体窗口 |
GLUT_LUMINANCE | 0x0200 | 窗口使用亮度颜色模型 |
glClearColor(r,b,g,a);
背景颜色
glClear(GLbitfield mask);
GLbitfield:可以使用 | 运算符组合不同的缓冲标志位,表明需要清除的缓冲,例如glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)表示要清除颜色缓冲以及深度缓冲,可以使用以下标志位
GL_COLOR_BUFFER_BIT: 颜色缓冲
GL_DEPTH_BUFFER_BIT: 深度缓冲
GL_ACCUM_BUFFER_BIT: 累积缓冲
GL_STENCIL_BUFFER_BIT: 模板缓冲
也就是用glClearColor或者glClearDepth、glClearIndex、glClearStencil、glClearAccum等函数所指定的值来清除指定的缓冲区
glFlush()/glFinish()
强制刷新缓冲,保证绘图命令将被执行
glSwapBuffer()
glBegin();
glBegin表示一组用于定义一个或者多个图元的顶点的开始
GL_POINTS 单个顶点集
GL_LINES 多组双顶点线段,如果顶点数为奇数,最后一个顶点就会被忽略。
GL_LINE_STRIP 不闭合折线
GL_LINE_LOOP 闭合折线
GL_POLYGON 单个简单填充凸多边形
GL_TRIANGLES 多组独立填充三角形
GL_TRIANGLE_STRIP 线型连续填充三角形串
GL_TRIANGLE_FAN 扇形连续填充三角形串
GL_QUADS 多组独立填充四边形
GL_QUAD_STRIP 连续填充四边形串
glTranslatef()等此类几何转换接口在glBegin()和glEnd()之间是无效的。因此,如果想对模型的位置进行转换,要在调用glBegin()和glEnd()接口对之前行处理。
在glBegin()和glEnd()之间可调用的函数如下:
glVertex():设置顶点坐标
glColor():设置当前颜色
glIndex():设置当前颜色表
glNormal():设置法向坐标
glEvalCoord():产生坐标
glCallList()、glCallLists():执行显示列表
glTexCoord():设置纹理坐标
glEdgeFlag():控制边界绘制
glMaterial():设置材质
glEnd();
glEnd表示一组用于定义一个或者多个图元的顶点的结束
glEnable():
用于启用各种功能。功能由参数决定
类型 | 值 | 说明 |
---|---|---|
GL_ALPHA_TEST | 4864 | 跟据函数glAlphaFunc的条件要求来决定图形透明的层度是否显示 |
GL_AUTO_NORMAL | 3456 | 执行后,图形能把光反射到各个方向 |
GL_BLEND | 3042 | 启用颜色混合。例如实现半透明效果 |
GL_CLIP_PLANE0 ~ GL_CLIP_PLANE5 | 12288 ~ 12283 | 根据函数glClipPlane的条件要求 启用图形切割管道。这里指六种缓存管道 |
GL_COLOR_LOGIC_OP | 3058 | 启用每一像素的色彩为位逻辑运算 |
GL_COLOR_MATERIAL | 2930 | 执行后,图形(材料)将根据光线的照耀进行反射 反射要求由函数glColorMaterial进行设定 |
GL_CULL_FACE | 2884 | 根据函数glCullFace要求启用隐藏图形材料的面 |
GL_DEPTH_TEST | 2929 | 启用深度测试 根据坐标的远近自动隐藏被遮住的图形(材料) |
GL_DITHER | 3024 | 启用抖动 |
GL_FOG | 2912 | 雾化效果 例如距离越远越模糊 |
GL_INDEX_LOGIC_OP | 3057 | 逻辑操作 |
GL_LIGHT0 ~ GL_LIGHT7 | 16384 ~ 16391 | 启用0号灯到7号灯(光源) 光源要求由函数glLight函数来完成 |
GL_LIGHTING | 2896 | 启用灯源 |
GL_LINE_SMOOTH | 2848 | 执行后,过虑线段的锯齿 |
GL_LINE_STIPPLE | 2852 | 执行后,画虚线 |
GL_LOGIC_OP | 3057 | 逻辑操作 |
GL_MAP1_COLOR_4 | 3472 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成RGBA曲线 |
GL_MAP1_INDEX | 3473 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成颜色索引曲线 |
GL_MAP1_NORMAL | 3474 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成法线 |
GL_MAP1_TEXTURE_COORD_1 | 3475 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标 |
GL_MAP1_TEXTURE_COORD_2 | 3476 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标 |
GL_MAP1_TEXTURE_COORD_3 | 3477 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标 |
GL_MAP1_TEXTURE_COORD_4 | 3478 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标 |
GL_MAP1_VERTEX_3 | 3479 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 在三维空间里生成曲线 |
GL_MAP1_VERTEX_4 | 3480 | 根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 在四维空间里生成法线 |
GL_MAP2_COLOR_4 | 3504 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成RGBA曲线 |
GL_MAP2_INDEX | 3505 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成颜色索引 |
GL_MAP2_NORMAL | 3506 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成法线 |
GL_MAP2_TEXTURE_COORD_1 | 3507 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标 |
GL_MAP2_TEXTURE_COORD_2 | 3508 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标 |
GL_MAP2_TEXTURE_COORD_3 | 3509 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标 |
GL_MAP2_TEXTURE_COORD_4 | 3510 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标 |
GL_MAP2_VERTEX_3 | 3511 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 在三维空间里生成曲线 |
GL_MAP2_VERTEX_4 | 3512 | 根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 在三维空间里生成曲线 |
GL_NORMALIZE | 2977 | 根据函数glNormal的设置条件,启用法向量 |
GL_POINT_SMOOTH | 2832 | 执行后,过虑线点的锯齿 |
GL_POLYGON_OFFSET_FILL | 32823 | 根据函数glPolygonOffset的设置,启用面的深度偏移 |
GL_POLYGON_OFFSET_LINE | 10754 | 根据函数glPolygonOffset的设置,启用线的深度偏移 |
GL_POLYGON_OFFSET_POINT | 10753 | 根据函数glPolygonOffset的设置,启用点的深度偏移 |
GL_POLYGON_SMOOTH | 2881 | 过虑图形(多边形)的锯齿 |
GL_POLYGON_STIPPLE | 2882 | 执行后,多边形为矢量画图 |
GL_SCISSOR_TEST | 3089 | 根据函数glScissor设置,启用图形剪切 |
GL_STENCIL_TEST | 2960 | 启用模板测试 |
GL_TEXTURE_1D | 3552 | 启用一维文理 |
GL_TEXTURE_2D | 3553 | 启用二维文理 |
GL_TEXTURE_GEN_Q | 3171 | 根据函数glTexGen,启用纹理处理 |
GL_TEXTURE_GEN_R | 3170 | 根据函数glTexGen,启用纹理处理 |
GL_TEXTURE_GEN_S | 3168 | 根据函数glTexGen,启用纹理处理 |
GL_TEXTURE_GEN_T | 3169 | 根据函数glTexGen,启用纹理处理 |
glDisable()
用来关闭的。与glDisable()参数一致
glShadeModel()
参数mode可以是GL_SMOOTH(默认值)或GL_FLAT。采用恒定着色时(即GL_FLAT),使用图元中某个顶点的颜色来渲染整个图元。 在使用光滑着色时(即GL_SMOOTH),独立的处理图元中各个顶点的颜色。对于线段图元,线段上各点的颜色将根据两个顶点的颜色通过差值得到。对于多边形图元,多边形内部区域的颜色将根据所有顶点的颜色差值得到。
glFrontFace(GLenum mode)
作用是控制多边形的正面是如何决定的
GL_CCW 表示窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面。
GL_CW 表示顶点顺序为顺时针方向的表面为正面。
在默认情况下,mode是GL_CCW
glPolygonMode(GLenum face,GLenum mode)
face这个参数确定显示模式将适用于物体的哪些部分,控制多边形的正面和背面的绘图模式:
GL_FRONT表示显示模式将适用于物体的前向面(也就是物体能看到的面)
GL_BACK表示显示模式将适用于物体的后向面(也就是物体上不能看到的面)
GL_FRONT_AND_BACK表示显示模式将适用于物体的所有面
mode这个参数确定选中的物体的面以何种方式显示(显示模式):
GL_POINT表示显示顶点,多边形用点显示
GL_LINE表示显示线段,多边形用轮廓显示
GL_FILL表示显示面,多边形采用填充形式
glTranslatef(x,y,z)
沿X轴正方向平移x个单位(x是有符号数)
沿Y轴正方向平移y个单位(y是有符号数)
沿Z轴正方向平移z个单位(z是有符号数)
glScalef(x,y,z)
glRotatef(angle,a,b,c)
绕过原点与(a,b,c)的轴正方向旋转angle度
glLoadIdentity()
重置当前指定的矩阵为单位矩阵
glViewport(GLint x,GLint y,GLsizei width, GLsizei height);
左下角坐标,宽,高
glClipPlane(GLenum plane,Const GLdouble *equation);
定义一个裁剪平面,quation参数指向平面方程Ax + By + Cz + D = 0的4个系数。
gluUnProject()
int WINAPI gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz );
(winx,winy,winz)为要映射的窗口坐标
(objx,objy,objz)为计算的 x
modelview 矩阵从 glGetDoublev 调用
projMatrix投影矩阵从 glGetDoublev 调用
视区从 glGetIntegerv 调用
gluLookAt()
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 相机向上的方向在世界坐标中的方向
你把相机想象成为你自己的脑袋:
第一组数据就是脑袋的位置
第二组数据就是眼睛看的物体的位置
第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)
gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar );
fovy 上平面与下平面的夹角° aspect 屏幕的宽高比 zNear 近视点距离 zFar 远视点距离
void glOrtho( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar );
正交投影
glPushMatrix()
将当前矩阵保存入堆栈顶(保存当前矩阵)
glPopMatrix()
当经过一系列的变换后,栈顶矩阵被修改,此时调用glPopMatrix()时,栈顶矩阵被弹出,且又会恢复为原来的状态。glPushMatrix()和glPopMatrix()的配对使用可以消除上一次的变换对本次变换的影响。使本次变换是以世界坐标系的原点为参考点进行。
glMatrixMode()
mode 指定哪一个矩阵堆栈是下一个矩阵操作的目标,可选值:
- GL_MODELVIEW,对模型视图矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,输出自己的物体图形了。
- GL_PROJECTION,对投影矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,为我们的场景增加透视。
- GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,为我们的图形增加纹理贴图。
glLoadMatrixf(M)
replace the current matrix with an arbitrary matrix M
glMultMatrixf(M)
将当前矩阵乘以任意矩阵
glKeybordFunc(unsigned char key,int x,int y)
键盘回调函数
glutTimerFunc(unsigned int millis, void (*func)(int value), int value)
调用毫秒数,回调Timer,Timer的标识值
其真实意义是在millis毫秒后回调Timer,因此应在回调Timer中重新调用该函数以形成循环