vulkan环境安装

OpenTK 2026-05-26 16:23:59

在 VS2022 中配置 Vulkan、GLFW 和 GLM 主要分为三步:先下载好这三个库,然后在 VS 项目里指定头文件和库的路径,最后在代码中包含头文件并链接库文件。

最关键的步骤在于正确配置项目的附加包含目录附加库目录附加依赖项,下面一步步来操作。

🛠️ 第一步:环境准备 (下载库文件)

首先,你需要下载运行代码所需的 Vulkan SDK、GLFW 和 GLM 库。

  1. 安装 Vulkan SDK

    • 前往 LunarG Vulkan SDK 官网 下载最新版本的 SDK。

    • 下载后是一个安装程序,建议使用默认安装路径(如 C:\VulkanSDK\),安装时建议勾选所有组件以避免后续缺少文件。

    • 安装完成后,进入 Vulkan SDK 的 Bin 目录(如 C:\VulkanSDK\<版本号>\Bin),双击运行 vkcube.exe。如果出现一个旋转的彩色立方体,说明你的显卡驱动和 SDK 都安装成功了。

  2. 下载 GLFW 库 (负责创建窗口)

    • 前往 GLFW 官网下载页,在 "Windows pre-compiled binaries" 部分,下载 64-bit Windows binaries

    • 下载后解压到你选定的目录(如 D:\Libs\glfw-3.4.bin.WIN64)。你会看到 include 和 lib-vc2022 这两个关键文件夹。

  3. 下载 GLM 库 (负责数学运算)

    • 前往 GLM Github 仓库 下载最新的源码包(如 glm-0.9.9.8.zip 或更新版本)。

    • 下载后解压到你选定的目录(如 D:\Libs\glm),你只需要用到里面的 glm 文件夹。

🗂️ 第二步:配置VS2022项目 (核心)

现在,我们将在你的 VS2022 项目里把这些库连接起来。

  1. 创建项目:在 VS2022 中新建一个 C++ 空项目。你可以在项目创建向导中搜索"空项目"来找到这个模板。

  2. 打开属性页:在右侧"解决方案资源管理器"中,右键点击你的项目名称,选择属性

    小提示:为了方便切换,建议先在属性页窗口顶部的"配置"下拉菜单中,选择所有配置,"平台"选择所有平台

  3. 配置头文件目录:在左侧菜单栏,导航至 C/C++ -> 常规,在右侧找到附加包含目录进行编辑。点击出现的小文件夹图标,然后添加以下三个路径:

    • Vulkan 头文件目录:C:\VulkanSDK\<你的版本号>\Include

    • GLFW 头文件目录:你的GLFW解压路径\include

    • GLM 头文件目录:你的GLM解压路径\glm

  4. 配置库文件目录:在左侧菜单栏,导航至链接器 -> 常规,在右侧找到附加库目录进行编辑。同样点击图标,添加以下两个路径:

    • Vulkan 库文件目录:C:\VulkanSDK\<你的版本号>\Lib

    • GLFW 库文件目录:你的GLFW解压路径\lib-vc2022

  5. 指定要链接的库文件:在左侧菜单栏,导航至链接器 -> 输入,在右侧找到附加依赖项进行编辑。在弹出的对话框中,逐行添加以下两个库文件名:

    • vulkan-1.lib

    • glfw3.lib

  6. (可选) 设置C++语言标准:为了兼容性,建议在C/C++ -> 语言中,将C++ 语言标准设置为 ISO C++17 标准 (/std:c++17)

完成以上所有步骤后,点击"确定"保存你的项目属性设置。

✅ 第三步:验证与测试

现在我们来编写一段测试代码,验证环境是否配置成功。

  1. 创建源文件:在"解决方案资源管理器"中,右键点击项目下的"源文件"文件夹,选择"添加" -> "新建项",创建一个名为 main.cpp 的文件。

  2. 编写测试代码:将下面的代码复制并粘贴到你的 main.cpp 文件中,覆盖原有内容。这段代码会初始化 GLFW 和 Vulkan,并打印支持的扩展数量。

