Xcode与C++之游戏开发:OpenGL

上一篇:Xcode与C++之游戏开发:带有简单AI的塔防游戏
SDL 渲染器支持 2D 图形,但是不支持 3D 图形。为了同时支持 2D 和 3D,这里使用了著名的 OpenGL。

OpenGL 介绍

OpenGL(Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。底层图形库提供的接口用于渲染二维或者三维图形,可以说这些接口架起了上层应用程序和底层 GPU 之间的桥梁。应用程序使用这些接口发送渲染命令,而这些接口会向显卡驱动发送渲染命令。

切换到 OpenGL

在前面的章节里,使用的是 SDL_Renderer,现在要换成 OpenGL,就要把它移除掉了。在 Game.cpp 的实现中把原本的标志位 0 换成 OpenGL:

    // 创建 SDL 窗体
    mWindow = SDL_CreateWindow(
                               "OpenGL",       // 标题
                               100,               // 窗体左上角的 x 坐标
                               100,               // 窗体左上角的 y 坐标
                               1024,              // 窗体宽度
                               768,               // 窗体高度
                               SDL_WINDOW_OPENGL  // OpenGL
                               );

在创建 OpenGL 窗口之前,可以设置 OpenGL 相关的一些属性,比如色彩深度,版本等。要配置这些参数可以使用 SDL_GL_SetAttribute

    // 设置 OpenGL 参数
    // core OpenGL
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    // 指定版本 3.3
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    // RGBA
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
    // 双缓冲
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    // 强制使用硬件加速
    SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);

将之后的 SDL_Renderer 创建部分删除。接下来就是创建一个 OpenGL 上下文(context),可以把 context 理解成 OpenGL 世界。

添加一个成员变量到 Game 中:

SDL_GLContext mContext;

并在 Initialize 中进行初始化:

mContext = SDL_GL_CreateContext(mWindow);

有了 Create 自然需要有销毁,在 Shutdown 函数里添加析构,通用声明顺序和析取顺序相反,应该在 SDL_DeleteWindow 之前添加:

void Game::Shutdown()
{
   
    UnloadData();
    IMG_Quit();
    SDL_GL_DeleteContext(mContext);
    SDL_DestroyWindow(mWindow);
    SDL_Quit();
}

现在已经创建好了 OpenGL 的上下文,但还有一个问题。OpenGL 为了保持后向兼容,需要手动使用扩展才能使用 OpenGL 3.3。为了避免这个繁琐的过程,不妨使用 GLEW 库(OpenGL Extension Wrangler Library)。这样的话只要一个函数调用就可以获得支持的所有扩展功能,包括3.3 版本之前的功能。

GLEW 用起来还是挺方便的,就是去 GLEW官网 下载源文件,之后解压,一个 make 就自动编译了。使用 GLEW 的方式和之前添加 SDL 库一样了,添加库依赖,在 Build Settings 中加上头文件的路径。

要初始化 GLEW,可以添加下面的代码到创建 context 之后:

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
   
        SDL_Log("初始化 GLEW 失败!");
        return false;
    }

渲染一帧

渲染的原理和之前的 SDL 还是一样的,清除、绘制、交换缓冲区,使用 OpenGL 本质上就是换了个渲染器:

void Game::GenerateOutput()
{
   
    // 灰色
    glClearColor(0.86f, 0.86f, 0.86f, 1.0f);
    // 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    
    // TODO: 绘制场景
    
    // 交换缓冲区
    SDL_GL_SwapWindow(mWindow);
}

需要添加系统自带的 OpenGL 库
Xcode与C++之游戏开发:OpenGL_第1张图片

正常来讲,应该就可以看到一个灰色背景的 OpenGL 环境了,这也意味着我们把渲染器换成了 OpenGL 了。

Xcode与C++之游戏开发:OpenGL_第2张图片

渲染基础

2D 图形和 3D 图形其实没什么区别,因为本质上 3D 图形也是 2D图形,只不过它是被压平到了 2D 屏幕上。早期的一些 2D 游戏,比如说任天堂,会简单的把画面图像复制到颜色缓冲区,这个过程被称为 blitting(印迹)。然而,现在的硬件并不擅长干这种事情,但是在多边形渲染上却非常高效。因此,可以说现在所有的游戏,无论是 2D 还是 3D,最终都是用多边形来满足图形需求。

最简单的多边形是三角形,这是现在游戏最终的底层基础(四边形可以分解成两个三角形,五边形可以分解为3个三角形…)。多边形不仅计算简单,可以具有很好的伸缩性,如果设备性能不行,那么三角形绘制得少一些,这个技术也就是所谓的 HLOD(分层 LOD)。

规范化的设备坐标

NDC(Normalized device coordinates )是 OpenGL 默认的坐标系统。窗口的中心是坐标原点,左下角是 (-1,-1),右上角是 (1,1)。这个规范化的坐标体系与屏幕的实际高度和宽度无关。在渲染过程中,GPU(准确来说是图形硬件)会把 NDC 的坐标转为实际的像素位置。

在 3D 中,z 坐标分量范围也是从 -1 到 +1,正轴朝向屏幕内部。对于 2D,显然 z 分量为 0。

顶点和索引缓冲

如果有一个由三角形组成的 3D 模型,需要通过某种方式在内存中存储这些三角形的顶点。最简单粗暴就是直接存顶点,比如这样:

float vertices[] = {
   
    -0.5f,  0.5f, 0.0f,    
    0.5f,  0.5f, 0.0f

你可能感兴趣的:(游戏开发,opengl,c++,游戏开发)