游戏引擎开发日志(第二天)
上一天的地址:https://blog.csdn.net/z736248591/article/details/117201596
————————————哥是可爱的分割线————————————————
第二天 2021年5月24日
回顾:上一天创建了项目,决定了目标和工具。今天继续。
这里使用GLFW作为渲染库。
GLFW介绍:
GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan development on the desktop. It provides a simple API for creating windows, contexts and surfaces, receiving input and events.
GLFW is written in C and supports Windows, macOS, X11 and Wayland.
GLFW is licensed under the zlib/libpng license.
下载glfw丢到external,这里使用OpenGL。
CmakeLists.txt:
# CMakeList.txt: TheSeedGameEngine 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)project ("TheSeedGameEngine"VERSION 0.0.1DESCRIPTION "A 2D multi-platform game engine"HOMEPAGE_URL "https://github.com/nayaku/TheSeedGameEngine"LANGUAGES C CXX)# 添加glwf库
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(external/glfw-3.3.4)
# 找到OpenGL
find_package(OpenGL REQUIRED)# 将源代码添加到此项目的可执行文件。
add_executable (TheSeedGameEnginesrc/main.c)
target_link_libraries(TheSeedGameEngine glfwOpenGL::GL)
# TODO: 如有需要,请添加测试并安装目标。
我们在src\main.c填入代码:
#include<GLFW/glfw3.h>int main()
{GLFWwindow* window;// 初始化GLFW库if (!glfwInit())return -1;// 创建窗口和OpenGL的内容window = glfwCreateWindow(640, 480, "The Seed Game Engine", NULL, NULL);if (!window){glfwTerminate();return -1;}// 创建内容glfwMakeContextCurrent(window);// 主循环while (!glfwWindowShouldClose(window)){// 渲染glClear(GL_COLOR_BUFFER_BIT);// 交换缓冲glfwSwapBuffers(window);// 处理事件消息glfwPollEvents();}glfwTerminate();return 0;
}
编译运行:
很不错!成功了。
额外补充:win10以后在命令行输入tree可以查看文件树,不需要安装额外的软件。
开始编写渲染部分
新建一个Vulkan实例。
static VkInstance vulkanInstance;
static void VulkanInitInstance()
{// 应用信息VkApplicationInfo appInfo = {.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,.pApplicationName = "Demo",.applicationVersion = VK_MAKE_VERSION(1,0,0),.pEngineName = "The Seed Game Engine",.engineVersion = VK_MAKE_VERSION(1,0,0),.apiVersion = VK_API_VERSION_1_0,};// 使用glfw扩展unsigned int glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);// 实例信息VkInstanceCreateInfo createInfo = {.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,.pApplicationInfo = &appInfo,.enabledExtensionCount = glfwExtensionCount,.ppEnabledExtensionNames = glfwExtensions,.enabledLayerCount = 0};// 创建实例VkResult result = vkCreateInstance(&createInfo,NULL,&vulkanInstance);if(result == VK_SUCCESS){printf("Vulkan实例创建成功!\n");}else{printf("Vulkan实例创建失败!\n");abort();}
}
销毁实例:
static void VulkanDestroyInstance(){vkDestroyInstance(vulkanInstance,NULL);printf("Vulkan实例销毁完毕");glfwDestroyWindow(window);glfwTerminate();
}
初始化窗口
void InitWindow(int width,int height,const char* title)
{glfwInit();glfwWindowHint(GLFW_CLIENT_API,GLFW_NO_API);glfwWindowHint(GLFW_RESIZABLE,GLFW_FALSE);window = glfwCreateWindow(width,height,title,NULL,NULL);
}
这里封装一下glfwWindowShouldClose
函数
int WindowShouldClose()
{int flag = glfwWindowShouldClose(window);if(!flag){glfwPollEvents();}return flag;
}
修改main函数
int main()
{InitWindow(800,600,"Demo");while (!WindowShouldClose()){}CloseWindow();return 0;
}
运行:
成功运行。
继续。。。
添加获取物理设备
static void PickPhysicalDevice()
{uint32_t deviceCount;VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount, NULL);assert(result == VK_SUCCESS);if (deviceCount == 0){printf("Failed to find GPUs with Vulkan support!");abort();}VkPhysicalDevice* devices = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * deviceCount);vkEnumeratePhysicalDevices(instance, &deviceCount, devices);// 选择可用的物理设备VkPhysicalDevice physicalDevice=devices[0];//没啥特殊要求,直接选择第一个设备即可free(devices);// 输出选择的物理设备信息VkPhysicalDeviceProperties deviceProperties;vkGetPhysicalDeviceProperties(device, &deviceProperties);printf("Current Physical Info:ID: %I32u\nName: %s\nVulkan Version: %I32u\n",deviceProperties.deviceID,deviceProperties.deviceName,deviceProperties.apiVersion);
}
接下去要判断可用的队列族。这里一直没搞懂什么是队列族,今天来查查看。
不同的queue有着不同的职能,有的负责普通的3D图形渲染的例如Graphic Queue,有的负责像素块Blit的例如Transfer Queue,有的是负责计算的例如Compute Queue,还有负责稀疏绑定的例如Sparse Binding。当然有的queue能同时负责多个职能的,一般第一个是全能的1。其中队列族支持的功能,用queueFlags表示2。
我的集成显卡是Intel HDU Graphics630,就只有一个队列。可以图形、计算、传输、稀疏矩阵。
(注:该软件为GPU-Z 官网 汉化版下载)
独立显卡是GTX 1050,一共有3个队列家族。
补充PickPhysicalDevice
函数完整
// 获取设备队列族的数量uint32_t queueFamilyCount;vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, NULL);VkQueueFamilyProperties* queueFamilyProperties = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * queueFamilyCount);vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, NULL);// 遍历队列族for (uint32_t i = 0; i < queueFamilyCount; i++){// 支持图形工作if (queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT){queueFamilyIndex = i;break;}}free(queueFamilyProperties);
然后在c文件的头添加queueFamilyIndex
定义。
static uint32_t queueFamilyIndex = -1;
运行后输出如下:
Current Vulkan instance created success.
Physical Info:ID: 7308
Name: GeForce GTX 1050 Ti
Vulkan Version: 4202651
Vulkan instance destroyed.
继续。。。
编写CreateLogicalDevice()
函数。
这里只创建一个队列。因为很多时候没有必要创建多个队列。这是因为可以在多个线程上创建所有命令缓冲区,然后在主线程一次性的以较低开销的调用提交队列3。
float queuePriority = 1.0f;VkDeviceQueueCreateInfo queueCreateInfo={.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,.queueFamilyIndex = queueFamilyIndex,.queueCount = 1,// 只需要创建一个队列.pQueuePriorities = &queuePriority}
这里需要VK_KHR_SWAPCHAIN_EXTENSION_NAME扩展支持,因为并不是所有的图形卡具备能力将绘制的图像直接显示到屏幕上4。
验证层开启比较麻烦,而且有些情况下也不支持。这里先不开。
const char *deviceExtensionNames[]={VK_KHR_SWAPCHAIN_EXTENSION_NAME};VkDeviceCreateInfo createInfo = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,.pQueueCreateInfos = &queueCreateInfo,.queueCreateInfoCount = 1,.ppEnabledExtensionNames = deviceExtensionNames,.enabledLayerCount = 0 // 先不开启验证层};
最后创建逻辑设备
VkResult result = vkCreateDevice(physicalDevice,&createInfo,NULL,&logicalDevice);
今天到这里就结束了,也写了好长一堆代码,最后贴出完整的VulkanManager.c
的全部代码。完整的可以去Github上
#include "VulkanManager.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>// GLFW窗口
static GLFWwindow* window;
// Vulkan实例
static VkInstance instance;
// 物理设备
static VkPhysicalDevice physicalDevice;
// 使用的队列家族编号
static uint32_t queueFamilyIndex = -1;
// 逻辑设备
static VkDevice logicalDevice;/* 初始化实例 */
static void InitInstance(const char* title)
{// 应用信息VkApplicationInfo appInfo = {.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,.pApplicationName = title,.applicationVersion = VK_MAKE_VERSION(1, 0, 0),.pEngineName = "The Seed Game Engine",.engineVersion = VK_MAKE_VERSION(1, 0, 0),.apiVersion = VK_API_VERSION_1_0,};// 使用glfw扩展unsigned int glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);// 实例信息VkInstanceCreateInfo createInfo = {.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,.pApplicationInfo = &appInfo,.enabledExtensionCount = glfwExtensionCount,.ppEnabledExtensionNames = glfwExtensions,.enabledLayerCount = 0};// 创建实例VkResult result = vkCreateInstance(&createInfo, NULL, &instance);if (result == VK_SUCCESS){printf("Vulkan instance created success.\n");}else{printf("Vulkan instance created failed.\n");abort();}
}/* 销毁实例 */
static void DestroyInstance()
{vkDestroyInstance(instance, NULL);printf("Vulkan instance destroyed.");glfwDestroyWindow(window);
}/* 获取物理设备 */
static void PickPhysicalDevice()
{uint32_t deviceCount;VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount, NULL);assert(result == VK_SUCCESS);if (deviceCount == 0){printf("Failed to find GPUs with Vulkan support!");abort();}VkPhysicalDevice* devices = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * deviceCount);vkEnumeratePhysicalDevices(instance, &deviceCount, devices);// 选择可用的物理设备physicalDevice = devices[0];//没啥特殊要求,直接选择第一个设备即可free(devices);// 输出选择的物理设备信息VkPhysicalDeviceProperties deviceProperties;vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);printf("Current Physical Info:ID: %I32u\nName: %s\nVulkan Version: %I32u\n",deviceProperties.deviceID,deviceProperties.deviceName,deviceProperties.apiVersion);// 获取设备队列族的数量uint32_t queueFamilyCount;vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);VkQueueFamilyProperties* queueFamilyProperties = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * queueFamilyCount);vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);// 遍历队列族for (uint32_t i = 0; i < queueFamilyCount; i++){// 支持图形工作if (queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT){queueFamilyIndex = i;break;}}free(queueFamilyProperties);
}/* 创建逻辑设备 */
static void CreateLogicalDevice()
{// 队列优先级float queuePriority = 1.0f;VkDeviceQueueCreateInfo queueCreateInfo = {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,.queueFamilyIndex = queueFamilyIndex,.queueCount = 1,// 只需要创建一个队列.pQueuePriorities = &queuePriority};const char* deviceExtensionNames[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };VkDeviceCreateInfo createInfo = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,.pQueueCreateInfos = &queueCreateInfo,.queueCreateInfoCount = 1,.ppEnabledExtensionNames = deviceExtensionNames,.enabledLayerCount = 0 // 先不开启验证层};VkResult result = vkCreateDevice(physicalDevice, &createInfo, NULL, &logicalDevice);
}void InitWindow(int width, int height, const char* title)
{glfwInit();glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);window = glfwCreateWindow(width, height, title, NULL, NULL);InitInstance(title);PickPhysicalDevice();
}int WindowShouldClose()
{int flag = glfwWindowShouldClose(window);if (!flag){glfwPollEvents();}return flag;
}
void CloseWindow()
{DestroyInstance();glfwTerminate();
}
第三天的地址:https://blog.csdn.net/z736248591/article/details/117266221
vulkan的QueueFamilyProperties - 月色疯狂 - 博客园https://www.cnblogs.com/mooniscrazy/p/11711634.html ↩︎
Vulkan初始化——虚拟逻辑设备 - 知乎 https://zhuanlan.zhihu.com/p/24877337 ↩︎
Vulkan填坑学习Day05—逻辑设备与队列_沉默的舞台剧的博客-CSDN博客 https://blog.csdn.net/qq_35312463/article/details/103862429 ↩︎
Vulkan 交换链详解_sy_liao的专栏-CSDN博客 https://blog.csdn.net/u010281924/article/details/105368560 ↩︎
游戏引擎开发日志(第二天)相关推荐
- AS3 RPG游戏引擎开发日志3:地图坐标转换
在这里更改之前说的45度角坐标转换的问题,地图仍然不变,但地图坐标和游戏坐标的关系改变了,它的对应关系如下图: 其中虚线表示地图的边缘,区块中标的数是数组的索引,即地图坐标.地图的高度用大写的H表示, ...
- 【转载】浅析游戏引擎开发
浅析游戏引擎开发 1 引言 电脑游戏作为一种娱乐方式越来越为人们所接受.即时通讯开发对于电脑游戏来说, 游戏引擎是用于控制游戏功能的 主程序, 如接受玩家控制信息的输入, 选择合适的声音以合适的音量播 ...
- python怎么制作游戏图片_Python游戏引擎开发(二):显示图片
本篇文章是Python游戏引擎开发系列的第二篇文章,主要介绍如何显示图片,大家可以学习下. 在上一章中我们讲了如何创建窗口以及对界面进行重绘.可能有朋友不理解为什么要进行全窗口的重绘呢?我在这里可以大 ...
- 用C++实现跨平台游戏引擎开发
游戏开发系列 用C++实现跨平台游戏引擎开发 你是否梦想写一部格斗游戏但却无从着手呢?是否你只因游戏开发好玩而对之感兴趣?本文我们将分析一个通用的跨平台游戏引擎,每个游戏开发新手都可以自由地使用它. ...
- Python游戏引擎开发(六):动画的小小研究
今天我们来研究动画,其实这个动画就是一个Sprite+Bitmap的结合体.不造什么是Sprite和Bitmap?=__=#看来你是半路杀进来的,快去看看前几章吧: Python游戏引擎开发(一):序 ...
- unity应用开发实战案例_Unity3D游戏引擎开发实战从入门到精通
Unity3D游戏引擎开发实战从入门到精通(坦克大战项目实战.NGUI开发.GameObject) 一.Unity3D游戏引擎开发实战从入门到精通是怎么样的一门课程(介绍) 1.1.Unity3D游戏 ...
- 简单游戏引擎开发笔记(一)
---恢复内容开始--- 一.游戏引擎简介 1.概念 游戏引擎是指一些已编写好的可编辑电脑游戏系统或者一些互交式实时图像应用程序的核心组件.这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的在 ...
- 游戏引擎开发和物理引擎_视频游戏开发的最佳游戏引擎
游戏引擎开发和物理引擎 In this article, we'll look at some of the most popular game engines for video game deve ...
- 视频教程-三维游戏引擎开发-图形理论基础-其他
三维游戏引擎开发-图形理论基础 2004年毕业于西南科技大学,计算机科学技术专业,从事软件开发,游戏开发,擅长游戏开发,桌面应用,手机游戏. 张立铜 ¥117.00 立即订阅 扫码下载「CSDN程序员 ...
最新文章
- SSM框架下结合 log4j、slf4j打印日志
- 40亿骚扰电话拨出,6亿用户隐私泄露,央视315曝光AI黑暗面
- Java黑皮书课后题第7章:7.10(找出最小元素的下标)使用下面的方法头编写一个方法,求出一个整数数组中的最小元素下标。编写测试程序,提示用户输入10个数字,调用这个方法返回最小值的下标(多个则最小
- Android下ListView的分页(9.6)
- [C++STL]常用算术生成算法
- python输出文本和值_python读取文本中数据并转化为DataFrame的实例
- Launch Instruments
- CDM CDP及传统备份技术对比
- web内容缓存 nginx高性能缓存详解
- Vijos P1784 数字统计【进制】
- 西威变频器使用说明书_北京2020第三期变频器电路板维修技术培训开班通知
- iOS学习笔记——多控制器管理
- 滚动条滚动到页面底部继续加载
- html5制作当当图书榜页面,当当图书.html
- 福建等保测评五流程,收藏收藏
- LZMA解压缩编码算法的使用
- 左岸语不惊人死不休系列摘录
- 存在感应雷达模块 毫米波雷达传感器 智能生活技术应用
- 2018上期Android学期总结
- 手持式水质监测仪在污水处理中的应用