其实这个在以前的博文中介绍了很多次了,不过有基于GLut的有基于glew的,这次再详细记录一下以及它们的区别,以及当前最流行的选择;
其实GLUT跟glew都没问题, 只是目前主流会采用glad,窗口选用GLFW或者SDL,不过我还是喜欢GLFW + GLAD组合。
1、GLAD
由于OpenGL只是一个标准规范,具体实现是有驱动开发提供,也就是显卡制造方实现,而且OpenGL驱动版本非常众多,不同显卡方维护自己的一套,而且从1.0、2.* ,3.*,4.*..以及到近期的Vulkan,这样它的大多数函数的位置都无法再编译时候确定,需要在运行时查询。所以开发者就需要在运行时候获取函数地址并将其保存在一个函数指针中供以后使用。
以前大家基本基于GLEW来加载OpenGL函数,现在GLAD逐渐成为主流,why,体验一下就明白了,哈哈;当然这两个都你可以不使用,在不使用的情况下,在windows下调用一个opengl函数方法如下:
// 定义函数原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正确的函数并赋值给函数指针
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 此时函数可以被正常调用了
GLuint buffer;
glGenBuffers(1, &buffer);
所以GLEW或GLAD就是帮开发者完成这个事情的。
GLAD还用之处在于它是个在线服务,可以根据需要定义的OPenGL版本来加载的opengl函数以及扩展;
GlAD的在线服务地址:https://glad.dav1d.de/
如图所示:语言设置为C/C++,API选择,模式选择为Core,勾选Generate a loader,最后点击生成。
Glad的提供给你一个zip压缩包,解压后有include还有src目录;
使用如下:
include
文件下的两个目录复制到系统 include
目录下,比如,在 Mac
下就是 /usr/local/include/
目录。src
目录下的 glad.c
添加到你的工程当中去。#include
是不是比GLEW灵活?当然GLEW要么加载编译好的库,要么自己编译。最终使用也是加一个头文件,调用一下glewinit();
2、GLFW
GLFW 是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文,创建窗口以及处理用户输入。顺带一提:GLWF 支持 windows,MacOS 和 Linux。
在 Windows 下,在 GLFW 的下载页 GLFW 可以下载到二进制版本和相应的头文件,也可以下载源码自己编译,并不复杂,需要 CMake,或者直接将工程加到你的工程,调用它的CMAKE就可以。
在 Mac 下也可以编译 GLFW,但是,这里我们选择一种更为方便的方式:homebrew。如果你还不会使用 homebrew,请看《Homebrew 简介和基本使用》。
安装 glfw:
brew install glfw3
C++ 文件中使用,需要引入头文件:
#include
详细使用官网就有demo,可以在官网看到;
贴一个效果:
代码如下:
#include
#include
using namespace std;
#include
#include
// 窗口尺寸变化回调函数
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
// 处理用户输入
void process_input(GLFWwindow *window);
int main(int argc, char const *argv[])
{
// 初始化环境
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Mac os
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
GLFWwindow *window = glfwCreateWindow(800, 600, "Hello OpenGL", NULL, NULL);
if (window == NULL)
{
cout << "Failed to create window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// 加载 glad
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout << "Glad init faild!!!" << endl;
return -1;
}
// 创建顶点着色器
string vertex_shader_code = "#version 410 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main() {\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\n";
uint32_t vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
const GLchar *source(vertex_shader_code.c_str());
glShaderSource(vertexShader, 1, &source, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, sizeof(infoLog), NULL, infoLog);
cout << "VERTEX SHADER COMPILE ERROR: " << infoLog << endl;
}
// 创建片段着色器
string frag_shader_code = "#version 410 core\n"
"out vec4 FragColor;\n"
"void main() {\n"
" FragColor = vec4(0.5f, 0.8f, 1.4f, 1.0f);\n"
"}\n";
uint32_t fragShader;
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar *fragSource(frag_shader_code.c_str());
glShaderSource(fragShader, 1, &fragSource, NULL);
glCompileShader(fragShader);
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragShader, sizeof(infoLog), NULL, infoLog);
cout << "FRAG SHADER COMPILE ERROR: " << infoLog << endl;
}
// 创建着色器程序
uint32_t shaderProgram;
shaderProgram = glCreateProgram();
// 链接着色器
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, sizeof(infoLog), NULL, infoLog);
cout << "SHADER PROGRAM LINK ERROR: " << infoLog << endl;
}
// 删除着色器对象
glDeleteShader(vertexShader);
glDeleteShader(fragShader);
// 数据准备
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f};
uint32_t VAO, VBO;
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(float), (void *)0);
glEnableVertexAttribArray(0);
// 渲染循环
while (!glfwWindowShouldClose(window))
{
process_input(window);
glClearColor(0.3f, 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;
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
void process_input(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
Enjoy it~