OpenGL自制游戏引擎-HelloTriangle

2019-07-02 17:58:34 浏览数 (1)

Pipeline: 开始绘制图形之前,我们必须先给OpenGL输入一些顶点数据,OpenGL不是简单地把所有的3D坐标变换为屏幕上的2D像素;OpenGL仅当3D坐标在3个轴(x、y和z)上都为-1.0到1.0的范围内时才处理它。所有在所谓的标准化设备坐标(Normalized Device Coordinates)范围内的坐标才会最终呈现在屏幕上. 定义这样的顶点数据以后,我们会把它作为输入发送给图形渲染管线的第一个处理阶段:顶点着色器。它会在GPU上创建内存用于储存我们的顶点数据,还要配置OpenGL如何解释这些内存,并且指定其如何发送给显卡。顶点着色器接着会处理我们在内存中指定数量的顶点。 通过顶点缓冲对象(Vertex Buffer Objects, VBO)管理这个内存,它会在GPU内存(通常被称为显存)中储存大量顶点。使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。从CPU把数据发送到显卡相对较慢,所以只要可能我们都要尝试尽量一次性发送尽可能多的数据。 顶点缓冲对象是我们在[OpenGL]教程中第一个出现的OpenGL对象。就像OpenGL中的其它对象一样,这个缓冲有一个独一无二的ID,所以我们可以使用glGenBuffers函数和一个缓冲ID生成一个VBO对象:

代码语言:javascript复制
unsigned int VBO;
glGenBuffers(1, &VBO);

glGenBuffers--返回n个当前未使用的缓存对象名称,并保存到buffers数组中。返回到buffers中的名称不一定是连续的整形数组。

使用Blender输出一个Triangle

代码语言:javascript复制
# Blender v2.79 (sub 0) OBJ File: ''
# www.blender.org
mtllib untitled.mtl
o Plane
v -0.992970 -0.048377 1.045255
v 1.007030 -0.048377 1.045255
v 0.007030 -0.048377 -0.954745
vn 0.0000 1.0000 0.0000
usemtl None
s off
f 1//1 2//1 3//1

vn表示法向量 f表示每个点的法向量是哪个?

CPU -> GPU 1.obj序列化 2.在GPU中存成VBO(Vertex Buffer Object) 3.VAO

添加UV信息后

代码语言:javascript复制
# Blender v2.79 (sub 0) OBJ File: ''
# www.blender.org
mtllib untitled.mtl
o Plane
v -1.061739 -0.317821 0.976793
v 0.938261 0.003355 0.976793
v -1.061739 0.107229 -1.023207
v 0.938261 -0.317821 -1.023207
vt 1.000000 0.009676
vt 0.991038 1.000000
vt 0.000000 0.000000
vt 0.000627 1.000000
vn -0.1552 0.9663 0.2054
vn 0.2054 0.9663 -0.1552
usemtl None
s off
f 1/1/1 2/2/1 3/3/1
f 3/3/2 2/2/2 4/4/2

在程序中添加VAO

顶点数组对象(Vertex Array Object, VAO)可以像顶点缓冲对象那样被绑定,任何随后的顶点属性调用都会储存在这个VAO中。这样的好处就是,当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。这使在不同顶点数据和属性配置之间切换变得非常简单,只需要绑定不同的VAO就行了。刚刚设置的所有状态都将存储在VAO中

代码语言:javascript复制
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

在程序中添加VBO;glBindBuffer指定当前激活的缓存对象。glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数。

代码语言:javascript复制
    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

为了让我们编写的shader让OpenGL动态执行,我们要创建一个shader Project。我们首先要做的是创建一个着色器对象,注意还是用ID来引用的。所以我们储存这个顶点着色器为unsigned int,然后用glCreateShader创建这个着色器:

We wrote the source code for the vertex shader (stored in a const C string at the top of the code file), but in order for OpenGL to use the shader it has to dynamically compile it at run-time from its source code.

代码语言:javascript复制
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

同样创建一个fragmentShader,用out关键字声明输出变量

代码语言:javascript复制
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

Shader Program

A shader program object is the final linked version of multiple shaders combined. To use the recently compiled shaders we have to link them to a shader program object and then activate this shader program when rendering objects. The activated shader program's shaders will be used when we issue render calls.

代码语言:javascript复制
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    //声明一个ShaderProgram , 连接两个Shader ,shader之间将处理数据传递数据
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

顶点着色器: 使用in关键字,在顶点着色器中声明所有的输入顶点属性。现在我们只关心位置(Position)数据,所以我们只需要一个顶点属性。由于每个顶点都有一个3D坐标,我们就创建一个vec3输入变量aPos。我们同样也通过layout (location = 0)设定了输入变量的位置值(Location)。

为了设置顶点着色器的输出,我们必须把位置数据赋值给预定义的gl_Position变量。

代码语言:javascript复制
#version 330 core
layout (location = 0) in vec3 aPos;

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

链接顶点属性: 顶点着色器提供很强灵活性,这意味着我们需要手动指定输入数据的那一部分对应顶点着色器的哪一个顶点属性。 顶点缓冲数据(VertexBufferObject)会被解析为一个位置数据存储为32Bit(4byte),一个vertex包括3个位置数据,三个数据之间没有空袭(Tightly Packed),数据中第一个值在缓冲开始的位置。

有了这些信息我们就可以使用glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据;使用glEnableVertexAttribArray,以顶点属性位置值作为参数,启用顶点属性;

绘制图元 glDrawArrays函数第一个参数是我们打算绘制的OpenGL图元的类型。由于我们在一开始时说过,我们希望绘制的是一个三角形,这里传递GL_TRIANGLES给它。第二个参数指定了顶点数组的起始索引,我们这里填0。最后一个参数指定我们打算绘制多少个顶点,这里是6

代码语言:javascript复制
        glBindVertexArray(VAO);
        glUseProgram(shaderProgram);
        glDrawArrays(GL_TRIANGLES, 0, 6);

0 人点赞