绘制图形的大致流程
图中,浅蓝色方格是整个过程中的重要对象。
准备顶点坐标,创建VAO,并将坐标存入VBO
GLfloat vertices[] = { // 顶点位置
-0.5, -0.5, 0,
0.5, -0.5, 0,
0, 0.5, 0
};
unsigned int VAO; // 用以储存当前VBO和顶点属性
glGenVertexArrays(1, &VAO); // 创建一个顶点数组对象
glBindVertexArray(VAO); // 绑定顶点数组对象,这样后面的VBO才会被记录
unsigned int VBO;
glGenBuffers(1, &VBO); // 生成一个缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 将缓冲对象与顶点缓冲区VAO绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将数据写入顶点缓冲区,第四个参数描述了数据在未来是否会发生剧烈改变, GL_STATIC_DRAW 代表几乎不会改变
创建顶点着色器对象
const char* vertexShaderSource = "#version 330 core\n" // 顶点着色器的源码
"layout (location = 0) in vec3 aPos;\n"
"void main(){\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER); // 创建一个顶点着色器对象
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // 将着色器对象与源码进行装配。第二个参数为着色器源码的数量。
glCompileShader(vertexShader); // 编译着色器
GLint issuccess;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &issuccess); // 检查编译是否成功
if(!issuccess){
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); // 如果编译失败则获得错误信息
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
abort();
}
创建片段着色器对象
const char* fragmentShaderSource = "#version 330 core\n" // 片段着色器源码
"out vec4 FragColor;\n"
"void main(){\n"
" FragColor = vec4(1.0, 0.5, 0.2, 1.0);\n"
"}\0";
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); // 创建一个片段着色器对象
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); // 将片段着色器与源码进行装配
glCompileShader(fragmentShader); // 编译片段着色器
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &issuccess); // 检查编译是否成功
if(!issuccess){
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); // 如果编译失败则获得错误信息
std::cout << "ERROR::SHADER::FRAGEMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
abort();
}
创建程序对象
unsigned int shaderProgram;
shaderProgram = glCreateProgram(); // 创建一个程序对象
glAttachShader(shaderProgram, vertexShader); // 让程序对象包含的那个点着色器
glAttachShader(shaderProgram, fragmentShader); // 让程序对象包含片段着色器
glLinkProgram(shaderProgram); // 链接程序
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &issuccess); // 检查链接是否成功
if(!issuccess){
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); // 失败时获得报错信息
std::cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n" << infoLog << std::endl;
abort();
}
声明顶点的内存排列形式
glDeleteShader(vertexShader);glDeleteShader(fragmentShader); // 删除不再需要的着色器对象
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (void*)0); // 告诉 openGL 我们的顶点数据的内存排列形式。参数:起始位置、每组数据个数、数据类型、是否归一化、每一组数据的大小、起始位置序号的指针。
glEnableVertexAttribArray(0); // 启用顶点属性
这里的起始位置是 0 是因为我们在顶点着色器中声明了 location = 0
绘制三角形
// 主循环
while(!glfwWindowShouldClose(window)){
// 检查输入
...
// 渲染
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram); // 激活程序对象
glBindVertexArray(VAO); // 指定使用的顶点数组对象
glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形。参数:图形模式、数据起点、点个数
// 更新
glfwSwapBuffers(window);
glfwPollEvents();
}
整体代码
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
void frameBufferSizeCallback(GLFWwindow* window, int width, int height);
void checkInput(GLFWwindow* window);
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(800, 600, "opengl test window", NULL, NULL);
if(window==NULL){
std::cout<< "Failed to create window with glfw.\n";
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
std::cout<< "Failed to initalize glad.\n";
return -1;
}
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, frameBufferSizeCallback);
// 绘制
GLfloat vertices[] = { // 顶点位置
-0.5, -0.5, 0,
0.5, -0.5, 0,
0, 0.5, 0
};
unsigned int VAO; // 用以储存当前VBO和顶点属性
glGenVertexArrays(1, &VAO); // 创建一个顶点数组对象
glBindVertexArray(VAO); // 绑定顶点数组对象,这样后面的VBO才会被记录
unsigned int VBO;
glGenBuffers(1, &VBO); // 生成一个缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 将缓冲对象与顶点缓冲区VAO绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将数据写入顶点缓冲区,第四个参数描述了数据在未来是否会发生剧烈改变, GL_STATIC_DRAW 代表几乎不会改变
const char* vertexShaderSource = "#version 330 core\n" // 顶点着色器的源码
"layout (location = 0) in vec3 aPos;\n"
"void main(){\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER); // 创建一个顶点着色器对象
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // 将着色器对象与源码进行装配。第二个参数为着色器源码的数量。
glCompileShader(vertexShader); // 编译着色器
GLint issuccess;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &issuccess); // 检查编译是否成功
if(!issuccess){
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); // 如果编译失败则获得错误信息
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
abort();
}
const char* fragmentShaderSource = "#version 330 core\n" // 片段着色器源码
"out vec4 FragColor;\n"
"void main(){\n"
" FragColor = vec4(1.0, 0.5, 0.2, 1.0);\n"
"}\0";
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); // 创建一个片段着色器对象
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); // 将片段着色器与源码进行装配
glCompileShader(fragmentShader); // 编译片段着色器
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &issuccess); // 检查编译是否成功
if(!issuccess){
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); // 如果编译失败则获得错误信息
std::cout << "ERROR::SHADER::FRAGEMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
abort();
}
unsigned int shaderProgram;
shaderProgram = glCreateProgram(); // 创建一个程序对象
glAttachShader(shaderProgram, vertexShader); // 让程序对象包含的那个点着色器
glAttachShader(shaderProgram, fragmentShader); // 让程序对象包含片段着色器
glLinkProgram(shaderProgram); // 链接程序
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &issuccess); // 检查链接是否成功
if(!issuccess){
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); // 失败时获得报错信息
std::cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n" << infoLog << std::endl;
abort();
}
glDeleteShader(vertexShader);glDeleteShader(fragmentShader); // 删除不再需要的着色器对象
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (void*)0); // 告诉 openGL 我们的顶点数据的内存排列形式。参数:起始位置、每组数据个数、数据类型、是否归一化、每一组数据的大小、起始位置序号的指针。
glEnableVertexAttribArray(0); // 启用顶点属性
// 主循环
while(!glfwWindowShouldClose(window)){
// 检查输入
checkInput(window);
// 渲染
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram); // 激活程序对象
glBindVertexArray(VAO); // 指定使用的顶点数组对象
glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形。参数:图形模式、数据起点、点个数
// 更新
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
// g++ -o out main.cpp lib/glad.c -lglfw -lGL -lm -lXrandr -lXi -lX11 -lXxf86vm -lpthread -ldl -lXinerama -lXcursor
void frameBufferSizeCallback(GLFWwindow* window, int width, int height){glViewport(0, 0, width, height);}// 设置回调函数
void checkInput(GLFWwindow* window){
if(glfwGetKey(window, GLFW_KEY_ESCAPE)==GLFW_PRESS){
glfwSetWindowShouldClose(window, 1);
}
}
参考链接:你好,三角形
标签:fragmentShader,OpenGL,对象,vertexShader,Linux,顶点,三角形,GL,着色器 From: https://www.cnblogs.com/torch-hxm/p/17927927.html