目的本文介绍使用GLSL绘图。
坐标想要用GLSL绘图,首先要有对应坐标。
OpenGL显示界面中心点为坐标原点,宽度为[-1,1],高度为[-1,1],不论实际宽高为多少都是这个范围。
数组将三角形坐标转换为数组。
二维三角形的三个顶点为
1 2 3 4 5 float vertices[] = { -0.5f ,-0.5f , 0.0f , 0.5f ,-0.5f , 0.0f , 0.0f , 0.5f , 0.0f };
这个是以C++数组的形式存储数据,但是此数据发送到GPU中该如何存储呢?
渲染流程
图片来自LearnOpenGL,这个教程比Nehe OpenGL更新更好,推荐。
VBO顶点数据数组传递至显卡后,存储在GPU显存上的一段存储空间对象里面,这个对象叫做VBO(Vertex Buffer Object,顶点缓冲对象)。VBO在C++中表现为一个 unsigned int 类型变量,理解成为GPU内存对象的一个ID编号。
VAOVBO除了表示顶点外,还可以表示颜色。那么问题来了,如果一次渲染多个VBO呢?
VAO(Vertex Array Object,顶点数组对象),用于存储一个Mesh网络所有的顶点属性描述信息。
简单来说,VAO包含一个或多个VBO。
VAO和VBO必须同时出现。
顶点着色器顶点着色器的作用是把存储在VBO中的顶点数据进行处理并准备绘图。
片段着色器片段着色器的作用是把已经会好的图进行上色。纹理也是由RGB等颜色组成的,所以纹理填充是在这里实施的。但是没有直接操作片段着色器的接口,所以要把颜色、纹理等通过顶点着色器传递给片段着色器。
代码 指定GL版本首先告诉GLFW当前使用的是OpenGL 3+ API
1 2 3 glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3 );glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 3 );glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
初始化glad初始化glad的glfw接口,通过glad我们可以使用几乎所有的OpenGL相关的API。
1 2 3 4 5 if (!gladLoadGLLoader ((GLADloadproc)glfwGetProcAddress)) { fprintf (stderr, "Failed to initialize GLAD\n" ); return -1 ; }
顶点着色器顶点着色器是类C代码,以字符串形式提供
1 2 3 4 5 6 const char *vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" "}\0" ;
片段着色器片段着色器是类C代码,以字符串形式提供
1 2 3 4 5 6 const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}\n\0" ;
着色器加载加载着色器代码,编译代码,检查编译状态,使用着色器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 unsigned int 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); fprintf (stderr, "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" ); }unsigned int fragmentShader = glCreateShader (GL_FRAGMENT_SHADER);glShaderSource (fragmentShader, 1 , &fragmentShaderSource, NULL );glCompileShader (fragmentShader);glGetShaderiv (fragmentShader, GL_COMPILE_STATUS, &success);if (!success) { glGetShaderInfoLog (fragmentShader, 512 , NULL , infoLog); fprintf (stderr, "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" ); }unsigned int shaderProgram = glCreateProgram ();glAttachShader (shaderProgram, vertexShader);glAttachShader (shaderProgram, fragmentShader);glLinkProgram (shaderProgram);glGetProgramiv (shaderProgram, GL_LINK_STATUS, &success);if (!success) { glGetProgramInfoLog (shaderProgram, 512 , NULL , infoLog); fprintf (stderr, "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" ); }glDeleteShader (vertexShader); glDeleteShader (fragmentShader);
三角形定义三角形顶点数组
1 2 3 4 5 float vertices[] = { 0.5f , -0.5f , 0.0f , -0.5f , -0.5f , 0.0f , 0.0f , 0.5f , 0.0f };
创建VAO和VBO1 2 3 unsigned int VAO,VBO;glGenBuffers (1 , &VBO);glGenVertexArrays (1 ,&VAO);
使用VAO和VBO1 2 3 4 5 6 glBindVertexArray (VAO);glBindBuffer (GL_ARRAY_BUFFER, VBO); glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer (0 , 3 , GL_FLOAT, GL_FALSE, 3 * sizeof (float ), (void *)0 ); glEnableVertexAttribArray (0 );
先绑定VAO,表示以下的所有VBO都绑定到此VAO中。当然,目前只有一个VBO。
绑定VBO,并将数组内容传递给VBO,但是此时VBO只是知道有一个长度为9数组。
我们还需要告诉VBO如何使用这个数组,即3个一组使用,每个元素都是float。
显示1 2 3 4 5 glUseProgram (shaderProgram); glBindVertexArray (VAO); glDrawArrays (GL_TRIANGLES, 0 , 3 );glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
先告知使用着色器程序,然后使用VAO,开始绘图,绘图模式为轮廓模式。
释放资源1 2 3 glDeleteBuffers (1 , &VAO);glDeleteBuffers (1 , &VBO);glDeleteProgram (shaderProgram);
注意这里的释放顺序。
效果编译运行