绘制一个正方形真的很简单,很显然,两个三角形铺在一起就可以了
一、绘制正方形
其实如果完全理解了前面的知识, 那么理论上不需要任何参考就可以绘制正方形,就如上所说,两个三角形只有顶点的位置不同而已……
那么绘制一个正方形需要多少个顶点呢?按照如上的方法,应该是需要6个,然而很明显只需要4个即可,因为有两个顶点它们在同一个位置,如果重复绘制会多出50%额外的开销,所以我们的解决方法就是:定义4个顶点,然后再定义2个绘制索引,也就是顶点复用,因此对于上一份输出三角形的代码,添加改动如下:
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
};
GLuint indices[] =
{
0, 1, 2, //用前3个顶点绘制第一个三角形
1, 2, 3 //用后3个顶点绘制第二个三角形
};
GLuint EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
while (!glfwWindowShouldClose(window))
{
//......
//glDrawArrays(GL_TRIANGLES, 0, 3); --此行不要
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//......
}
glDeleteBuffers(1, &EBO);
这样就可以输出我们想要的结果:
二、索引缓冲对象 EBO
上面的EBO(Element Buffer Object)即索引缓冲区对象,这个缓冲区主要用来存储顶点的索引信息,可以看出,它的用法和VBO非常的像,除此之外,它也可以被VAO所绑定
和VBO不同的是,我们传递GL_ELEMENT_ARRAY_BUFFER当作缓冲目标,并且在绘制时使用glDrawElements来替换glDrawArrays函数,表示我们使用当前绑定的索引缓冲对象中的索引进行绘制
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0):第一个参数为绘制模式,第二个参数为绘制顶点个数,第三个参数为索引类型,第四个参数为EBO中的偏移量,一样填写0就好,当我们不再使用索引缓冲对象的时候,可以传递一个索引数组
三、线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE):配置OpenGL如何绘制图元,第一个参数表示我们打算将其应用到所有的三角形的正面和背面(其实对于我们的例子没有什么区别,可以暂时无视),第二个参数表示用线来绘制,之后的绘制调用会一直以线框模式绘制三角形,直到第二个参数传入GL_FILL后回到默认模式
四、测试
看可不可以在不参考任何文章和代码的情况下,仅通过修改之前生成的三角形的代码,生成如下图形:
参考代码:
#pragma comment(lib,"glew32.lib")
#include<iostream>
#include<opengl/glew.h>
#define GLEW_STATIC
#include<GLFW/glfw3.h>
#include<opengl/freeglut.h>
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
const GLuint WIDTH = 800, HEIGHT = 600;
// Shaders
const GLchar* VShader =
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
const GLchar* FShaderY =
"#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
const GLchar* FShaderB =
"#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(0.1f, 0.1f, 1.0f, 1.0f);\n"
"}\n\0";
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glewExperimental = GL_TRUE;
glewInit();
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &VShader, NULL);
glCompileShader(vertexShader);
GLuint fShaderY = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fShaderY, 1, &FShaderY, NULL);
glCompileShader(fShaderY);
GLuint fShaderB = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fShaderB, 1, &FShaderB, NULL);
glCompileShader(fShaderB);
GLuint shaderYellow = glCreateProgram();
GLuint shaderBlue = glCreateProgram();
glAttachShader(shaderYellow, vertexShader);
glAttachShader(shaderYellow, fShaderY);
glLinkProgram(shaderYellow);
glAttachShader(shaderBlue, vertexShader);
glAttachShader(shaderBlue, fShaderB);
glLinkProgram(shaderBlue);
glDeleteShader(vertexShader);
glDeleteShader(fShaderY);
glDeleteShader(fShaderB);
GLfloat trangleY[] =
{
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.0f, 0.0f, 0.0f
};
GLfloat trangleB[] =
{
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.0f, 0.0f, 0.0f
};
GLuint VBO[2], VAO[2];
glGenVertexArrays(2, VAO);
glGenBuffers(2, VBO);
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(trangleY), trangleY, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(trangleB), trangleB, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderYellow);
glBindVertexArray(VAO[0]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glUseProgram(shaderBlue);
glBindVertexArray(VAO[1]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
glDeleteVertexArrays(2, VAO);
glDeleteBuffers(2, VBO);
glfwTerminate();
return 0;
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}