OpenGL进阶(二十):绘制一个长方形和一个三角形

发表于2017-09-07
评论0 1k浏览

OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性,关于OpenGL的一些基本使用就不做介绍了,这里给大家介绍是OpenGL进阶方面的技巧,去绘制一个长方形和一个三角形。

简介

先看最终效果


今天要学习的重点是怎样在场景中绘制两个(或者以上的)物体,



方框的绘制

方框其实是由两个三角形组成,看一下VBO, VAO, EBO的定义


  1. GLfloat vertices[] = {  
  2.     0.5f, 0.5f, -1.0f,  
  3.     0.5f, -0.5f, -1.0f,  
  4.     -0.5f, -0.5f, -1.0f,  
  5.     -0.5f, 0.5f, -1.0f  
  6. };  
  7.   
  8.   
  9. GLuint indices[] = {    
  10.     0, 1, 3,   
  11.     1, 2, 3    
  12. };  
  13. //First: Square  
  14. // Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).  
  15. glBindVertexArray(VAOs[0]);  
  16.   
  17.   
  18. glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);  
  19. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  
  20.   
  21.   
  22. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);  
  23. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);  
  24.   
  25.   
  26. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);  
  27. glEnableVertexAttribArray(0);  
  28.   
  29.   
  30. glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind  
  31.   
  32.   
  33. glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs)  


Shader的定义


shader就直接写到一个string里面先

  1. // Shaders  
  2. const GLchar* vertexShaderSource = "#version 330 core\n"  
  3. "layout (location = 0) in vec3 position;\n"  
  4. "void main()\n"  
  5. "{\n"  
  6. "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"  
  7. "}\0";  
  8. const GLchar* fragmentShaderSource = "#version 330 core\n"  
  9. "out vec4 color;\n"  
  10. "void main()\n"  
  11. "{\n"  
  12. "color = vec4(1.0f, 0f, 0f, 1.0f);\n"  
  13. "}\n\0";  


Shader的创建和删除

  1. // Vertex shader  
  2. GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);  
  3. glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);  
  4. glCompileShader(vertexShader);  
  5. // Check for compile time errors  
  6. GLint success;  
  7. GLchar infoLog[512];  
  8. glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);  
  9. if (!success)  
  10. {  
  11.     glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);  
  12.     qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog ;  
  13. }  
  14. else  
  15. {  
  16.     qDebug() << "Vertex Shader compile success!";  
  17. }  
  18.   
  19.   
  20. // Fragment shader  
  21. GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);  
  22. glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);  
  23. glCompileShader(fragmentShader);  
  24. // Check for compile time errors  
  25. glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);  
  26. if (!success)  
  27. {  
  28.     glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);  
  29.     qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog ;  
  30. }  
  31. else  
  32. {  
  33.     qDebug() << "Fragment Shader compile success!";  
  34. }  
  35.   
  36. // Link shaders  
  37. shaderProgram = glCreateProgram();  
  38. glAttachShader(shaderProgram, vertexShader);  
  39. glAttachShader(shaderProgram, fragmentShader);  
  40. glLinkProgram(shaderProgram);  
  41. // Check for linking errors  
  42. glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);  
  43. if (!success) {  
  44.     glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);  
  45.     qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog ;  
  46. }  
  47. else  
  48. {  
  49.     qDebug() << "Link Program success!";  
  50. }  


用了EBO,所以在绘制的时候用glDrawElements,要绘制线框模式,所以在最前面加  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

  1. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  
  2. glUseProgram(shaderProgram);  
  3. glBindVertexArray(VAOs[0]);  
  4. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);  


这里再补一下VBO,VAO,,EBO 的概念

顶点缓冲对象(Vertex Buffer Objects, VBO)在GPU内存(通常被称为显存)中储存大量顶点。使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。从CPU把数据发送到显卡相对较慢,所以只要可能我们都要尝试尽量一次性发送尽可能多的数据。当数据发送至显卡的内存中后,顶点着色器几乎能立即访问顶点,这是个非常快的过程。

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


索引缓冲对象(Element Buffer Object,EBO,也叫Index Buffer Object,IBO),和顶点缓冲对象一样,EBO也是一个缓冲,它专门储存索引,OpenGL调用这些顶点的索引来决定该绘制哪个顶点。


三者的关系



绘制三角形

三角形比较简单,只用了没用用EBO,数据定义如下

  1. GLfloat secondTriangle[] = {  
  2.     0.0f, -0.5f, -1.0,  // Left  
  3.     0.9f, -0.5f, -1.0,  // Right  
  4.     0.45f, 0.5f, -1.0   // Top   
  5. };  

VertexShader还是用原来的那个,FragmentShader换个颜色

  1. const GLchar* fragmentShader2Source = "#version 330 core\n"  
  2. "out vec4 color;\n"  
  3. "void main()\n"  
  4. "{\n"  
  5. "color = vec4(0.0f, 1f, 1f, 1.0f);\n"  
  6. "}\n\0";  


Shader的编译和链接

  1. // Fragment shader2  
  2. GLuint fragmentShader2 = glCreateShader(GL_FRAGMENT_SHADER);  
  3. glShaderSource(fragmentShader2, 1, &fragmentShader2Source, NULL);  
  4. glCompileShader(fragmentShader2);  
  5. // Check for compile time errors  
  6. glGetShaderiv(fragmentShader2, GL_COMPILE_STATUS, &success);  
  7. if (!success)  
  8. {  
  9.     glGetShaderInfoLog(fragmentShader2, 512, NULL, infoLog);  
  10.     qDebug() << "ERROR::SHADER::FRAGMENT 2::COMPILATION_FAILED\n" << infoLog;  
  11. }  
  12. else  
  13. {  
  14.     qDebug() << "Fragment Shader 2 compile success!";  
  15. }  
  16.   
  17. // Link shaders 2  
  18. shaderProgram2 = glCreateProgram();  
  19. glAttachShader(shaderProgram2, vertexShader);  
  20. glAttachShader(shaderProgram2, fragmentShader2);  
  21. glLinkProgram(shaderProgram2);  
  22. // Check for linking errors  
  23. glGetProgramiv(shaderProgram2, GL_LINK_STATUS, &success);  
  24. if (!success) {  
  25.     glGetProgramInfoLog(shaderProgram2, 512, NULL, infoLog);  
  26.     qDebug() << "ERROR::SHADER::PROGRAM 2::LINKING_FAILED\n" << infoLog ;  
  27. }  
  28. else  
  29. {  
  30.     qDebug() << "Link Program2 success!";  
  31. }  


Shader使用完了记得要delete

  1. glDeleteShader(vertexShader);  
  2. glDeleteShader(fragmentShader);  
  3. glDeleteShader(fragmentShader2);  

VAO和VBO的绑定如下


  1. //Second: Triangle  
  2. glBindVertexArray(VAOs[1]);  
  3.   
  4. glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);  
  5. glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW);  
  6.   
  7. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);  
  8. glEnableVertexAttribArray(0);  
  9.   
  10. glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind  
  11.   
  12. glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs)  


最后绘制

  1. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);  
  2. glUseProgram(shaderProgram2);  
  3. glBindVertexArray(VAOs[1]);  
  4. glDrawArrays(GL_TRIANGLES, 0, 3);  
  5. glBindVertexArray(0);  

参考

learnopengl - http://learnopengl.com/


http://blog.csdn.net/silangquan/article/details/52186805

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引