本节内容

  • OpenGl简要介绍
  • 创建第一个窗口

OpenGl简要介绍

什么是OpenGl

OpenGl是一个规范,虽然一般被认为是一个API,但其本身并不负责实现.

OpenGl严格规定每个函数如何执行以及输出值,内部具体实现则由OpenGl库开发者完成.而其开发者一般为显卡厂商.

核心模式 && 立即渲染模式

立即渲染模式被时代抛弃

核心模式更自由,是主流

扩展(Extension)

为了开发者不必等待新的规范发布,通过检查显卡是否支持某些功能,来实现更好的优化和别的特性

状态机

OpenGL本身是一个大状态机,根据自身的状态来执行操作

对象

对象是一个结构体

Hello World,创建第一个窗口

首先需要:

  1. 创建OpenGl上下文
  2. 创建窗口

由于这两个步骤在不同平台上都不一样,并且OpenGL有意将其抽象出去,所以需要我们自己进行处理.当然,这一步已经有许多成熟的开源库为我们处理好了.

GLFW

GLFW是一个c语言库,它可以创建OpenGL上下文,定义窗口,处理输入

GLAD

由于OpenGL只是一个规范,具体实现需要驱动开发者根据显卡进行实现,导致OpenGL驱动版本众多,从而导致大部分函数无法在编译时确定而需要在运行时查询,所以任务又落到了开发者身上:开发者需要在运行时获取函数地址并存储在一个函数指针中以供使用(方法因平台而异),而这一操作确实无聊繁琐.GLAD正是这个问题的救世主

使用VS Code 配置环境

  1. 设置文件目录如下

    C:OPENRENDER
    ├───Source
    │ ├───Include
    │ └───Src
    └───ThirdParty

    git init

    git init

    创建CMakeLists.txt文件和README.md文件

    touch CMakeLists.txt
    touch README.md

    按需添加LICENSE文件

  2. 配置GLFW

    cd ThirdParty
    git clone https://github.com/glfw/glfw.git
  3. GLAD

    打开GLAD网站下载对应版本文件

    将文件放入ThirdParty目录下,并添加CMakeLists.txt文件

    set(CMAKE_CXX_STANDARD 17)

    file(GLOB_RECURSE source CONFIGURE_DEPENDS "src/*.c" "src/*.h")

    add_library(glad ${source})

    target_include_directories(glad PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

  4. 在根目录下创建CMakelists.txt文件

    cmake_minimum_required(VERSION 3.10)

    project(
    OpenRender
    LANGUAGES CXX
    )

    set(CMAKE_BUILD_TYPE Release)

    add_subdirectory(ThirdParty/glfw)
    add_subdirectory(ThirdParty/glad)

    add_subdirectory(Source)

    编写Source文件夹下的CMakeLists.txt文件

    set(CMAKE_CXX_STANDARD 17)

    file(GLOB_RECURSE source CONFIGURE_DEPENDS "src/*.cpp" "src/*.h")

    add_executable(OpenRender ${source})

    target_include_directories(OpenRender PUBLIC include)

    target_link_libraries(OpenRender glad glfw)
  5. 在Souce文件夹中创建main.cpp文件编译运行,检查第三方库是否正确链接

    #include <iostream>
    #include <glad/glad.h>
    #include <GLFW/glfw3.h>

    int main()
    {
    if (!glfwInit())
    {
    std::cout << "Failed to initialize GLFW" << std::endl;
    return -1;
    }

    glfwTerminate();
    return 0;
    }

创建窗口

在main.cpp中添加如下代码

#include <iostream>
#include "glad/glad.h" //glad 必须在Glfw前加载
#include "Glfw/glfw3.h"

//窗口大小变化回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}

//输入处理函数
void ProcessInput(GLFWwindow* window)
{
//按下ESC键退出程序
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}

int main()
{
//初始化glfw
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 设置opengl主版本为3
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // 设置opengl次版本为3
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //告诉GLFW 我们使用的是核心模式
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

//创建窗口
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL-BickRenderer", NULL, NULL);//创建窗口,800*600为窗口大小,LearnOpenGL为窗口标题
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();//终止glfw
return -1;
}
glfwMakeContextCurrent(window);//通知GLFW将此窗口的上下文设置为当前线程的主上下文

//初始化GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))//TODO: 这里暂时不是很清楚
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}

//设置Viewport
glViewport(0, 0, 800, 600);//左下角坐标为(0,0),右上角坐标为(800,600)
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//设置窗口大小变化回调函数

//渲染循环
while(!glfwWindowShouldClose(window))//窗口应该关闭时结束循环
{
//输入
ProcessInput(window);//处理输入

//渲染
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置清空屏幕使用的颜色,是一个状态设置函数
glClear(GL_COLOR_BUFFER_BIT);//清空颜色缓冲,是一个状态使用函数,获取状态后执行

//交换缓冲,检查并调用事件回调函数
glfwSwapBuffers(window); //交换颜色缓冲
glfwPollEvents(); //检查是否触发事件(输入),更新窗口状态,调用对应回调函数
}

glfwTerminate(); //终止glfw
}

由于GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h),所以需要在其它依赖于OpenGL的头文件之前包含GLAD

运行程序,已经可以看到一个窗口了.

第一个窗口