cpp

// 必须在包含glfw3.h之前定义这个宏,它会自动包含vulkan.h
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

// GLM 相关宏和头文件
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>

#include <iostream>

int main() {
    // 1. 初始化 GLFW
    glfwInit();

    // 告诉 GLFW 不要创建 OpenGL 上下文,因为我们要用 Vulkan
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    // 创建一个窗口
    GLFWwindow* window = glfwCreateWindow(800, 600, "Vulkan 测试窗口", nullptr, nullptr);

    // 2. 测试 Vulkan 基本功能
    uint32_t extensionCount = 0;
    // 枚举所有支持的 Vulkan 实例扩展
    vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
    std::cout << "此驱动支持 " << extensionCount << " 个 Vulkan 扩展。\n";

    // 3. 测试 GLM 数学库 (一个简单的向量矩阵乘法)
    glm::mat4 matrix;
    glm::vec4 vec;
    auto test = matrix * vec;
    std::cout << "GLM 数学库工作正常。\n";

    // 4. 进入主循环,持续监听窗口事件,直到用户关闭窗口
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    }

    // 5. 清理资源并退出
    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}
  1. 编译运行:点击 VS 顶部菜单栏的 本地 Windows 调试器 运行程序。

如果一切顺利,你会看到一个名为 "Vulkan 测试窗口" 的空白窗口弹出,同时在 VS 的输出或控制台窗口中,会打印出支持的 Vulkan 扩展数量。


🤔 如果编译报错怎么办?

根据不同的配置情况和需求,可以参考下表:

遇到的问题可能的原因与解决办法
找不到 glfw3.h 或 vulkan.h这是最常见的错误。说明附加包含目录配置不正确或路径没写对。请回到第二步的第3小步,仔细检查你添加的三个路径是否正确指向了 GLFW 和 glm 文件夹。
链接错误 LNK2019 (无法解析的外部符号)这说明链接器找不到函数的具体实现。请检查:
1. 附加库目录中是否正确添加了 lib-vc2022 和 Vulkan Lib 文件夹。
2. 附加依赖项中是否准确添加了 vulkan-1.lib 和 glfw3.lib
程序运行后弹窗很快消失这通常是程序逻辑问题,但为了看清输出,你可以在 main 函数的 return 0; 前加上 system("pause"); 这行代码。

💡 善用官方示例

当你完成基础环境的配置后,如果想进一步学习Vulkan的各种渲染技巧,最佳实践是直接研究Khronos Group官方维护的示例项目。

它包含了从基础入门到高级特性的大量完整代码。你可以通过以下方式获取并构建它:

bash

git clone --recurse-submodules https://github.com/KhronosGroup/Vulkan-Samples.git
cd Vulkan-Samples
cmake -G "Visual Studio 17 2022" -A x64 -S . -B build/windows
cmake --build build/windows --config Release --target vulkan_samples

构建成功后,你就可以在 build/windows/app/bin/Release/AMD64/ 目录下找到 vulkan_samples.exe,并在VS中通过设置命令行参数(如 sample hello_triangle)来运行具体的示例。

 

 

绘制三角形

你的项目文件夹/
├── main.cpp
└── shaders/
    ├── triangle.vert
    └── triangle.frag

 

代码

#version 450

vec2 positions[3] = vec2[](
    vec2(0.0, -0.5),
    vec2(0.5, 0.5),
    vec2(-0.5, 0.5)
);

void main() {
    gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
}

 

#version 450

layout(location = 0) out vec4 outColor;

void main() {
    outColor = vec4(0.0, 0.5, 0.8, 1.0);
}

 

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>

const int WIDTH = 800;
const int HEIGHT = 600;

// 读取 SPIR-V 文件
std::vector<char> readFile(const std::string& filename) {
    std::ifstream file(filename, std::ios::ate | std::ios::binary);
    if (!file.is_open()) {
        throw std::runtime_error("Failed to open file: " + filename);
    }
    size_t fileSize = (size_t)file.tellg();
    std::vector<char> buffer(fileSize);
    file.seekg(0);
    file.read(buffer.data(), fileSize);
    file.close();
    return buffer;
}

