在刚刚学习了现代OpenGL后,想做一些好玩的东西。这是第一个,想做两个三角形,然后这两个三角形的颜色会一直变化,就能达到闪烁的效果。
- 绘制两个不同颜色的三角形的话,首先应该将顶点的索引分成两个ibo对象,然后通过两个vao对象来进行绑定,而顶点数据vbo对象可以共用两个,只不过需要在两个vao对象上分别绑定一次;
- 不同颜色的三角形,则需要两个不同的片段着色器(疑问:能否只用同一个片段着色器达到两种不同的颜色?),然后分别在不同的FragmentShader中设置不同的颜色,然后在窗口循环中进行渲染时,分别对两个vao进行渲染前使用不同的ShaderProgram以及绑定两个vao对象即可;
- 如果想让三角形的颜色变化起来,也就是在每次循环渲染时改变着色器的颜色设置。可以通过uniform来获得两个片段着色器中的颜色变量,然后在着色器程序外部对片段着色器中的颜色变量进行赋值,从而达到每次渲染时颜色变化的效果。
代码如下:(这些代码看起来有点乱,没有抽象化,不符合面向对象编程的风格,但是对于整个OpenGL的渲染管线的理解来说比抽象出来更加容易理解)
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(640, 480, "Rectangle", nullptr, nullptr);
glfwMakeContextCurrent(window);
std::cout << glGetString(GL_VERSION) << std::endl;
glewInit();
unsigned int vao1;
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
std::vector<float> vertices = {
-0.5f, -0.5f, // 0
0.5f, -0.5f, // 1
0.5f, 0.5f, // 2
-0.5f, 0.5f // 3
};
unsigned int vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
std::vector<int> indices1 = {
0, 1, 2
};
unsigned int ibo1;
glGenBuffers(1, &ibo1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo1);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * sizeof(unsigned int), &indices1[0], GL_STATIC_DRAW);
unsigned int vao2;
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
std::vector<int> indices2 = {
2, 3, 0
};
unsigned int ibo2;
glGenBuffers(1, &ibo2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo2);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * sizeof(unsigned int), &indices2[0], GL_STATIC_DRAW);
const char* vertexShaderSource = "#version 330 core\n"
"layout(location = 0) in vec4 pos;\n"
"void main()\n"
"{\n"
" gl_Position = pos;\n"
"}\0";
unsigned int vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertexShaderSource, nullptr);
glCompileShader(vs);
int success;
glGetShaderiv(vs, GL_COMPILE_STATUS, &success);
if (!success)
{
char message[512];
glGetShaderInfoLog(vs, 512, nullptr, message);
std::cout << message << std::endl;
}
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"uniform vec4 u_Color;\n"
"void main()\n"
"{\n"
" color = u_Color;\n"
"}\0";
unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragmentShaderSource, nullptr);
glCompileShader(fs);
const char* fragmentShaderSource1 = "#version 330 core\n"
"out vec4 color;\n"
"uniform vec4 u_Color;\n"
"void main()\n"
"{\n"
" color = u_Color;\n"
"}\0";
unsigned int fs1 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs1, 1, &fragmentShaderSource1, nullptr);
glCompileShader(fs1);
unsigned int program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
int result;
glGetProgramiv(program, GL_LINK_STATUS, &result);
if (!result)
{
char info[512];
glGetProgramInfoLog(program, 512, nullptr, info);
std::cout << info << std::endl;
}
unsigned int program1 = glCreateProgram();
glAttachShader(program1, vs);
glAttachShader(program1, fs1);
glLinkProgram(program1);
glUseProgram(program1);
glDeleteShader(vs);
glDeleteShader(fs);
glDeleteShader(fs1);
glBindVertexArray(0);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
int location1 = glGetUniformLocation(program, "u_Color");
ASSERT(location1 != -1);
int location2 = glGetUniformLocation(program1, "u_Color");
ASSERT(location2 != -1);
float r1 = 0.0f, r2 = 1.0f;
float increment1 = 0.05f, increment2 = 0.05f;
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao1);
glUseProgram(program);
glUniform4f(location1, r1, 0.2f, 0.8f, 1.0f);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(vao2);
glUseProgram(program1);
glUniform4f(location2, 0.4f, r2, 0.2f, 1.0f);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
glfwSwapBuffers(window);
glfwPollEvents();
if (r1 > 1)
increment1 = -0.05f;
else if (r1 < 0)
increment1 = 0.05f;
r1 += increment1;
if (r2 > 1)
increment2 = -0.05f;
else if (r2 < 0)
increment2 = 0.05f;
r2 += increment2;
}
glDeleteProgram(program);
glfwTerminate();
return 0;
}
效果: