本文共 14597 字,大约阅读时间需要 48 分钟。
float vertices[] = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f, 0.5f, 0.0f};
glViewport(GLint x, GLint y, GLsizei width, GLsizei height);//x y:定义视口的左下角开始位置//width,height :定义这个视口矩形的宽度和高度
unsigned int VBO;glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //把用户定义的数据复制到当前绑定缓冲对象上//参数1:目标缓冲的类型//参数2:传输数据的大小(以字节为单位)//参数3:数据指针//参数4:指定我们希望显卡如何管理给定的数据
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";
unsigned int vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);//创建一个着色器,参数GL_VERTEX_SHADER 或者GL_FRAGMENT_SHADER,由于我们创建的是顶点shader,所以填入GL_VERTEX_SHADER ,否则就是片元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;}
void glGetShaderiv(GLuint shader,GLenum pname,GLint *params);//shader:要查询的着色器对象//pname : 查询类型,可以设置的有GL_SHADER_TYPE、GL_DELETE_STATUS、GL_COMPILE_STATUS、GL_INFO_LOG_LENGTH.//GL_SHADER_TYPE: 用来判断并返回着色器类型,若是顶点着色器则success=GL_VERTEX_SHADER,若是片元着色器success=GL_FRAGMENT_SHADER//GL_DELETE_STATUS: 判断着色器是否被删除,success=GL_TRUE,否则success=GL_FALSE,//GL_COMPILE_STATUS: 用于检测编译是否成功,success=GL_TRUE,否则success=GL_FALSE,//GL_INFO_LOG_LENGTH: 获取着色器的信息日志的长度(information log length), 如果着色器没有信息日志,则success=0。//GL_SHADER_SOURCE_LENGTH: 获取着色器源码长度,不存在则success=0;//params:查询的内容
const char *fragmentShaderSource = "#version 330 core\n""out vec4 FragColor;\n""void main()\n""{\n"" FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n""}\n\0";
unsigned int fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); //创建一个片元着色器glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);//设置片元源码glCompileShader(fragmentShader); //编译
2.7 着色器Program对象
两个着色器现在都编译了,接下来就是把两个着色器对象链接到一个用来渲染(调用顶点shader和片元shader数据)的着色器Program对象中。
unsigned int shaderProgram;shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader); //将附加vertexShader到的shaderProgram对象中glAttachShader(shaderProgram, fragmentShader);//将附加fragmentShader到的shaderProgram对象中glLinkProgram(shaderProgram); //将附加的shader链接到program对象中 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); //链接后不再需要它们,需要删除shaderglDeleteShader(fragmentShader);
glGetProgramiv(shaderProgram, GL_ATTACHED_SHADERS, &cnt); //获取着色器对象的数量
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//设置顶点属性glEnableVertexAttribArray(0);//使能顶点属性(默认是禁止的)glUseProgram(shaderProgram); //激活Program对象someOpenGLFunctionThatDrawsOurTriangle();// 绘制物体
void glVertexAttribPointer(GLuint index , GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr);//指定渲染时索引值为 index 的顶点属性数组的数据格式和位置。//index:指定要修改的顶点位置的索引值,之前使用layout(location = 0)设置了顶点位置为0,//size:指定每个顶点属性的组件数量。必须为1、2、3、4之一。(如我们这里顶点是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))//type:指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT//normalized:是否希望数据被标准化。设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。我们把它设置为GL_FALSEM,不需要。//stride:步长,指定顶点之间的偏移量。我们这里是每3个float为一个顶点,所以偏移量为3 * sizeof(float)//ptr:可以指向需要绑定的VBO,如果已经绑定VBO,并且位置数据在缓冲中起始位置为0,那么此项为0,否则填入开头的偏移量
当我们绘制好物体后,每当最大化,尺寸变化界面后,openGL就会进入刷新状态,所以我们需要把所有这些状态配置储存在一个顶点数组对象(Vertex Array Object, VAO)中,每次刷新时,就可以通过VAO来恢复状态.
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //设置清除颜色(背景色)为rgba(0.2f, 0.3f, 0.3f, 1.0f)// 初始化代码,初始化顶点shader、片元shader、program、vbo// ... ..// ... ...//1.初始化vaounsigned int VAO;glGenVertexArrays(1, &VAO); // 注册VAOglBindVertexArray(VAO); // 绑定VAO//2. 把顶点数组复制到缓冲中供OpenGL使用glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把用户定义的顶点数据复制到vao上 //3. 设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);//使能顶点属性(默认是禁止的)//4. 解绑VAOglBindVertexArray(0);
glClear(GL_COLOR_BUFFER_BIT); //开始清除,设置背景色glUseProgram(shaderProgram); ////激活Program对象glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3); //绘制三角形someOpenGLFunctionThatDrawsOurTriangle();// 绘制物体glBindVertexArray(0); //绘制完成,便解绑,用来绑定下一个要绘制的物体
glDrawArrays(GLenum mode, GLint first, GLsizei count);//函数根据顶点数组中的坐标数据和指定的模式,进行绘制。//mode,绘制方式,如下图所示,提供以下参数://GL_POINTS(画点)、GL_LINES(每两个顶点为一条直线)、GL_LINE_LOOP(是个环状)、//GL_LINE_STRIP(第一个顶点和最后一个顶点不相连)、GL_TRIANGLES(每三个顶点组成一个三角形)、//GL_TRIANGLE_STRIP(共用多个顶点的一个三角形)、GL_TRIANGLE_FAN(共用一个原点为中心的一个三角形)。//first,从数组缓存中的哪一位开始绘制,一般为0。//count,数组中顶点的数量。
如下图所示:
//hello_triangle.cpp#include#include #include void framebuffer_size_callback(GLFWwindow* window, int width, int height);void processInput(GLFWwindow *window); // settingsconst unsigned int SCR_WIDTH = 800;const unsigned int SCR_HEIGHT = 600; 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";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"; int main(){// glfw: initialize and configure// ------------------------------glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X#endif // glfw window creation// --------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // glad: load all OpenGL function pointers// ---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;} // build and compile our shader program// ------------------------------------// vertex shaderint vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// check for shader compile errorsint 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;}// fragment shaderint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// check for shader compile errorsglGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// link shadersint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// check for linking errorsglGetProgramiv(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); // set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float vertices[] = {-0.5f, -0.5f, 0.0f, // left0.5f, -0.5f, 0.0f, // right0.0f, 0.5f, 0.0f // top}; unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).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); // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbindglBindBuffer(GL_ARRAY_BUFFER, 0); // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.glBindVertexArray(0); // uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // render loop// -----------while (!glfwWindowShouldClose(window)){// input// -----processInput(window); // render// ------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT); // draw our first triangleglUseProgram(shaderProgram);glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organizedglDrawArrays(GL_TRIANGLES, 0, 3);// glBindVertexArray(0); // no need to unbind it every time // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();} // optional: de-allocate all resources once they've outlived their purpose:// ------------------------------------------------------------------------glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO); // glfw: terminate, clearing all previously allocated GLFW resources.// ------------------------------------------------------------------glfwTerminate();return 0;} // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly// ---------------------------------------------------------------------------------------------------------void processInput(GLFWwindow *window){if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);} // glfw: whenever the window size changed (by OS or user resize) this callback function executes// ---------------------------------------------------------------------------------------------void framebuffer_size_callback(GLFWwindow* window, int width, int height){// make sure the viewport matches the new window dimensions; note that width and// height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);}
未完待续 ,下章学习:
转载地址:http://waiyz.baihongyu.com/