OpenGL | 让一个三角形转起来
基本思路:
直接利用传给GPU的数据并行计算旋转后三角形的参数,而不需要bande passante entre CPU et GPU。
Sol: 利用uniform参数调节shaders,可以将其视为在CPU上运行的代码可以传递给图形卡着色器的变量,对于一个形状顶点的uniforms参数是常熟。
利用glUniformX
函数进行改变。
二维旋转用到的矩阵:
主要修改的部分:
Shader: 增加一个4维旋转矩阵R并作用于position,这个是对所有的物体作用的,即大家一起一个方向旋转。
#version 330 core
layout (location = 0) in vec4 position;
uniform mat4 R;
void main()
{
gl_Position = R*position;
}
旋转控制:
// ******************************** //
// Setup animation data
// ******************************** //
const float t = counter_drawing_loop/100.0f;
// create rotation matrix
const std::array<GLfloat,16> R = {
std::cos(t),-std::sin(t),0,0,
std::sin(t), std::cos(t),0,0,
0, 0,1,0,
0, 0,0,1
};
// ******************************** //
// Clear screen
// ******************************** //
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// ******************************** //
// Draw data
// ******************************** //
glUseProgram(shader_program);
glBindVertexArray(vao);
// Rotation
const GLint R_loc = glGetUniformLocation(shader_program, "R"); // Locate R uniform variable in the shader,因为shader中uniform变量名字为R
glUniformMatrix4fv(R_loc, 1, GL_TRUE, &R[0]); // Send rotation matrix R as uniform parameter R_loc
// Draw call
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 3, 3);
glBindVertexArray(0);
glUseProgram(0);
如果不使用glClear(GL_COLOR_BUFFER_BIT);
清屏的后果
在具体画之前,需要调用glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
- location: Localisation de la variable uniform renvoyée par la fonction
glGetUniformLocation
,如我们之前用的是const GLint R_loc = glGetUniformLocation(shader, "R");
- count: Nombre de paramètre uniforms à envoyer par cet appel. 我们这里只需要传递时间参数 t t t.
- transpose: Indique si la matrice doit être transposée une fois passée au shader. GLSL utilise une représentation par colonne, qui est la version transposée de la représentation implicitement utilisée lors de la définition de la matrice dans le programme principal. Nous plaçons ainsi ce paramètre à true. [因为默认是要转置,所以要设置为GL_True]
- value: Adresse du premier élément des données (rem. la matrice doit nécessairement être stockée sous la forme d’une suite de valeurs contigües en mémoire). Uniform真实数据来源
总结:
vertex_shader.glsl
:用于控制位置,图形大小
#version 330 core
layout (location = 0) in vec4 position;
uniform mat4 R;
void main()
{
gl_Position = R*position;
}
fragment_shader.glsl
:用于控制图形的颜色
#version 330 core
out vec4 FragColor;
uniform vec4 color;
void main()
{
FragColor = color;
// FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
uniform
变量的使用:
首先需要在shader中定义,并取一个变量名varName
然后在主要函数main中可以定义一个函数用于将数据传给shader中的varName
,常用std::array<GLfloat,16>
,std::vector<GLfloat>
定义具体的值在变量realVar
等,最后利用下面的代码将realVar
和varName
联系在一起,颜色设置默认对下一个物体有效。
// Locate R uniform variable in the shader
const GLint R_loc = glGetUniformLocation(shader_program, "R");
glUniformMatrix4fv(R_loc, 1, GL_TRUE, &R[0]); // Send rotation matrix as uniform parameter
// Color
const GLint color1_loc = glGetUniformLocation(shader_program, "color");
glUniform4fv(color1_loc, 1, &color1[0]);
部分代码:
int main()
{
std::cout<<"*** Init GLFW ***"<<std::endl;
glfw_init();
std::cout<<"*** Create window ***"<<std::endl;
auto window = glfw_create_window(500,500,"My Window");
glfwMakeContextCurrent(window);
std::cout<<"*** Init GLAD ***"<<std::endl;
glad_init();
print_opengl_information();
std::cout<<"*** Setup Data ***"<<std::endl;
load_data();
std::cout<<"*** Compile Shader ***"<<std::endl;
shader_program = create_shader_program("shaders/vertex_shader.glsl","shaders/fragment_shader.glsl");
std::cout<<"*** Start GLFW loop ***"<<std::endl;
while( !glfwWindowShouldClose(window) ) {
draw_data();
++counter_drawing_loop; // 在这里设置类似一个时间,用于更新R中的参数。
glfwSwapBuffers(window);
glfwPollEvents();
}
std::cout<<"*** Terminate GLFW loop ***"<<std::endl;
}
void draw_data()
{
// ******************************** //
// Setup animation data
// ******************************** //
const float t = counter_drawing_loop/100.0f;
// create rotation matrix
const std::array<GLfloat,16> R = {
std::cos(t),-std::sin(t),0,0,
std::sin(t), std::cos(t),0,0,
0, 0,1,0,
0, 0,0,1
};
const std::vector<GLfloat> color1 = {1.0f,0.0f,0.0f,0.0f};
const std::vector<GLfloat> color2 = {0.0f,1.0f,0.0f,0.0f};
// ******************************** //
// Clear screen
// ******************************** //
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// ******************************** //
// Draw data
// ******************************** //
glUseProgram(shader_program);
glBindVertexArray(vao);
// Rotation
const GLint R_loc = glGetUniformLocation(shader_program, "R"); // Locate R uniform variable in the shader
glUniformMatrix4fv(R_loc, 1, GL_TRUE, &R[0]); // Send rotation matrix as uniform parameter
// Color
const GLint color1_loc = glGetUniformLocation(shader_program, "color");
glUniform4fv(color1_loc, 1, &color1[0]);
// Draw call
glDrawArrays(GL_TRIANGLES, 0, 3);
const GLint color2_loc = glGetUniformLocation(shader_program, "color");
glUniform4fv(color2_loc, 1, &color2[0]);
glDrawArrays(GL_TRIANGLES, 3, 3);
glBindVertexArray(0);
glUseProgram(0);
}