【计算机图形学】笔记

图形系统

image-20220518170931699

光栅图像

也称为图像、位图、点阵图、像素图,以像素数组的形式存贮在帧缓冲区中

基本图元

  • 设置点大小 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对象绘制过程中,实质上是进行的坐标系的变换,以节省大量的计算时间。

  • 变换物体:物体上所有点变换到新位置,坐标改变

    image-20220519115346305

  • 变换坐标系:物体上的点没有移动,在新的坐标系中描述(计算量小,速度快)

    image-20220519115531727

坐标系变换理解

  • 正向:image-20220519121924407
  • 逆向:image-20220519121837565

在坐标系M下的a向量表示为 Ma 其在坐标系N下表示为 b= N-1MaMa=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代表相同的角位移

  • 单位四元数

    image-20220622150418003

  • 共轭四元数:向量部分变负

    q*=[w v]*=[w -v]

  • 四元数的逆:共轭除以模的平方

    image-20220622150114195

    qq-1=[1,0]

  • 四元数乘法

    image-20220622145812616

    • 满足结合律,不满足交换律

    • 四元数乘的模等于模的乘积,单位四元数的乘仍然是单位四元数

      image-20220622150055802

    • 四元数乘积的逆等于各四元数逆反顺序相乘

      image-20220622150040033

      扩展3d点(x,y,z)到四元数空间为p=[0,(x,y,z)]

      设q为单位化四元数,n为旋转轴,θ为旋转角。则p绕n旋转θ公式为:

      image-20220622150643141

      若q为一般形式的四元数,可通过标准化转换求得旋转轴和旋转角度

      连续旋转:先转a,再转b,等于执行ba旋转

      image-20220622152104195

  • 新乘法

    image-20220622152016441

    在新四元数乘法定义下:先a旋转,再b旋转,等于执行一次ab旋转。乘法顺序与旋转顺序相同。

    image-20220622152043474

    image-20220622152213642

  • 四元数的差:一个方位到另一个方位的角位移

    image-20220622152602016

  • 四元数点乘:对于单位四元数a,b有-1<=a*b<=1,其点乘越大,则a、b所代表的角位移越相似

    image-20220622152707212

    θ为a、b之差d的夹角,则

    image-20220622152922378

  • 四元数对数

    记α为θ/2,定义:

    image-20220622153042707

  • 四元数指数

    image-20220622153158545

  • 四元数数乘:标量值直接乘以四元数中每个分量,满足交换律

    image-20220622153247625

  • 四元数的幂:表示角位移的t倍

    image-20220622154310060

四元数插值

Slerp插值

开始四元数q0和结束四元数q1,差值参数t,0≤t ≤1,slerp(q0,q1,t)返回q0到q1间的方位

image-20220622154907238

简化

image-20220622155729925

  • 四元数加法(实部实部相加,虚部虚部相加),要考虑两个四元数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_RGB0x0000指定 RGB 颜色模式的窗口
