OpenGL学习笔记(LearnOpenGL)-第二部分 绘制三角形

基础知识

顶点数组对象:Vertex Array Object,VBO

顶点缓冲对象:Vertx Buffer Object,VBO

索引缓冲对象:Element Buffer Object,EBO/Index Buffer Object,IBO

OpenGL将3D空间中的坐标转换为适应屏幕的2D像素,处理过程由OpenGL的图形渲染管线管理。(该部分内容上一节笔记中有涉及)管线总结为:顶点数据(Vertices) > 顶点着色器(Vertex Shader) > 图元装配(Assembly) > 几何着色器(Geometry Shader) > 光栅化(Rasterization) > 片断着色器(Fragment Shader) > 逐片断处理(Per-Fragment Operations) > 帧缓冲(FrameBuffer)。再经过双缓冲的交换(SwapBuffer),渲染内容就显示到了屏幕上。

下面引用一段来自:细说图形学渲染管线 - 知乎的内容。

顶点数据:顶点数据用来为后面的顶点着色器等阶段提供处理的数据。是渲染管线的数据主要来源。送入到渲染管线的数据包括顶点坐标、纹理坐标、顶点法线和顶点颜色等顶点属性。为了让OpenGL明白顶点数据构成的是什么图元,我们需要在绘制指令中传递相对应的图元信息。常见的图元包括:点(GL_POINTS)、线(GL_LINES)、线条(GL_LINE_STRIP)、三角面(GL_TRIANGLES)

顶点着色器:顶点着色器主要功能是进行坐标变换。将输入的局部坐标变换到世界坐标、观察坐标和裁剪坐标。虽然我们也会在顶点着色器进行光照计算(称作高洛德着色),然后经过光栅化插值得到各个片段的颜色,但由于这种方法得到的光照比较不自然,所以一般在片段着色器进行光照计算。关于坐标变换以及着色方案的细节,我们会在后面详细介绍。

曲面细分:曲面细分是利用镶嵌化处理技术对三角面进行细分,以此来增加物体表面的三角面的数量,是渲染管线一个可选的阶段。它由外壳着色器(Hull Shader)、镶嵌器(Tessellator)和域着色器(Domain Shader)构成,其中外壳着色器和域着色器是可编程的,而镶嵌器是有硬件管理的。我们可以借助曲面细分的技术实现细节层次(Level-of-Detail)的机制,使得离摄像机越近的物体具有更加丰富的细节,而远离摄像机的物体具有较少的细节。

曲面细分实现三角面的划分


几何着色器:几何着色器也是渲染管线一个可选的阶段。我们知道,顶点着色器的输入是单个顶点(以及属性), 输出的是经过变换后的顶点。与顶点着色器不同,几何着色器的输入是完整的图元(比如,点),输出可以是一个或多个其他的图元(比如,三角面),或者不输出任何的图元。几何着色器的拿手好戏就是将输入的点或线扩展成多边形。下图展示了几何着色器如何将点扩展成多边形。

几何着色器例子


图元组装:图元组装将输入的顶点组装成指定的图元。图元组装阶段会进行裁剪和背面剔除相关的优化,以减少进入光栅化的图元的数量,加速渲染过程。在光栅化之前,还会进行屏幕映射的操作:透视除法和视口变换

关于透视除法和视口变换到底属于流水线的那个阶段并没有一个权威的说法,某些资料将这两个操作归入到图元组装阶段,某些资料将它归入到光栅化过程,但对我们理解整个渲染管线并没有太大的影响,我们只需要知道在光栅化前需要进行屏幕映射就可以了,所以我们这里将屏幕映射放到了图元组装过程。这两个操作主要是硬件实现,不同厂商会有不同的设计。

光栅化:经过图元组装以及屏幕映射阶段后,我们将物体坐标变换到了窗口坐标。光栅化是个离散化的过程,将3D连续的物体转化为离散屏幕像素点的过程。包括三角形组装和三角形遍历两个阶段。光栅化会确定图元所覆盖的片段,利用顶点属性插值得到片段的属性信息,然后送到片段着色器进行颜色计算,我们这里需要注意到片段是像素的候选者,只有通过后续的测试,片段才会成为最终显示的像素点。

光栅化阶段

片段着色器:片段着色器在DirectX中也成为像素着色器(Pixel Shader)。片段着色器用来决定屏幕上像素的最终颜色。在这个阶段会进行光照计算以及阴影处理,是渲染管线高级效果产生的地方。

测试混合阶段:管线的最后一个阶段是测试混合阶段。测试包括裁切测试、Alpha测试、模板测试和深度测试。没有经过测试的片段会被丢弃,不需要进行混合阶段;经过测试的片段会进入混合阶段。Alpha混合可以根据片段的alpha值进行混合,用来产生半透明的效果。Alpha表示的是物体的不透明度,因此alpha=1表示完全不透明,alpha=0表示完全透明。测试混合阶段虽然不是可编程阶段,但是我们可以通过OpenGL或DirectX提供的接口进行配置,定制混合和测试的方式。

实现环节:

首先完成与上一部分创建窗口同样的操作:初始化glfw、glad、窗口。

