learnopengl——三角形

原文网址:https://learnopengl.com/Getting-started/Hello-Triangle

在OpenGL中,所有的东西都是3D空间中。但是屏幕和窗口是2D数组的像素。所以OpenGL的大部分工作是关于把3D坐标转换为2D像素。将3D坐标转换为2D像素的过程是由OpenGL的图形管线控制的。图形管线可以被分为两个部分:第一部分是把3D坐标转换为2D坐标,第二部分是把2D坐标转换为颜色像素。本节我们将会简要的讨论图形管线,以及如何使用它来创建好看的像素。

图形管线的输入时一系列3D坐标,然后把他们转换到有颜色的2D像素,最终显示在屏幕上。图形管线可以被分为几个步骤,每个步骤都需要前一步的输出作为输入。所有的步骤都是高度特殊化的,他们可以并行执行。因为他们并行的特性,目前图形显卡由几千个小的处理内核,加速了处理数据的能力,处理数据的小程序是工作在GPU上的,这些小程序叫做shader。

有些shader可以由开发者配置,你可以写自己的shader,替换掉默认的shader。这个允许我们细粒度的控制管线的特定的部分,由于他们是工作在GPU上的,所以他们节省了大量的CPU时间。shader可以使用GLSL——OpenGL Shading Language编写,下一节我们可以更加详细的介绍。

下面我们抽象出管线的几个步骤,注意蓝色的部分是我们可以加入shader的部分:
在这里插入图片描述

你可以看到,图形管线包含大量的部分,每个部分负责处理对应的数据。

定点数据定义好之后,我们把他输入到管线的第一个步——顶点着色器。这个操作是在GPU上开辟内存,然后储存顶点数据,顶点着色器负责处理这些顶点数据。

我们使用VBO——vertex buffer object来管理这个内存,VBO对象可以储存GPU中的大量的顶点数据。使用这些缓冲对象的优势是,我们可以一次发送一大批的数据给图形显卡,而不需要每次发送一个顶点数据。由CPU发送数据给图形显卡是很慢的,所以我们一次发送尽量发送多的数据。一旦数据在图形显卡的内存中了,顶点着色器就可以快速的处理这些数据了。

本节是第一次出现顶点缓冲对象的概念。像OpenGL中其他的对象一样,它也需要一个唯一的ID来标识。所以我们需要调用glGenBuffers来生成这个唯一的ID:

unsigned int VBO;
glGenBuffers(1, &VBO);  

OpenGL由多种类型的缓冲对象,顶点缓冲对象的类型为GL_ARRAY_BUFFER。OpenGL允许我们一次绑定几个缓冲只要他们的类型不同。我们可以绑定新创建的顶点缓冲对象到GL_ARRAY_BUFFER ,使用函数glBindBuffer:

glBindBuffer(GL_ARRAY_BUFFER, VBO);  

这样绑定之后,我们的VBO对象就绑定到了GL_ARRAY_BUFFER目标了。然后我们可以调用glBufferData函数来拷贝数据到缓冲:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBufferData把用户指定的额数据拷贝到当前绑定的的缓冲。第一个参数是缓冲的类型,当前缓冲对象是绑定到GL_ARRAY_BUFFER目标的。第二个参数指定了数据的大小,按字节计算。第三个参数是真正的数据。第四个参数指定了我们如何去控制管线的中的数据。他有三个形式:
1、GL_STATIC_DRAW:标记管线中的数据不会改变。
2、GL_DYNAMIC_DRAW:标记管线中的数据可以被改变。
3、GL_STREAM_DRAW:标记在每次绘制的时候,数据会被改变。

三角形的位置数据不会改变,每次渲染调用都保持不变,所以他的类型为:GL_STATIC_DRAW。
如果缓冲中的数据会被改变,那么要使用GL_DYNAMIC_DRAW 或者 GL_STREAM_DRAW。

顶点着色器
顶点着色器是每个人根据喜好能够可编程的着色器。当前的OpenGL要求是,如果想要做些渲染的事情,至少创建一个顶点着色器、一个片段着色器。所以为了画第一个三角形,需要简单的引入两个简单的着色器。后面的章节,我们将会更详细的讨论着色器。

第一件事是,使用GLSL着色语言写一个顶点着色器,然后是编译着色器,所以我们可以在自己的程序中使用它们。下面的是使用GLSL语言编写的简单的顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

你可以看到,GLSL看起来像C。每个shader开始都要是版本号的声明。由于OpenGL3.3和更高版本的GLSL匹配OpenGL(GLSL版本420对应的是OpenGL版本4.2)。

接着我们声明了所有的输入属性,使用关键字in。我们声明了一个顶点位置作为输入属性。GLSL有一个向量数据类型,它包含1到4个浮点数,这个后缀代表了几个浮点数。由于每个顶点有一个3D坐标,我们创建vec3作为输入,它的名字是aPos。我们同样设置其输入变量的位置是0,通过语法(layout=0)表示。你后面会看到我们为什么需要这个位置。

为了设置顶点着色器的输出,我们需要指定位置数据到预定义的gl_Position变量,这个是在场景背后的vec4变量。在main函数的结束,无论我们把gl_Position设置为多少,它都会是顶点着色器的输出。由于我们的书是一个3维的向量,我们需要把它转换为4维的向量。我们可以把三维向量的第四维设置为1.0f,变为四维向量,后面会介绍我们为什么会这样做。

当前的顶点着色器是一个简单的着色器,因为我们不做任何特殊的处理,只是简单的把输入的数据作为着色器的输出。在真实的应用中,输入数据通常是不在规格化的设备坐标中,所谓我们首先要做的是,转换输入数据到OpenGL可视区域。

编译shader

片段着色器
片段着色器是我们创建用来渲染三角形的第二个也是最后一个shader。片段着色器是关于计算颜色的。为了保持其简单性,我们只是将输出的颜色设置为orange-ish颜色。

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
} 

片段着色器只需要一个输出变量,他是四维的向量。定义了最终的颜色,是由我们自己计算的。我们可以用out关键字来声明输出变量,这里我们的输出变量名为FragColor。接着我们指定vec4作为输出,alpha值为1.0,表示非透明。

顶点数组对象
一个顶点数组对象(称之为VAO),可以像顶点缓冲对象一样绑定,接下来的顶点属性的调用,都会被储存在VAO中。这个优点是,当我们在配置顶点属性指针的时候,你只需要在想要绘制物体的时候调用一次即可,我们只需要绑定到指定的VAO。这个在不同的顶点数据和属性之间做切换,唯一做的是绑定到不同的VAO,所有的状态都存储在VAO中。

一个顶点数组存储的方式如下:
1、调用glEnableVertexAttribArray 或者 glDisableVertexAttribArray
2、顶点属性配置通过glVertexAttribPointer
3、顶点缓冲对象和顶点属性相关,通过调用函数glVertexAttribPointer
在这里插入图片描述

创建要给VAO对象,和创建VBO类似:

unsigned int VAO;
glGenVertexArrays(1, &VAO);  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值