GLUT_RGBA0x0000指定 RGBA 颜色模式的窗口
GLUT_INDEX0x0001指定颜色索引模式的窗口
GLUT_SINGLE0x0000指定单缓存窗口
GLUT_DOUBLE0x0002指定双缓存窗口
GLUT_ACCUM0x0004窗口使用累加缓存
GLUT_ALPHA0x0008窗口的颜色分量包含 alpha 值
GLUT_DEPTH0x0010窗口使用深度缓存
GLUT_STENCIL0x0020窗口使用模板缓存
GLUT_MULTISAMPLE0x0080指定支持多样本功能的窗口
GLUT_STEREO0x0100指定立体窗口
GLUT_LUMINANCE0x0200窗口使用亮度颜色模型

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_TEST4864跟据函数glAlphaFunc的条件要求来决定图形透明的层度是否显示
GL_AUTO_NORMAL3456执行后,图形能把光反射到各个方向
GL_BLEND3042启用颜色混合。例如实现半透明效果
GL_CLIP_PLANE0 ~ GL_CLIP_PLANE512288 ~ 12283根据函数glClipPlane的条件要求 启用图形切割管道。这里指六种缓存管道
GL_COLOR_LOGIC_OP3058启用每一像素的色彩为位逻辑运算
GL_COLOR_MATERIAL2930执行后,图形(材料)将根据光线的照耀进行反射 反射要求由函数glColorMaterial进行设定
GL_CULL_FACE2884根据函数glCullFace要求启用隐藏图形材料的面
GL_DEPTH_TEST2929启用深度测试 根据坐标的远近自动隐藏被遮住的图形(材料)
GL_DITHER3024启用抖动
GL_FOG2912雾化效果 例如距离越远越模糊
GL_INDEX_LOGIC_OP3057逻辑操作
GL_LIGHT0 ~ GL_LIGHT716384 ~ 16391启用0号灯到7号灯(光源) 光源要求由函数glLight函数来完成
GL_LIGHTING2896启用灯源
GL_LINE_SMOOTH2848执行后,过虑线段的锯齿
GL_LINE_STIPPLE2852执行后,画虚线
GL_LOGIC_OP3057逻辑操作
GL_MAP1_COLOR_43472根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成RGBA曲线
GL_MAP1_INDEX3473根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成颜色索引曲线
GL_MAP1_NORMAL3474根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成法线
GL_MAP1_TEXTURE_COORD_13475根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标
GL_MAP1_TEXTURE_COORD_23476根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标
GL_MAP1_TEXTURE_COORD_33477根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标
GL_MAP1_TEXTURE_COORD_43478根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 生成文理坐标
GL_MAP1_VERTEX_33479根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 在三维空间里生成曲线
GL_MAP1_VERTEX_43480根据函数Map1对贝赛尔曲线的设置, 启用glEvalCoord1,glEvalMesh1,glEvalPoint1 在四维空间里生成法线
GL_MAP2_COLOR_43504根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成RGBA曲线
GL_MAP2_INDEX3505根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成颜色索引
GL_MAP2_NORMAL3506根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成法线
GL_MAP2_TEXTURE_COORD_13507根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标
GL_MAP2_TEXTURE_COORD_23508根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标
GL_MAP2_TEXTURE_COORD_33509根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标
GL_MAP2_TEXTURE_COORD_43510根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 生成纹理坐标
GL_MAP2_VERTEX_33511根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 在三维空间里生成曲线
GL_MAP2_VERTEX_43512根据函数Map2对贝赛尔曲线的设置, 启用glEvalCoord2,glEvalMesh2,glEvalPoint2 在三维空间里生成曲线
GL_NORMALIZE2977根据函数glNormal的设置条件,启用法向量
GL_POINT_SMOOTH2832执行后,过虑线点的锯齿
GL_POLYGON_OFFSET_FILL32823根据函数glPolygonOffset的设置,启用面的深度偏移
GL_POLYGON_OFFSET_LINE10754根据函数glPolygonOffset的设置,启用线的深度偏移
GL_POLYGON_OFFSET_POINT10753根据函数glPolygonOffset的设置,启用点的深度偏移
GL_POLYGON_SMOOTH2881过虑图形(多边形)的锯齿
GL_POLYGON_STIPPLE2882执行后,多边形为矢量画图
GL_SCISSOR_TEST3089根据函数glScissor设置,启用图形剪切
GL_STENCIL_TEST2960启用模板测试
GL_TEXTURE_1D3552启用一维文理
GL_TEXTURE_2D3553启用二维文理
GL_TEXTURE_GEN_Q3171根据函数glTexGen,启用纹理处理
GL_TEXTURE_GEN_R3170根据函数glTexGen,启用纹理处理
GL_TEXTURE_GEN_S3168根据函数glTexGen,启用纹理处理
GL_TEXTURE_GEN_T3169根据函数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是有符号数)

image-20220519165435701

glScalef(x,y,z)

image-20220519165740518

glRotatef(angle,a,b,c)

绕过原点与(a,b,c)的轴正方向旋转angle度

image-20220520150625381

image-20220519170552122

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中重新调用该函数以形成循环

Licensed under CC BY-NC-SA 4.0
Last updated on Jun 06, 2023 00:00 UTC
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy