参考https://learnopengl.com/
1、创建窗口
glfw是一个针对OpenGL的窗口管理库,这里使用glfw库创建窗口并处理输入,glfw库可以在它的官网上下载,提供了动态库和静态库供选择,也可以下载源码自己编译。以官方下载的静态库glfw3.lib为例,将下载的静态库复制到自己方便管理的路径,这里放在工程路径下的lib文件夹内,并将该文件路径添加到工程属性的依赖库里
将glfw3.h复制到工程目录下的glfw文件夹内,并在.cpp文件内包含该头文件#include "glfw/glfw3.h"
创建窗口的步骤:
(1)初始化glfw
glfwInit();
(2)配置OpenGL属性项
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint设置相应的属性,GLFW_CONTEXT_VERSION_MAJOR和GLFW_CONTEXT_VERSION_MINOR设置需要使用的OpenGL版本,这里选择3.3版本,GLFW_OPENGL_CORE_PROFILE表示我们使用core-profile版本,不需要兼容低版本特性
(3)创建窗口
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);//创建一个800x600大小的窗口
if (window == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//将window设置为当前窗口
(4)显示窗口并处理消息
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwWindowShouldClose判断窗口是否要关闭,点击关闭按钮的时候返回true,也就是退出循环
glfwSwapBuffers交换缓冲区,将要显示的像素颜色显示到屏幕
glfwPollEvents处理消息
(5)结束
最后调用glfwTerminate()即可。
最后代码合起来
#include "glfw/glfw3.h"
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(SCR_WIDTH, SCR_HEIGHT, "OpenGL", NULL, NULL);
if (window == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
2、画三角形
窗口创建后就可以在窗口上画出三角形了,这里需要用到OpenGL的api接口,如果自己写代码获取OpenGL动态库中的函数就太麻烦了,而且OpenGL有很多版本,不同版本的api也有区别。//顶点着色器代码:
#version 330 core //版本
layout (location = 0) in vec3 vertexPos; //顶点位置,由程序传入
void main()//着色器程序执行main函数
{
gl_Position = vec4(vertexPos, 1.0);//gl_Position为内部定义变量,表示顶点的位置
}
//片段着色代码:
#version 330 core
void main()
{
gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);//gl_FragColor为内部定义变量,表示像素的颜色
}
(2)创建和编译着色器
GLuint CreateShader(GLuint type,const GLchar* source)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);//获取编译结果
if (!success)
{
char infoLog[512];
glGetShaderInfoLog(shader, 512, NULL, infoLog);//获取具体错误描述infoLog
std::cout << infoLog << std::endl;
}
return shader;
}
假设顶点着色器程序字符串为const GLchar* vsSource,片段着色器程序字符串为const GLchar* fsSource,则创建顶点着色器和片断着色器的代码分别为
GLuint CreateShaderProgram(const GLchar* vsSource,const GLchar* fsSource)
{
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER,vsSource);
GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER,fsSource);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success)
{
char infoLog[512];
glGetProgramInfoLog(program, 512, NULL, infoLog);
std::cout << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return program;
}
(4)将三角形顶点数据传入着色器
GLfloat vertices[] =
{
-0.5f, 0.5f, 0.0f, // 1
-0.5f, -0.5f, 0.0f, // 2
0.5f, -0.5f, 0.0f, // 3
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);//创建顶点数组对象
glGenBuffers(1, &VBO);//创建顶点缓冲
glBindVertexArray(VAO);//设置当前顶点数组对象为VAO
{
glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定VBO到GL_ARRAY_BUFFER
{
//将定点数据赋值给GL_ARRAY_BUFFER,也就是VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//将缓冲中的顶点数据和vertexPos关联起来,这里是通过第一个参数0和着色器中的location=0关联的
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);//取消VBO绑定
}
glBindVertexArray(0);//取消VAO绑定
为了看起来清晰,将部分代码用{}括起来,后面只要使用VAO就可以获取到顶点数据,OpenGL的坐标范围为-1到1
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//设置清除颜色
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);//shaderProgram为CreateShaderProgram返回的着色器程序
glBindVertexArray(VAO); //绑定VAO
glDrawArrays(GL_TRIANGLES, 0, 3);//画三角形
(6)结束
运行结果:
附上完整代码:#include "glad/glad.h"
#include "glfw/glfw3.h"
#include
const GLchar *vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 vertexPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(vertexPos, 1.0);\n"
"}\0";
const GLchar *fragmentShaderSource =
"#version 330 core\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
"}\n\0";
GLuint CreateShader(GLuint type, const GLchar* source)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
char infoLog[512];
glGetShaderInfoLog(shader, 512, NULL, infoLog);
std::cout << infoLog << std::endl;
}
return shader;
}
GLuint CreateShaderProgram(const GLchar* vsSource, const GLchar* fsSource)
{
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, vsSource);
GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER, fsSource);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success)
{
char infoLog[512];
glGetProgramInfoLog(program, 512, NULL, infoLog);
std::cout << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return program;
}
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", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
return -1;
}
GLuint shaderProgram = CreateShaderProgram(vertexShaderSource,fragmentShaderSource);
GLfloat vertices[] = {
-0.5f, 0.5f, 0.0f, // 1
-0.5f, -0.5f, 0.0f, // 2
0.5f, -0.5f, 0.0f, // 3
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
{
glBindBuffer(GL_ARRAY_BUFFER, VBO);
{
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}