顶点输入

指定三个顶点,顶点的z坐标深度相同,即表示在同一2D平面,深度值表示的是遮挡关系。注意OpenGL的绘制窗口所处理的是标准化的坐标,范围在-1~1之间才为OpenGL的可视区域。标准化坐标接着会变为屏幕空间坐标,是通过使用glViewport函数提供的数据进行视口变换完成的。glOrtho函数只是负责使用什么样的视景体来截取图像,并不负责使用某种规则把图像呈现在屏幕上。glViewport负责把视景体截取的图像按照怎样的高和宽显示到屏幕上。图像会根据视口的大小拉伸变形。

定义好定点后需要将其输入发送给顶点着色器,顶点着色器在GPU上工作,创建内存用于储存顶点数据,我们需要通过顶点缓冲对象VBO管理GPU内存储存大量顶点,可以帮助我们一次发送很多顶点数据到GPU上,定义好VBO后需要使用glBindBuffer函数为定义的VBO绑定一种缓冲类型,绑定后任何在该类型上的缓冲调用都会用来配置绑定好的VBO。

定义顶点数据->定义VBO->为VBO绑定类型(此处将VBO绑定在GL-ARRAY_BUFFER目标上)->

调用glBufferData函数将之前定义的顶点数据复制到缓存的内存中:

 glBufferData用于像buffer类型传入数据,第一个参数为目标缓冲的类型,第二个参数为传输数据的大小,第三个即为实际数据,第四个参数为数据的属性。

 顶点着色器

使用GLSL编写顶点着色器,并对其进行编译。以下面的代码为例:

char* vertexShaderSource引号内的内容即为GLSL编写的顶点着色器源代码。

第一行为版本声明,表示使用的为OpenGL3.3版本核心模式。

layout为布局限定符,in关键词在vertexshader中声明输入顶点的属性,并设定输入变量的位置值。下一行中给gl_Position创建四维向量并将原本的vec3的x、y、z值输入,对w值赋值为1.0f。

将上述内容编码在字符串中后,即生成了着色器源码。下面需要创建一个着色器对象,创建方式与创建VBO有些类似,需要定义一个unsigned int来满足用ID引用,并将需要创建的着色器类型提供给glCreateShader。在此之后需要将放入字符串的GLSL着色器源码附着给创建好的着色器并对其进行编译。

 这里要说明的是,glShderSource函数,第一个参数为着色器对象,第二个参数制定了传递的源码字符串数量,第三个参数是顶点着色器的源码,第四个参数暂时设置为null。

下面检测编译是否成功:

glGetShaderiv用于检测是否成功,glGetShaderInforLog获取错误消息,

片段着色器

片段着色器用于计算像素最后的颜色输出,以下面的源码为例,同样使用GLSL语言编写好后放入字符串等待编译。

创建着色器并确定类型、将着色器源码与着色器附着,对其进行编译并检验编译是否成功的程序与顶点着色器的程序类似。流程均为,定义unsigned int 创建着色器对象并说明其类型,使用glShaderSource函数将其与源码连接,并进行编译使用glCompileShader函数。

 着色器程序

最终的着色器程序对象是多个着色器合并之后最终链接完成的版本,前面完成创建的顶点着色器和片段着色器需要被Link为一个着色器程序对象,然后在渲染对象时激活这个着色器程序,以及后续调用激活的着色器程序。 

创建对象的程序与前面类似,创建好着色器程序对象后将前面写好两个着色器对象使用glAttachShader()附加其上并使用glLinkProgram()连接。

同检验编译是否成功的部分,此处可以使用类似的方法检测连接是否成功。

 在顶点着色器与片段着色器完成了链接后,即可将其删除。

链接顶点属性

我们输入的顶点数据需要向OpenGL解释这些数据的意义,使用函数glVertexAttribPointer函数高速OpenGL如何解释这些数据。

上面的内容对应在函数中就是

 参数一:location的值,由于着色器源码的部分layout语句中将顶点的位置值设置为0,所以第一个参数的值为0.

参数二:顶点属性的大小,顶点属性是一个vec3,所以此处为3

参数三:参数的数据类型

参数四:是否希望数据被标准化

参数五:步长,即两个数据间的间隔,由于vec传入的数据类型为float,此处每个数据的长度即为

3*sizeof(float)

参数六:表示缓冲中起始位置的偏移量。

下面的函数glEnableVertexAttribArray用于激活上面我们设置的数据格式。

仅使用顶点缓冲对象VBO的流程

VAO顶点数组对象 

在核心模式下必须使用VAO传入顶点数据

 创建VAO首先int unsigned VAO,然后使用glBindVertexArray(VAO)绑定。

整体的流程大致是:创建VAO\VBO,绑定VAO VBO,输入顶点数据,配置顶点数据设置顶点属性指针,在渲染循环中绘制。

此处的最后一句,我们使用glDrawArrays(GL_TRIANGLES, 0, 3);

glDrawArrays函数第一个参数是我们想要画出的图元类型,第二个参数是顶点数据在数组中的起始下标,第三个元素是我们想要画出的顶点数目。至此,我们完成了三角形的绘制。 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值