小白入门opengl(二)画出三角形

在opengl中任何事物都在3D空间中,而屏幕与窗口确实2D的,由3D坐标转化为2D的处理过程是opengl的图形渲染管线管理的。可以被划分为两个主要部分,第一部分把你的3D坐标转化为2D坐标,第二部分则是把2D坐标转化为有颜色的像素。
在图形渲染管线上运行各自的小程序,从而图形渲染管线鲁艾苏处理你的数据,这样的小程序叫做着色器。
有些着色器允许开发者自己配置,可以让我们更加细致的控制渲染管线的特定部分。
小白入门opengl(二)画出三角形_第1张图片
在现代OpenGL中,我们必须至少定义一个顶点着色器和一个片段着色器,
1.顶点输入
float vertices[]={
-0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
0.0f,0.5f,0.0f
};
由于我们渲染的是一个2d图形,所以我们将它顶点的z坐标设置为0.0。
定义了以上的顶点数据后,我们会把它作为输入发送给图形渲染管线的第一个处理阶段。
我们通过顶点缓冲对象来管理这个内存,会在GPU内存中存储大量的顶点,好处就是可以一次性的发送大量的数据至显卡的内存中。顶点着色器能够立即访问到顶点。
我们可以使用glGenBuffers函数和一个缓冲ID来生成一个VBO对象,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER,然后调用glBufferData来将之前定义的顶点数据复制到缓冲的内存中:

unsigned int VBO;
glGenBuffers(1,&VBO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);

glBufferData的第四个参数由三种形式,用于告诉显卡如何去管理给定的数据

  • GL_STATIC_DRAW:数据不会或者几乎不会改变很多
  • GL_DYNAMIC_DRAW:数据会被改变很多
  • GL_STREAM_DRAW:数据每次绘制的时候都会改变
    现在我们已经把顶点的数据存储到了显卡中了。
    2顶点着色器和片段着色器
    首先,我们使用GLSL(OpenGL Shading Language)编写顶点着色器,,然后编译此着色器。
    每个着色器都起始于一个版本声明,例如(GLSL 420 对应OpenGL4.2)
    下一步使用in关键字,在顶点着色器中输入顶点属性,现在我们只关心Position数据,所以我们只需要一个顶点属性,GLSL有一个向量数据类型,包含1到4个float分量,通过layout(location =0)设定输入变量的位置值。
    编译着色器,但是为了能够让OpenGL使用它,我们必须在运行时动态的编译它的源码。
    首先我们要做的就是要创建一个对象,注意还是用id来引用的,所以我们存储这个顶点着色器为unsigned int,然后用glCreateShader来创建这个着色器,同样类似的还有片段着色器
//将其存储在vertexShaderSource 字符串中
#version 330 core
layout (location = 0) in vec3 aPos;

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

然后就是编译该着色器。

unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
//下面是检查文件是否编译成功,如果编译不成功就是输出一些相关信息
int  success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
    glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
    std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}

片段着色器与之类似,不过参数改为了GL_FRAGMENT_SHADER
然后创建一个着色器程序,将其连接到用来渲染的着色器程序。

int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	// check for linking errors
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

opengl解释顶点属性
小白入门opengl(二)画出三角形_第2张图片
位置数据被储存为32位(4字节)浮点值。
每个位置包含3个这样的值。
在这3个值之间没有空隙(或其他值)。这几个值在数组中紧密排列(Tightly Packed)。
数据中第一个值在缓冲开始的位置。
有了这些信息我们就可以使用glVertexAttribPointer函数告诉OpenGL如何解析顶点函数。

glVertexAttritPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void)*0);
glEnableVertexAttribArray(0);//以顶点属性位置值作为参数,启用顶点属性

在OpenGL中绘制一个物体,代码会像如下所示那样


// 0. 复制顶点数组到缓冲中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 1. 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 2. 当我们渲染一个物体时要使用着色器程序
glUseProgram(shaderProgram);
// 3. 绘制物体
someOpenGLFunctionThatDrawsOurTriangle();


顶点数组对象(VAO)


OpenGL的核心模式要求我们使用VAO,所以它知道该如何处理我们的顶点输入。如果我们绑定VAO失败,OpenGL会拒绝绘制任何东西。


一个顶点数组对象会存储下面的东西,

  • glEnableVertexAttribArray和glDisableVertexAttribArray的调用。
  • 通过glVertexAttribPointer设置的顶点属性配置。
  • 通过glVertexAttribPointer调用与顶点属性关联的顶点缓冲对象。
    小白入门opengl(二)画出三角形_第3张图片
    创建一个VAO与VBO很类似的
unsigned int VAO;
glGenVertexArrays(1,&VAO);

要想使用VAO,要做的是使用glBindVertexArray绑定VAO。绑定之后起,绑定和配置对应的VBO和属性指针,之后解绑VAO供之使用,在绘制一个物体前,将VAO绑定到希望的设定上去。

// ..:: 初始化代码(只运行一次 (除非你的物体频繁改变)) :: ..
// 1. 绑定VAO
glBindVertexArray(VAO);
// 2. 把顶点数组复制到缓冲中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

[...]

// ..:: 绘制代码(渲染循环中) :: ..
// 4. 绘制物体
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
someOpenGLFunctionThatDrawsOurTriangle();

你可能感兴趣的:(opengl,learning)