OpenGL基础汇总

OpenGL(应用程序接口 即API)——用于访问图形硬件的可编程特性

1. 各种矩阵:

世界矩阵(World Matrix):世界矩阵确定一个统一的世界坐标,用于组织独立的物体形成一个完整的场景;

视图矩阵(View Matrix):摄像机/观察者的位置等信息,将所有世界坐标转换为观察坐标 

投影矩阵(Projection Matirx):投影矩阵就是3维物体的平面影射.把三维场景在一个二维的平面上显示。裁剪坐标,转换到屏幕上

模型矩阵(Model Matrix):主要针对模型的平移、旋转、缩放等功能,将模型由局部空间转换到世界空间

纹理矩阵:对生成的纹理坐标进行坐标变换。使用纹理坐标变换可以对纹理坐标进行诸如平移、旋转和缩放等三维变换。可以通过一个简单的平移矩阵对纹理坐标进行变换,从而使物体表面上的纹理不断变换位置,产生动画效果。纹理坐标自动生成在三维图形程序中最广泛的应用是环境映射。

2. OpenGL常用的坐标系:(https://learnopengl-n.readthedocs.io/zh/latest/01%20Getting%20started/08%20Coordinate%20Systems/

局部空间(物体空间):指对象所在的坐标空间

世界空间:相对于世界的坐标。物体变换到的最终空间就是世界坐标系

观察空间(摄像机空间/视觉空间):经常被人们称之为OpenGL的摄像机,就是将对象的世界空间的坐标转换为用户视野前面的坐标。因此观察空间就是从摄像机角度观察到的空间。

裁剪空间(视觉空间):在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个给定的范围内,且任何在这个范围之外的点都应该被裁剪掉。被裁剪掉的坐标就被忽略了,所以剩下的坐标就将变为屏幕上可见的片段。

屏幕空间:一般由glViewPort设置。

3. OpenGL可编程管线

通过shader语言,可以在GPU上进行计算,释放CPU

shader可以理解为一些为图形处理单元(GPU)编译的小程序

4.OpenGL的渲染流程(下图OpenGL4.3的渲染流水线)

(详解https://blog.csdn.net/candycat1992/article/details/39675513

 

 

 

 

 

 

首先,我们以数组的形式传递3个3D坐标作为图形渲染管线的输入,用来表示一个三角形,这个数组叫做顶点数据(Vertex Data);顶点数据是一系列顶点的集合。一个顶点(Vertex)是一个3D坐标的数据的集合。而顶点数据是用顶点属性(Vertex Attribute)表示的,它可以包含任何我们想用的数据,比如顶点的坐标,颜色,法线,纹理坐标等。

1,顶点着色器

它把一个单独的顶点及其属性作为输入。顶点着色器主要的功能是进行位置坐标变化。

2,图元装配阶段

将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并所有的点装配成指定图元的形状;本节例子中是一个三角形。

3,几何着色器

图元装配阶段的输出会传递给几何着色器(Geometry Shader)。几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。例子中,它生成了另一个三角形。

4,光栅化阶段

几何着色器的输出会被传入光栅化阶段(Rasterization Stage),这里它会把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。

5,片段着色器

片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。

6,测试与混合

在所有对应颜色值确定以后,最终的对象将会被传到最后一个阶段,我们叫做Alpha测试和混合(Blending)阶段。这个阶段检测片段的对应的深度(和模板(Stencil))值(后面会讲),用它们来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。这个阶段也会检查alpha值(alpha值定义了一个物体的透明度)并对物体进行混合(Blend)。所以,即使在片段着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同。

 

5. shader的使用过程

  1、顶点着色程序的源代码和片段作色程序的源代码要分别保存到一个字符数组里面;

  2、创建着色器对象 - glCreateshader();

  3、把源码关联到每个着色器对象 - glShaderSource();

  4、编译着色器 - glCompileShader();

  5、创建(着色)程序对象 - 使用glCreaterProgram();

  6、关联着色器到程序对象 - glAttachShader();

  7、链接程序 - glLinkProgram();

  8、激活着色器程序 - glUseProgram() 将OpenGL渲染管道切换到着色器模式;

  9、删除着色器和程序

  然后,才可以提交顶点

6. GLSL如何传递数据

Uniform变量:外部程序传递给shader的变量,在shader程序内部,uniform变量就像是C++的const,不能被shader程序修改。

attribute变量:只能在vertex shader中声明和使用的变量。一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。在application中,一般用函数glBindAttribLocation()来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer()为每个attribute变量赋值。

varying变量:varying变量是vertex和fragment shader之间做数据传递用的。一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值。因此varying变量在vertex和fragment shader二者之间的声明必须是一致的。application不能使用此变量。

7. (https://blog.csdn.net/dcrmg/article/details/53556664

顶点缓冲对象VBO:是在显卡存储空间中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法向量,顶点颜色数据等。渲染时直接从VBO取数据,不需要从CPU传输数据,效率高。可以开辟多个VBO,每个VBO在opengl中有其唯一的ID,这个ID对应具体的VBO的显存地址,通过ID对特定的VBO内的数据进行存取操作。

创建过程:glGenBuffers(开辟显存空间并分配ID)->glBindBuffer(数据类型绑定)->glBufferData(数据传输到显存缓冲区)->glVertexAttribPointer(通知opengl如何解释这些顶点数据)

VBO保存了一个模型的顶点属性信息,每次绘制前都要绑定顶点的所有信息,当数据量很大时重复这个动作很麻烦。VAO可以把所有配置存储在一个对象中,绘制模型时绑定这个VAO对象即可。

顶点数组对象VAO:保存了所有顶点数据属性的状态集合,存储了顶点数据的格式以及顶点数据所需的VBO对象的引用。VAO本身并没有存储顶点的相关属性数据,这些信息是存储在VBO中的,VAO相当于是对很多个VBO的引用,把一些VBO组合在一起进行对象的统一管理。

创建过程:glGenVertexArrays(开辟)->glBindVertexArray(绑定)->glDrawArrays(绘制)

VBO和VAO创建关联过程:

/*
1. Generate Vertex Array Object
2. Bind Vertex Array Object
 
3. Generate Vertex Buffer Object
4. Bind Vertex Buffer Object
*/

glGenVertexArrays(1, &vaoID[0]); // Create our Vertex Array Object  
glBindVertexArray(vaoID[0]); // Bind our Vertex Array Object so we can use it  
  
glGenBuffers(1, vboID); // Generate our Vertex Buffer Object  
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // Bind our Vertex Buffer Object  
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW  
  
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Set up our vertex attributes pointer  
  
glEnableVertexAttribArray(0); // Disable our Vertex Array Object  
glBindVertexArray(0); // Disable our Vertex Buffer Object  

delete [] vertices; // Delete our vertices from memory

索引缓冲对象EBO:相当于opengl中的顶点数组的概念,是为了解决同一个顶点多次重复调用的问题,可以减少内存浪费,提高执行效率。当需要使用重复顶点时,通过顶点的位置索引来调用顶点,而不是对重复的顶点信息重复记录,重复调用。EBO中存储的内容就是顶点为位置的索引indices,EBO跟VBO类似,也是显存中的一块内存缓冲器,只不过EBO保存的是顶点的索引。

创建过程:glGenBuffers(开辟)->glBindBuffer(绑定类型)->glBufferData(输入数据)->glDrawElements(绘制)

8. 顶点法线和面法线的作用

 面法线,垂直于平面,位于中央,经常用于flat着色。

点的法线是在使用Phone或Gouraud模型时计算光照使用。如果一个面上的所有法线都一样,他们的光照也就一样,就会产生 flatness 效果;而如果把每个顶点的法向设置不同,则更平滑。

9.CPU与GPU之间的调度

 OpenGL主程序由CPU调度运行,图像处理部分通过GLSL交由GPU执行。

CPU与GPU之间的数据传递分为三个步骤:

一、首先利用 OpenGL函数生成一个ID;二、根据需要对该ID号码进行内存类型的绑定;

经过以上步骤,GPU中用于接收系统内存中数据的标识符就准备好了。三、对这部分内存进行初始化,初始化的内容来自于系统内存中,这一部分功能利用glBufferData函数完成。

数据提交到GPU专用的内存中后,需要根据应用场景对这些数据进行适当的分配。比如,哪些数据当作顶点、当作颜色、用于控制光照。

 

10.OpenGL中的几种缓冲(https://blog.csdn.net/silangquan/article/details/17493167

帧缓冲:下面几种缓冲的集合,通过帧缓冲将场景渲染到一个不同的帧缓冲中,存放显示用的数据。像素数据必须通过一系列测试才能写进帧缓存。video controller负责将帧缓冲输出到显示器上。

颜色缓冲:存储所有片段的颜色,即视觉输出的效果

深度缓冲:是在三维图形中处理深度坐标的过程,是可见性问题的一个解决方法。根据缓冲的Z值,确定哪些面片被遮挡。由GLFW自动生成。

模板缓冲:与深度缓冲类似,模板缓冲可以为屏幕上的每个像素点保存一个无符号整数值。渲染过程中,通过比较模板值和预设值,决定是否更新相应的像素点的颜色值,即决定是否丢弃片段。

数据在OpenGL中的处理顺序:顶点着色器->片段着色器->模板测试->深度测试

11.mipmap

多级渐远纹理,目前应用最广泛的纹理映射技术之一。就是实现“实物近大远小,近处清晰远处模糊”的效果。简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。

背后的理念:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体距离的那个。

12. 光照模型的组成,各成分与什么有关

环境光:是由光源发出经环境多次散射而无法确定其入射方向的光,即似乎来自所有方向。其特征是入射方向和出射方向均为任意方向。

漫反射:来自特定方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去,效果为无论视点在哪里它都一样亮,其特征是入射方向唯一、出射方向为任意方向。与法线与入射光线的方向有关。

高光/镜面反射:来自特定方向并沿另一方向反射出去,一个平行激光束在高质量的镜面上产生100%的镜面反射,其特征是入射方向和出射方向均唯一。与反射方向和视线方向(或者是法线与h)有关。

光源:点光、定向光、手电筒(聚光灯)

13.OpenGL为什么不提供窗口操作(没有读取三维模型、图片的接口)

跨平台的特点造成的。因为它可以不依赖硬件和系统,因此就不会包含执行窗口任务的函数,或者处理用户输入等。这些函数是由我们使用的应用或系统来提供。

14. 三维数据如何在二维屏幕上显示

通过投影将三维坐标转换为二维坐标:

1. 透视投影:为了获得接近真实的三维物体效果而在二维平面上绘制、渲染的方法。类似于现实中人对事物的认识(近大远小,远处模糊近期清晰)。

2. 正投影:正射投影矩阵定义了一个类似立方体的平截头箱,它定义了一个裁剪空间,在这空间之外的顶点都会被裁剪掉。

主要是通过图形渲染管线管理的,被划分为两个过程:

1.把3D坐标转换为2D坐标

2.把2D坐标转换为实际有颜色的像素

15. GL_LINES、GL_LINE_STRIP 和 GL_LINE_LOOP的区别

GL_LINES:可以连接每一对相邻点而得到一组直线。如果最后一个端点处于奇数位置,则该点会被忽略。

GL_LINE_STRIP:会将传入的点依次连接直到最后一个端点。

GL_LINE_LOOP:在GL_LINE_STRIP的基础上又进行了首尾相连。

16. GL_TRIANGLES、GL_TRIANGLE_STRIP 和 GL_TRIANGLE_FAN的区别

GL_TRIANGLES:会将矩阵中每三个点取出绘制一个三角形,最后一组不足三个则自动忽略;

GL_TRIANGLE_STRIP:绘制时满足以下规则:第n(奇数,从1到k)个三角形将会连接n,n+1,n+2三个顶点,对于第n(偶数)个三角形将会连接n+1,n,n+2三个顶点。所以总共会绘制k-2个三角形。

GL_TRIANGLE_FAN:绘制时满足以下规则:第n(从1到k)个三角形将会连接1,n+1,n+2三个顶点。总共会绘制k-2个三角形。

 17. 片段和像素的区别

  1. 片段是渲染一个像素需要的全部信息,所有片段经过测试与混合后渲染成像素。

  2. 片段是三维定点光栅化后的数据集合, 还没经过深度测试,而像素是片段经过深度测试、模板测试、alpha 混合之后的结果。

  3. 片段的个数远远多于像素, 因为有的片段会在测试和混合阶段被丢弃, 无法被渲染成像素。

18. 齐次坐标系的理解(https://blog.csdn.net/business122/article/details/51916858

 

 

 

 

 参考:

https://blog.csdn.net/u014800094/article/details/53024646

https://blog.csdn.net/candycat1992/article/details/39675513

 https://blog.csdn.net/u010607947/article/details/70791947

 https://www.mfsun.com/mip/thread-66779-1-1.html

https://blog.csdn.net/zhaotianyu950323/article/details/79955805

posted @ 2019-05-13 11:03  Not-Bad  阅读(771)  评论(0编辑  收藏  举报