int main() {
    try {
        // 读取编译好的着色器
        std::cout << "Loading shaders..." << std::endl;
        auto vertCode = readFile("shaders/vert.spv");
        auto fragCode = readFile("shaders/frag.spv");
        std::cout << "Vertex shader size: " << vertCode.size() << " bytes" << std::endl;
        std::cout << "Fragment shader size: " << fragCode.size() << " bytes" << std::endl;

        // 初始化 GLFW
        if (!glfwInit()) {
            throw std::runtime_error("GLFW init failed");
        }

        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
        GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Triangle", nullptr, nullptr);
        if (!window) {
            throw std::runtime_error("Window creation failed");
        }

        // 创建 Vulkan 实例
        VkApplicationInfo appInfo{};
        appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
        appInfo.pApplicationName = "Triangle";
        appInfo.apiVersion = VK_API_VERSION_1_0;

        uint32_t glfwExtensionCount = 0;
        const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
        std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);

        VkInstanceCreateInfo createInfo{};
        createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
        createInfo.pApplicationInfo = &appInfo;
        createInfo.enabledExtensionCount = (uint32_t)extensions.size();
        createInfo.ppEnabledExtensionNames = extensions.data();

        VkInstance instance;
        if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
            throw std::runtime_error("Instance creation failed");
        }

        // 创建 Surface
        VkSurfaceKHR surface;
        if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
            throw std::runtime_error("Surface creation failed");
        }

        // 选择 GPU
        uint32_t deviceCount = 0;
        vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
        if (deviceCount == 0) {
            throw std::runtime_error("No Vulkan GPU found");
        }
        std::vector<VkPhysicalDevice> devices(deviceCount);
        vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
        VkPhysicalDevice physicalDevice = devices[0];

        VkPhysicalDeviceProperties props;
        vkGetPhysicalDeviceProperties(physicalDevice, &props);
        std::cout << "Using GPU: " << props.deviceName << std::endl;

        // 找队列族
        uint32_t queueFamilyCount = 0;
        vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
        std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
        vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data());

        uint32_t graphicsFamily = UINT32_MAX;
        for (uint32_t i = 0; i < queueFamilyCount; i++) {
            if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
                graphicsFamily = i;
                break;
            }
        }
        if (graphicsFamily == UINT32_MAX) {
            throw std::runtime_error("No graphics queue");
        }

        // 创建设备
        float queuePriority = 1.0f;
        VkDeviceQueueCreateInfo queueCreateInfo{};
        queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
        queueCreateInfo.queueFamilyIndex = graphicsFamily;
        queueCreateInfo.queueCount = 1;
        queueCreateInfo.pQueuePriorities = &queuePriority;

        const char* deviceExtension = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
        VkDeviceCreateInfo deviceCreateInfo{};
        deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
        deviceCreateInfo.queueCreateInfoCount = 1;
        deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
        deviceCreateInfo.enabledExtensionCount = 1;
        deviceCreateInfo.ppEnabledExtensionNames = &deviceExtension;

        VkDevice device;
        if (vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device) != VK_SUCCESS) {
            throw std::runtime_error("Device creation failed");
        }

        VkQueue graphicsQueue;
        vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue);

        // 创建 SwapChain
        VkSurfaceCapabilitiesKHR capabilities;
        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities);

        uint32_t formatCount;
        vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
        std::vector<VkSurfaceFormatKHR> formats(formatCount);
        vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data());
        VkSurfaceFormatKHR surfaceFormat = formats[0];

        VkExtent2D extent = capabilities.currentExtent;
        if (extent.width == 0xFFFFFFFF) {
            extent.width = WIDTH;
            extent.height = HEIGHT;
        }

        VkSwapchainCreateInfoKHR swapCreateInfo{};
        swapCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
        swapCreateInfo.surface = surface;
        swapCreateInfo.minImageCount = 2;
        swapCreateInfo.imageFormat = surfaceFormat.format;
        swapCreateInfo.imageColorSpace = surfaceFormat.colorSpace;
        swapCreateInfo.imageExtent = extent;
        swapCreateInfo.imageArrayLayers = 1;
        swapCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
        swapCreateInfo.preTransform = capabilities.currentTransform;
        swapCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
        swapCreateInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
        swapCreateInfo.clipped = VK_TRUE;

        VkSwapchainKHR swapChain;
        if (vkCreateSwapchainKHR(device, &swapCreateInfo, nullptr, &swapChain) != VK_SUCCESS) {
            throw std::runtime_error("Swapchain creation failed");
        }

        uint32_t imageCount;
        vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
        std::vector<VkImage> swapChainImages(imageCount);
        vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());

        // 创建 ImageView
        std::vector<VkImageView> swapChainImageViews(imageCount);
        for (uint32_t i = 0; i < imageCount; i++) {
            VkImageViewCreateInfo viewInfo{};
            viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
            viewInfo.image = swapChainImages[i];
            viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
            viewInfo.format = surfaceFormat.format;
            viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            viewInfo.subresourceRange.levelCount = 1;
            viewInfo.subresourceRange.layerCount = 1;
            if (vkCreateImageView(device, &viewInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
                throw std::runtime_error("ImageView creation failed");
            }
        }

        // 创建 RenderPass
        VkAttachmentDescription colorAttachment{};
        colorAttachment.format = surfaceFormat.format;
        colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
        colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
        colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
        colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
        colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

        VkAttachmentReference colorAttachmentRef{};
        colorAttachmentRef.attachment = 0;
        colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

        VkSubpassDescription subpass{};
        subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
        subpass.colorAttachmentCount = 1;
        subpass.pColorAttachments = &colorAttachmentRef;

        VkRenderPassCreateInfo renderPassInfo{};
        renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
        renderPassInfo.attachmentCount = 1;
        renderPassInfo.pAttachments = &colorAttachment;
        renderPassInfo.subpassCount = 1;
        renderPassInfo.pSubpasses = &subpass;

        VkRenderPass renderPass;
        if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
            throw std::runtime_error("RenderPass creation failed");
        }

        // 创建 Shader Module
        VkShaderModuleCreateInfo vertModuleInfo{};
        vertModuleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
        vertModuleInfo.codeSize = vertCode.size();
        vertModuleInfo.pCode = reinterpret_cast<const uint32_t*>(vertCode.data());

        VkShaderModule vertShaderModule;
        if (vkCreateShaderModule(device, &vertModuleInfo, nullptr, &vertShaderModule) != VK_SUCCESS) {
            throw std::runtime_error("Vertex shader module creation failed");
        }

        VkShaderModuleCreateInfo fragModuleInfo{};
        fragModuleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
        fragModuleInfo.codeSize = fragCode.size();
        fragModuleInfo.pCode = reinterpret_cast<const uint32_t*>(fragCode.data());

        VkShaderModule fragShaderModule;
        if (vkCreateShaderModule(device, &fragModuleInfo, nullptr, &fragShaderModule) != VK_SUCCESS) {
            throw std::runtime_error("Fragment shader module creation failed");
        }

        VkPipelineShaderStageCreateInfo vertStage{};
        vertStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        vertStage.stage = VK_SHADER_STAGE_VERTEX_BIT;
        vertStage.module = vertShaderModule;
        vertStage.pName = "main";

        VkPipelineShaderStageCreateInfo fragStage{};
        fragStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        fragStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
        fragStage.module = fragShaderModule;
        fragStage.pName = "main";

        VkPipelineShaderStageCreateInfo shaderStages[] = { vertStage, fragStage };

        // 创建 Pipeline
        VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
        vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;

        VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
        inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
        inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;

        VkViewport viewport{};
        viewport.x = 0.0f;
        viewport.y = 0.0f;
        viewport.width = (float)extent.width;
        viewport.height = (float)extent.height;
        viewport.minDepth = 0.0f;
        viewport.maxDepth = 1.0f;

        VkRect2D scissor{};
        scissor.offset = { 0, 0 };
        scissor.extent = extent;

        VkPipelineViewportStateCreateInfo viewportState{};
        viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
        viewportState.viewportCount = 1;
        viewportState.pViewports = &viewport;
        viewportState.scissorCount = 1;
        viewportState.pScissors = &scissor;

        VkPipelineRasterizationStateCreateInfo rasterizer{};
        rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
        rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
        rasterizer.lineWidth = 1.0f;
        rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
        rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;

        VkPipelineMultisampleStateCreateInfo multisampling{};
        multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
        multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;

        VkPipelineColorBlendAttachmentState colorBlendAttachment{};
        colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
        colorBlendAttachment.blendEnable = VK_FALSE;

        VkPipelineColorBlendStateCreateInfo colorBlending{};
        colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
        colorBlending.attachmentCount = 1;
        colorBlending.pAttachments = &colorBlendAttachment;

        VkPipelineLayout pipelineLayout;
        VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
        pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
        if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
            throw std::runtime_error("Pipeline layout creation failed");
        }

        VkGraphicsPipelineCreateInfo pipelineInfo{};
        pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
        pipelineInfo.stageCount = 2;
        pipelineInfo.pStages = shaderStages;
        pipelineInfo.pVertexInputState = &vertexInputInfo;
        pipelineInfo.pInputAssemblyState = &inputAssembly;
        pipelineInfo.pViewportState = &viewportState;
        pipelineInfo.pRasterizationState = &rasterizer;
        pipelineInfo.pMultisampleState = &multisampling;
        pipelineInfo.pColorBlendState = &colorBlending;
        pipelineInfo.layout = pipelineLayout;
        pipelineInfo.renderPass = renderPass;
        pipelineInfo.subpass = 0;

        VkPipeline graphicsPipeline;
        if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
            throw std::runtime_error("Graphics pipeline creation failed");
        }

        // 创建 Framebuffer
        std::vector<VkFramebuffer> framebuffers(imageCount);
        for (uint32_t i = 0; i < imageCount; i++) {
            VkImageView attachments[] = { swapChainImageViews[i] };
            VkFramebufferCreateInfo fbInfo{};
            fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
            fbInfo.renderPass = renderPass;
            fbInfo.attachmentCount = 1;
            fbInfo.pAttachments = attachments;
            fbInfo.width = extent.width;
            fbInfo.height = extent.height;
            fbInfo.layers = 1;
            if (vkCreateFramebuffer(device, &fbInfo, nullptr, &framebuffers[i]) != VK_SUCCESS) {
                throw std::runtime_error("Framebuffer creation failed");
            }
        }

        // 创建 Command Pool 和 Command Buffers
        VkCommandPool commandPool;
        VkCommandPoolCreateInfo poolInfo{};
        poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
        poolInfo.queueFamilyIndex = graphicsFamily;
        if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
            throw std::runtime_error("Command pool creation failed");
        }

        std::vector<VkCommandBuffer> commandBuffers(imageCount);
        VkCommandBufferAllocateInfo allocInfo{};
        allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
        allocInfo.commandPool = commandPool;
        allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
        allocInfo.commandBufferCount = imageCount;
        if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
            throw std::runtime_error("Command buffer allocation failed");
        }

        for (uint32_t i = 0; i < imageCount; i++) {
            VkCommandBufferBeginInfo beginInfo{};
            beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
            vkBeginCommandBuffer(commandBuffers[i], &beginInfo);

            VkRenderPassBeginInfo rpBegin{};
            rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
            rpBegin.renderPass = renderPass;
            rpBegin.framebuffer = framebuffers[i];
            rpBegin.renderArea.extent = extent;
            VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
            rpBegin.clearValueCount = 1;
            rpBegin.pClearValues = &clearColor;

            vkCmdBeginRenderPass(commandBuffers[i], &rpBegin, VK_SUBPASS_CONTENTS_INLINE);
            vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
            vkCmdDraw(commandBuffers[i], 3, 1, 0, 0);
            vkCmdEndRenderPass(commandBuffers[i]);
            vkEndCommandBuffer(commandBuffers[i]);
        }

        // 同步对象
        VkSemaphore semaphore;
        VkFence fence;
        VkSemaphoreCreateInfo semInfo{};
        semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
        VkFenceCreateInfo fenceInfo{};
        fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
        fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
        vkCreateSemaphore(device, &semInfo, nullptr, &semaphore);
        vkCreateFence(device, &fenceInfo, nullptr, &fence);

        std::cout << "Entering main loop - Triangle should appear!" << std::endl;
        std::cout << "Press ESC to exit" << std::endl;

        // 主循环
        while (!glfwWindowShouldClose(window)) {
            glfwPollEvents();

            if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
                glfwSetWindowShouldClose(window, true);
            }

            vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
            vkResetFences(device, 1, &fence);

            uint32_t imageIndex;
            vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, semaphore, VK_NULL_HANDLE, &imageIndex);

            VkSubmitInfo submitInfo{};
            submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
            submitInfo.waitSemaphoreCount = 1;
            submitInfo.pWaitSemaphores = &semaphore;
            VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
            submitInfo.pWaitDstStageMask = &waitStage;
            submitInfo.commandBufferCount = 1;
            submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
            submitInfo.signalSemaphoreCount = 1;
            submitInfo.pSignalSemaphores = &semaphore;
            vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence);

            VkPresentInfoKHR presentInfo{};
            presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
            presentInfo.waitSemaphoreCount = 1;
            presentInfo.pWaitSemaphores = &semaphore;
            presentInfo.swapchainCount = 1;
            presentInfo.pSwapchains = &swapChain;
            presentInfo.pImageIndices = &imageIndex;
            vkQueuePresentKHR(graphicsQueue, &presentInfo);
        }

        // 清理
        vkDeviceWaitIdle(device);
        vkDestroySemaphore(device, semaphore, nullptr);
        vkDestroyFence(device, fence, nullptr);
        vkDestroyCommandPool(device, commandPool, nullptr);
        for (auto fb : framebuffers) vkDestroyFramebuffer(device, fb, nullptr);
        vkDestroyPipeline(device, graphicsPipeline, nullptr);
        vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
        vkDestroyRenderPass(device, renderPass, nullptr);
        vkDestroyShaderModule(device, vertShaderModule, nullptr);
        vkDestroyShaderModule(device, fragShaderModule, nullptr);
        for (auto iv : swapChainImageViews) vkDestroyImageView(device, iv, nullptr);
        vkDestroySwapchainKHR(device, swapChain, nullptr);
        vkDestroyDevice(device, nullptr);
        vkDestroySurfaceKHR(instance, surface, nullptr);
        vkDestroyInstance(instance, nullptr);
        glfwDestroyWindow(window);
        glfwTerminate();

        std::cout << "Done!" << std::endl;

    }
    catch (const std::exception& e) {
        std::cerr << "ERROR: " << e.what() << std::endl;
        std::cin.get();
        return -1;
    }

    return 0;
}

 

 

编译

使用预编译的 SPIR-V 文件

既然你已经有了 .vert 和 .frag 文件,先用命令行工具把它们编译成 .spv 文件:

  1. 打开命令提示符(不是 VS 的)

  2. 进入你的项目目录

  3. 运行:

cmd

glslc shaders/triangle.vert -o shaders/vert.spv
glslc shaders/triangle.frag -o shaders/frag.spv

然后使用这个简单版本的 main.cpp

...全文
58 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

4

社区成员

发帖
与我相关
我的任务
社区描述
openTK、OpenGL、WebGL技术学习交流
图形渲染c#程序人生 技术论坛(原bbs) 广东省·深圳市
社区管理员
  • 亿只小灿灿
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