01、缓冲区与顶点属性:
- 之前我们实现了,在屏幕中心上绘制了一个点,而且这个点是固定值不能修改的,现在我们想一次绘制多个点,应该怎么做呢?需要使用顶点缓冲区进行数据传递
- OpenGL中想要绘制一个图形,需要将图形的顶点数据发送给顶点着色器。
- 通常做法会将顶点数据在C++端放入一个缓冲区,并把这个缓冲区和着色器中声明的顶点属性相关联(gl_Position)
02、VAO,VBO
- VBO(Vertex Buffer Object:顶点缓冲对象),在OpenGL中缓冲区被包含在VBO中,VBO在OpenGL应用程序中声明和实例化。
- VAO(Vertex Array Object:顶点数组对象),之前我们有使用过,作为一种组织缓冲区的方法,OpenGL程序中至少需要创建一个VAO
缓冲区与顶点属性交互方式:
- 当调用glDrawArrays()方法时,缓冲区中的数据开始流动,从缓冲区的开头开始按顺序流过顶点着色器,顶点着色器对每个顶点执行一次。
03、GLSL中设置顶点属性
"#version 410 \n"
"layout(location=0) in vec3 position; \n"
"void main(void){ \n"
" gl_Position = vec4(position, 1.0); \n"
"} \n";
- 解析:
- #version 410:表示当前电脑支持的OpenGL版本
- layout(location=0) in vec3 position;
- layout (location=0)称为“layout修饰符”,也就是我们把顶点属性和特定缓冲区关联起来的方法。这意味着,这个顶点属性的识别号是0,我们后面会用到
- 关键字in意思是输入(input),表示这个顶点属性将会从缓冲区中接收数值,vec3的意思是着色器每次调用会抓取3个浮点类型数值(用于表示顶点数据的X,Y,Z轴的坐标),变量名字为position
04、顶点数据放到缓冲区中并于顶点属性关联
- a、准备三个顶点坐标数据
float vPositions[9] = {
0.0, 0.5, 0.0,
-0.5,-0.5, 0.0,
0.5,-0.5, 0.0,
};
- b、创建VAO,和VBO
- glGenVertexArrays和glGenBuffers方法会创建VAO和VBO,创建成功会将缓冲区的整数型id值保存到数组vao和vbo中
- glBindVertexArray和glBindBuffer方法会将创建的缓冲区标记为活跃
- glBufferData方法会将顶点数据的数组复制到活跃缓冲区中,
GLuint vao[1];
GLuint vbo[2];
// 创建vao,并绑定
glGenVertexArrays(1, vao);
glBindVertexArray(vao[0]);
// 创建顶点缓冲对象vbo
glGenBuffers(2,vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// 将数据填充到缓冲区对象中
glBufferData(GL_ARRAY_BUFFER,sizeof(vPositions),vPositions,GL_STATIC_DRAW);
- c、将活跃的缓冲区数据关联到顶点属性
- glVertexAttribPointer方法的第一个参数为0,表示将缓冲区中的数据关联到顶点属性(location=0)的position中
- glEnableVertexAttribArray方法是启动顶点属性
// 标记第0个缓冲区为“活跃”
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// 将第0个属性关联到缓冲区
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// 启用第0个顶点属性
glEnableVertexAttribArray(0);
- d、最后我们执行glDrawArrays 方法时,第0个VBO中的数据将会传递给拥有位置为0(location=0)layout修饰符的顶点属性中。
05、齐次坐标
- 在GLSL代码中发现最后传递给gl_Position的数据是一个vec4的变量(gl_Position = vec4(position, 1.0);)
- 明明一个坐标数据只有xyz三个轴,为什么还需要使用第四个分量呢?
- 由四个分量组成的矢量被称为齐次坐标,它能够提高处理三维数据的效率
- 虽然齐次坐标是思维的,但是如果最后一个分量是1.0,那齐次坐标可以表示前三个分量为坐标值的那个点,比如齐次坐标(x,y,z,w)等价于(x/w, y/w, z/w)
06、实战-画三个点
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
GLuint renderProgram;
GLuint vao[1];
GLuint vbo[2];
// 创建着色器程序
GLuint createShaderProgram(){
const char *vertex_shader =
"#version 410 \n"
"layout(location=0) in vec3 position; \n"
"void main(void){ \n"
" gl_Position = vec4(position, 1.0); \n"
"} \n";
const char *fragment_shader =
"#version 410 \n"
"out vec4 color; \n"
"void main(void){ \n"
" color = vec4(1.0, 0.0, 0.0, 1.0); \n"
"} \n";
// 创建着色器对象
GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
// 创建着色器程序
GLuint vfProgram = glCreateProgram();
// 加载着色器代码
glShaderSource(vShader, 1, &vertex_shader, NULL);
glShaderSource(fShader, 1, &fragment_shader, NULL);
// 编译着色器对象
glCompileShader(vShader);
glCompileShader(fShader);
// 着色器程序绑定着色器对象(两个)
glAttachShader(vfProgram, vShader);
glAttachShader(vfProgram, fShader);
// 链接着色器程序
glLinkProgram(vfProgram);
return vfProgram;
}
void init(GLFWwindow* window) {
renderProgram = createShaderProgram();
float vPositions[9] = {
0.0, 0.5, 0.0,
-0.5,-0.5, 0.0,
0.5,-0.5, 0.0,
};
// 创建vao,并绑定
glGenVertexArrays(1, vao);
glBindVertexArray(vao[0]);
// 创建顶点缓冲对象vbo
glGenBuffers(2,vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// 将数据填充到缓冲区对象中
glBufferData(GL_ARRAY_BUFFER,sizeof(vPositions),vPositions,GL_STATIC_DRAW);
}
void display(GLFWwindow* window, double currentTime) {
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(renderProgram);
// 将vbo中关联的顶点数据取出来使用
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,0,0);
glEnableVertexAttribArray(0);
glPointSize(30.0);
glDrawArrays(GL_POINTS, 0, 3);
}
int main(void) {
if (!glfwInit()) {
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(600, 600, "OpenGL Demo", NULL, NULL);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
exit(EXIT_FAILURE);
}
glfwSwapInterval(1);
init(window);
while (!glfwWindowShouldClose(window)) {
display(window, glfwGetTime());
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
- 效果图
0602-实战2:画个三角形
- 还是使用上面的三个顶点数码,将三个点连接起来形成一个三角形即可,使用很简单,调用glDrawArrays 方法时,第一个参数设置为GL_TRIANGLES
glDrawArrays(GL_TRIANGLES, 0, 3);
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END