VBO,VAO,,EBO-penGL进阶(二十) - 绘制一个长方形和一个三角形

简介

先看最终效果

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

 

 

方框的绘制

方框其实是由两个三角形组成,看一下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/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值