Learn OpenGL(一)--简介与创建窗口

opengl_logo

代码Github地址

OpenGL 简介

  OpenGL是一个由Khronos Group维护的图形绘制的规范
  OpenGL规范规定了函数的执行、输出,但是具体的实现则是由库的开发者(通常指显卡生产商)来实现的,不同的库实现可能不一样
  OpenGL本质上是一个大状态机,通过改变上下文(context)的变量告诉OpenGL怎么绘图

创建窗口(GLFW)

创建窗口可以使用GLUT,SDL,QT,GLFW等,这里我用的是GLFW

GLFW

  GLFW是个开源的支持多个平台的库,支持OpenGL、Vulkan。提供创建窗口、事件接收等。

GLFW安装

头文件添加

1
#include <GLFW\glfw3.h>

  gcc 在编译时需要加入-lGLEW -lglfw3 -lGL -lX11 -lpthread -lXrandr -lXi,否则可能出现未定义的引用错误

待完成

GLAD

  因为OpenGL只是个规范,具体是由显卡驱动开发商决定,很多函数位置不能在编译时决定,自己来取得地址的话会导致代码很复杂,所以需要使用GLAD来帮我们实现

GLAD配置

  GLAD有一个在线服务可以根据语言、版本、模式来获取我们想要的库。打开后,语言选择C/C++,模式选择core,版本选择3.3(因为我用的是3.3版本)
  把生成的压缩文件解压,里面的glad和KHR目录放在你的项目头文件目录,glad.c也添加到工程中,并在项目引入头文件

1
#include <glad/glad.h>

CMakeLists.txt

  由于我使用的CLion创建的项目,所以也就使用CMake了,CMakeLists.txt部分内容如下
添加glad库

1
add_library(glad SHARED ./src/glad/glad.c)

添加stb_image(加载图片用)

1
add_library(stb_image SHARED ./src/stb_image/stb_image.cpp)

链接库(opengl_glfw03是项目可执行文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
target_link_libraries(opengl_glfw03 glad)
target_link_libraries(opengl_glfw03 stb_image)
target_link_libraries(opengl_glfw03 GLEW)
target_link_libraries(opengl_glfw03 glfw3)
target_link_libraries(opengl_glfw03 GL)
target_link_libraries(opengl_glfw03 X11)
target_link_libraries(opengl_glfw03 pthread)
target_link_libraries(opengl_glfw03 Xrandr)
target_link_libraries(opengl_glfw03 Xi)
target_link_libraries(opengl_glfw03 Xxf86vm)
target_link_libraries(opengl_glfw03 Xinerama)
target_link_libraries(opengl_glfw03 Xcursor)
target_link_libraries(opengl_glfw03 rt)
target_link_libraries(opengl_glfw03 m)
target_link_libraries(opengl_glfw03 dl)

main.cpp

编译没问题的话就可以创建窗口了

1
2
3
4
5
6
7
8
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>

int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}

开始创建窗口

  • 初始化GLFW
1
glfwInit();
  • GLFW选项设置函数
    hint:需要设置的选项
    value:需要设置的值
1
glfwWindowHint(int hint,int value);
  • 配置上下文版本为3.3
1
2
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);
  • 配置OpenGL模式为核心(core)模式
1
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
  • 配置多重采样实现抗锯齿
1
glfwWindowHint(GLFW_SAMPLES,4);

别忘了启用OpenGL的多重采样,虽然默认是启用的

1
glEnable(GL_MULTISAMPLE);
  • 创建窗口对象
    width:窗口宽度
    height:窗口高度
    title:窗口标题
    monitor
    share
1
glfwCreateWindow(int width,int height,const char *title,GLFWmonitor *monitor,GLFWwindow *share);
1
2
3
4
5
6
7
GLFWwindow *window=glfwCreateWindow(1200,720,"OpenGL",nullptr,nullptr);
if(window==nullptr){
// 当窗口创建失败时中断并退出
...
glfwTerminate();
return -1;
}
  • 将当前窗口设置为主线程上下文
1
glfwMakeContextCurrent(window);
  • 初始化GLAD
1
2
3
4
5
6
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
// 当GLAD初始化失败时退出
...
glfwTerminate();
return -1;
}
  • 添加窗口大小改变回调
1
2
3
4
// 声明回调函数
void onFramebufferSizeCallback(GLFWwindow*,int,int);
// 添加回调
glfwSetFramebufferSizeCallback(window,onFramebufferSizeCallback);
  • 在回调中处理视口变换
    x:左下角x坐标
    y:左下角y坐标
    width:渲染宽度
    height:渲染高度
1
glViewport(GLint x,GLint y,GLsizei width,GLsizei height);
1
2
3
void onFramebufferSizeCallback(GLFWwindow *window,int width,int height){
glViewport(0,0,width,height);
}
  • 渲染循环
    为了避免一运行就退出
1
2
3
4
5
6
while(!glfwWindowShouldClose(window)){
// 交换颜色缓冲
glfwSwapBuffers(window);
// 检查触发事件
glfwPollEvents();
}
  • 清除窗口颜色缓冲
    red:红
    green:绿
    blue:蓝
    alpha:透明通道
1
glClearColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha);

写在处理键盘事件代码之后

1
2
3
4
// 用glClearColor设置的颜色填充
glClearColor(0.5f,0.5f,0.6f,1.0f);
// 清除颜色缓冲
glClear(GL_COLOR_BUFFER_BIT);
  • 处理键盘事件
    声明函数
1
void onKeyInput(GLFWwindow *);

处理键盘事件写在循环体内部第一行

1
onKeyInput(window);
1
2
3
4
5
6
7
void onKeyInput(GLFWwindow *window){
// 判断ESC按钮就是否触发
if(glfwGetKey(window,GLFW_KEY_ESCAPE)==GLFW_PRESS){
// 触发就设置close为真
glfwSetWindowShouldClose(window,GLFW_TRUE);
}
}
  • 清理资源并退出
1
2
glfwTerminate();
return 0;

最后

此时运行代码应该会出现一个窗口像下面这个,按ESC即可退出,后面会在此基础上添加很多东西
代码Github地址
opengl_window