700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 游戏引擎开发日志(第二天)

游戏引擎开发日志(第二天)

时间:2023-03-17 23:25:05

相关推荐

游戏引擎开发日志(第二天)

上一天的地址:/z736248591/article/details/11796

————————————哥是可爱的分割线————————————————

第二天 5月24日

回顾:上一天创建了项目,决定了目标和工具。今天继续。

这里使用GLFW作为渲染库。

GLFW介绍:

GLFWis 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 "/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)# 找到OpenGLfind_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: 7308Name: GeForce GTX 1050 TiVulkan Version: 4202651Vulkan 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();}

第三天的地址:/z736248591/article/details/117266221

vulkan的QueueFamilyProperties - 月色疯狂 - 博客园/mooniscrazy/p/11711634.html ↩︎

Vulkan初始化——虚拟逻辑设备 - 知乎 /p/24877337 ↩︎

Vulkan填坑学习Day05—逻辑设备与队列_沉默的舞台剧的博客-CSDN博客 /qq_35312463/article/details/103862429 ↩︎

Vulkan 交换链详解_sy_liao的专栏-CSDN博客 /u010281924/article/details/105368560 ↩︎

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。