01 入门

发布时间 2023-05-03 16:57:01作者: ETHERovo

一、OpenGL

1. 核心模式与立即渲染模式

  • 早期的OpenGL使用立即渲染模式(Immediate mode,也就是固定渲染管线),OpenGL的大多数功能都被库隐藏起来。
  • 从OpenGL3.2开始,规范文档开始废弃立即渲染模式,并鼓励开发者在OpenGL的核心模式(Core-profile)下进行开发。

2. 扩展Extension

当一个显卡公司提出一个新特性或者渲染上的大优化,通常会以扩展的方式在驱动中实现。如果一个程序在支持这个扩展的显卡上运行,开发者可以使用这个扩展提供的一些更先进更有效的图形功能。通过这种方式,开发者不必等待一个新的OpenGL规范面世,就可以使用这些新的渲染特性了,只需要简单地检查一下显卡是否支持此扩展。

if(GL_ARB_extension_name)
{
    // 使用硬件支持的全新的现代特性
}
else
{
    // 不支持此扩展: 用旧的方式去做
}

3. 状态机

  • OpenGL的状态通常被称为OpenGL上下文(Context)
  • 状态设置函数(State-changing Function),这类函数将会改变上下文。以及状态使用函数(State-using Function),这类函数会根据当前OpenGL的状态执行一些操作

4. 对象

  • 可以看作C风格结构体
struct object_name {
    float  option1;
    int    option2;
    char[] name;
};
  • 一个例子
// OpenGL的状态
struct OpenGL_Context {
    ...
    object* object_Window_Target;
    ...     
};
// 创建对象
unsigned int objectId = 0;
glGenObject(1, &objectId);
// 绑定对象至上下文
glBindObject(GL_WINDOW_TARGET, objectId);
// 设置当前绑定到 GL_WINDOW_TARGET 的对象的一些选项
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
// 将上下文对象设回默认
glBindObject(GL_WINDOW_TARGET, 0);
  • 好处在于,可以定义多个对象,有选择地绑定,不需要重复设置选项。

二、创建窗口

  • 首先要做的就是创建一个OpenGL上下文(Context)和一个用于显示的窗口。

1. GLFW

GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入。

2. CMAKE

  • CMake需要一个源代码目录和一个存放编译结果的目标文件目录。源代码目录我们选择GLFW的源代码的根目录,然后我们新建一个 build 文件夹,选中作为目标目录。
  • 在设置完源代码目录和目标目录之后,点击Configure(设置)按钮,让CMake读取设置和源代码。
  • 选择工程的生成器
  • CMake会显示可选的编译选项用来配置最终生成的库。这里我们使用默认设置,并再次点击Configure(设置)按钮保存设置。
  • 保存之后,点击Generate(生成)按钮,生成的工程文件会在你的build文件夹中。

3. 编译

  • 在build文件夹里可以找到GLFW.sln文件,用Visual Studio 2019打开。因为CMake已经配置好了项目,并按照默认配置将其编译为64位的库,所以我们直接点击Build Solution(生成解决方案)按钮,然后在build/src/Debug文件夹内就会出现我们编译出的库文件glfw3.lib。
  • 建立一个新的目录里面包含Libs和Include文件夹,包含所有的第三方库文件和头文件,并且在你的IDE或编译器中指定这些文件夹。

4. 链接

  • 添加incluce目录与lib目录:VC++ Direction->Library Directions or Include Directions

  • 链接lib文件,Linker->Additional Depedences;除了glfw3.lib之外,还有opengl32.lib。
  • 添加头文件
#include <GLFE\glfw3.h>

5. GLAD

  • 因为OpenGL只是一个标准/规范,具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。
// 定义函数原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正确的函数并赋值给函数指针
GL_GENBUFFERS glGenBuffers  = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 现在函数可以被正常调用了
GLuint buffer;
glGenBuffers(1, &buffer);
  • GLAD是一个开源的库,它能解决我们上面提到的那个繁琐的问题。
  • 打开GLAD的在线服务,将语言(Language)设置为C/C++,在API选项中,选择3.3以上的OpenGL(gl)版本(我们的教程中将使用3.3版本,但更新的版本也能用)。之后将模式(Profile)设置为Core,并且保证选中了生成加载器(Generate a loader)选项。现在可以先(暂时)忽略扩展(Extensions)中的内容。都选择完之后,点击生成(Generate)按钮来生成库文件。
  • GLAD现在应该提供给你了一个zip压缩文件,包含两个头文件目录,和一个glad.c文件。将两个头文件目录(glad和KHR)复制到你的Include文件夹中(或者增加一个额外的项目指向这些目录),并添加glad.c文件到你的工程中。
  • 包含头文件
#include <glad/glad.h>

3. 你好,窗口

  • 请确认是在包含GLFW的头文件之前包含了GLAD的头文件。GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h),所以需要在其它依赖于OpenGL的头文件之前包含GLAD。
#include <glad/glad.h>
#include <GLFW/glfw3.h>