跳转至

教程前言

Vulkan 技术概览

Vulkan 是什么

VulkanKhronos Group 推出的一款跨平台现代图形与计算 API。与传统 API (如OpenGLDirect3D)相比,它为显卡提供了更好的抽象,使你可以更好的描述应用的工作内容,从而减少意外的驱动程序行为并带来更好的性能。

DirectX 12 同样是现代图形 API ,但它仅限于 Windows 平台。

与传统 API 的关键差异

维度 OpenGL/D3D11 Vulkan
驱动开销 高(由驱动隐式管理状态) 低(需开发者显式声明)
线程模型 单线程主导 原生多线程支持
着色器编译 运行时GLSL编译 预编译SPIR-V字节码
内存管理 驱动自动分配 开发者控制内存类型

这些优势的代价是开发者必须显式管理更多细节,需要编写更多代码以确保行为正确。

什么人适合 Vulkan

Vulkan 并不适合所有人,它针对的是热衷于高性能计算机图形学并愿意投入一些工作的程序员。

如果您主要对游戏开发感兴趣,那么 OpenGL 或 Direct3D 可能更适合您,因为它们的上手难度相对较低,且在多数场景下仍然能够满足需求。

另一种选择是使用 Unreal EngineUnity 这样的游戏引擎。这些引擎可以利用 Vulkan 的高性能特性,同时为开发者提供更易用的高级 API,从而在不牺牲太多性能的前提下显著降低开发难度。

在实际开发中通常会通过一个“渲染硬件接口(RHI)”层对图形引擎进行抽象,但学习底层的引擎 API 仍有助于你理解渲染程序本身。

学习前提

硬件要求

  • 支持 Vulkan 的设备(大部分现代显卡都支持)
  • 较新的显卡驱动

软件技能

  • 熟练的现代 C++ 编程能力(RAII、初始化列表等)
  • CMake 和 vcpkg 基础使用经验

理论知识

  • 线性代数,微积分等数学基础
  • 3D 图形学基础知识

本教程不会教你 OpenGL 或 Direct3D 的概念,但它确实要求您了解 计算机图形学 的基础知识。例如,它不会解释透视投影背后的数学原理。

强烈推荐先修课程:GAMES101-现代计算机图形学入门

学习的开始

在编程语言中,常常将打印 Hello World! 作为学习的开始,而图形 API 的学习将从第一个三角形的绘制开始。

绘制三角形需要什么

绘制一个三角形远比你想象的复杂,初学者很难快速理解各组件的作用。 作者为此设计了一个“比喻”,它并不精准,但有助于初学者的理解。

思考这样一个场景:

我们在玩一款沙盒游戏,目标是让一些机器人自动画画并提交画作。

  1. 首先我们需要创建一个新世界,初始化场景和机器人之类的设置,即创建实例 VkInstance

  2. 我们希望有东西在开发时帮我们检查错误,可以借助验证层 Validation Layer

  3. 然后需要找一些机器人帮我们画画,也就是物理设备 VkPhysicalDevice ,常代指 GPU 。

  4. 机器人有很多机械臂,有的可以画画,有的可以扫地,我们需要选择合适的机械臂去完成任务。一个机械臂对应一个队列 VkQueue ,一组支持特定功能的机械臂称为队列族 VkQueueFamily ,比如绘画队列族。

  5. 机器人(GPU)的型号不同,但我们希望有相同的操作方式,于是设计了统一的接口,这就是逻辑设备 VkDevice ,用于抽象物理设备。

  6. 你希望通过一个屏幕看画(实时渲染),这个屏幕是第三方的窗口系统,我们使用 GLFW 库。

  7. 我们需要一个工具,将画作扫描进屏幕,这个扫描仪就是窗口表面 VkSurfaceKHR

  8. 我们看画的速度和机器人画画的速度不一样,为了保证效率,可以用一个盒子作为缓冲。机器人往盒子里放画,扫描仪从盒子里拿画。这个盒子就是交换链 VkSwapchainKHR

  9. 特别的是,这些画画的纸可以重复使用,所以盒子里的纸的总数是固定的。这些纸就是图像 VkImage ,交换链中的图像总数固定。

  10. 不同的纸可能有不同的材质和大小,所以我们需要给每个纸写一个标签。这个标签就是图像视图 VkImageView ,描述图像的基本信息。

  11. 现在机器人终于可以画画了,我们要为他准备一个画桌,用于放置画纸等工具。这个画桌就是帧缓冲 VkFrameBuffer ,一帧代指一幅图像。

  12. 我们还要为机器人设计一个房子,这个房子代指渲染通道 VkRenderPass,而纸张对应其中的附件 Attachments

  13. 虽然这些附件放置(绑定)在画桌(帧缓冲)上,但我们需要为房子贴上告示牌,写明房子内有哪些附件,即附件描述 AttachmentDesctiption

  14. 机器人很笨,只能看着流程图画画,所以你需要在房子中放置一些流程图。这个流程图就代指图形管线 VkGraphicsPipeline

  15. 一个大房子分成多个小房间(可以只有一个),可以用不同的房间干不同的事,这些小房间就是子通道 VkSubpass ,一个子通道绑定一个图形管线。

  16. 我们有一份流程图的模版,只需要修改它的部分内容就可以变成新的流程图。其中某几个部分是可编程的,这里就用到了着色器模块 Shader Module

  17. 这些机器人很呆,需要你写信告诉他该画画了,在哪个房子的哪些房间根据哪些流程图画画。这些信代指命令缓冲 VkCommandBuffer

  18. 特殊的是信可以重用,我们使用一个命令池 VkCommandPool 管理这些资源。

  19. 事情一多,机器人做起来就乱了。要保证它先画画,画完才能把画拿出去,所以我们用信号量 Semaphore 处理 GPU 自身的同步。还要保证机器人先完成一张画,我们再寄出新的信,所以我们使用围栏 Fence 处理 CPU 和 GPU 之间的同步。

绘制第一个三角形大致就是这些内容,你目前不需要记住,在后面的学习中随时可以回顾此内容。

注意

上面的描述是非常简化的,与各个模块具体的功能并不完全一致。 这有助于初学者的理解,但当你学完具体内容,应当去理解他们更加准确的含义。

最后

由于大量的初始化工作,仅仅是绘制一个三角形就需要约700行代码。 但在后续的过程中,你会逐渐理解这些繁琐步骤的巨大意义。 且在完成了第一个三角形后,后续扩展纹理和 3D 模型不再需要那么多重复工作。


准备好投入高性能图形 API 的未来了吗?让我们开始吧!


评论