几何着色器

我们大部分情况下仅使用顶点着色器(vertex shader)和片元着色器(fragment shader),而实际上vulkan还提供了一个可选的几何着色器(geometry shader)。几何着色器位于顶点和片元着色器之间,如果没有使用时,则顶点着色器输出到片元着色器,在使用几何着色器后,顶点着色器输出组成一个基础图元的顶点信息到几何着色器,经过几何着色器处理后,再输出到片元着色器。几何着色器能够产生0个以上的基础图元(primitive),它能起到一定的裁剪作用、同时也能产生比顶点着色器输入更多的基础图元。

法线可视化

首先简述一下我们需要实现的简单效果,在原始模型的基础上我们来实现法线可视化:
1.原始加载模型代码不变;
2.新增一个管线来绘制法线;
3.shader部分新增一个顶点、几何、片元着色器来处理法线;

创建管线等基础部分就不在累述,如果想看具体实现,见最后源码。

那么我来主要说一下新增的shader部分,首先来看片元着色器:

#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enablelayout (location = 0) in vec3 inColor;
layout (location = 0) out vec4 outFragColor;void main(void){outFragColor = vec4(inColor, 1.0);
}

最简单的片元着色器,无需多说。接下来我们看的是顶点着色器,显然 也无需多说,依旧很简单:
#version 450

#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enablelayout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;layout (location = 0) out vec3 outNormal;out gl_PerVertex{vec4 gl_Position;
};void main(void){outNormal = inNormal;gl_Position = vec4(inPos.xyz, 1.0);
}

那么接下来中点来了,我们在以上两个阶段之间添加一个集合着色器normaldebug.geom:

#version 450#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enablelayout (triangles) in;
layout (line_strip, max_vertices = 6) out;layout (binding = 1) uniform UBO
{mat4 projection;mat4 model;
} ubo;layout (location = 0) in vec3 inNormal[];layout (location = 0) out vec3 outColor;void main(void)
{   float normalLength = 10;for(int i=0; i<gl_in.length(); i++){vec3 pos = gl_in[i].gl_Position.xyz;vec3 normal = inNormal[i].xyz;gl_Position = ubo.projection * (ubo.model * vec4(pos, 1.0));outColor = vec3(0.0, 1.0, 0.0);EmitVertex();gl_Position = ubo.projection * (ubo.model * vec4(pos + normal * normalLength, 1.0));outColor = vec3(0.0, 1.0, 1.0);EmitVertex();EndPrimitive();}
}

layout (*) in;输入可以有如下:

  • points:绘制GL_POINTS图元时
  • lines:绘制GL_LINES或GL_LINE_STRIP时
  • lines_adjacency:GL_LINES_ADJACENCY或GL_LINE_STRIP_ADJACENCY
  • triangles:GL_TRIANGLES、GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN 即绘制三角面片时使用
  • triangles_adjacency:GL_TRIANGLES_ADJACENCY或GL_TRIANGLE_STRIP_ADJACENCY

layout (*) out输出如下:

  • points 输出的图元是点
  • line_strip 输出的图元是线
  • triangle_strip 输出的图元是三角形
  • max_vertices 代表输出的最大顶点数量,超过这个数量,shader将不再绘制多出的顶点。

注:EmitVertex表示输出一个顶点,而EndPrimitive表示结束一个图元的输出,这是一对命令。只有几何着色器才有的命令。不明白的可以Google其用法

上述shader主要作用是在法线起点和延法线延长normalLength出新增两个点,并对其设置颜色。
运行,可看到如下效果:

此外几何着色器还有更多效果,有时间我们再来试一下爆炸或者腐蚀消散等效果吧。

附:main源码

//shader particlefire.cpp
#define GLM_ENABLE_EXPERIMENTAL
#define GLFW_INCLUDE_VULKAN
#define GLM_FORCE_RADIANS
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/hash.hpp>
#define TINYOBJLOADER_IMPLEMENTATION
#include <tiny/tiny_obj_loader.h>#include <random>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <set>
#include <array>
#include <algorithm>
#include <chrono>
#include <unordered_map>
#include "Camera.h"
#include "VulkanBuffer.hpp"
#include "VulkanInitializers.hpp"
#include "VulkanModel.hpp"
#include "VulkanTools.h"
#include "VulkanTexture.hpp"
#include <gli/gli.hpp>const int WIDTH = 960;
const int HEIGHT = 720;
const int MAX_FRAMES_IN_FLIGHT = 2;//鼠标移动位置记录
float lastX = WIDTH / 2, lastY = HEIGHT / 2;
//缩放视野
float fov = 75.0f;
bool firstMouse = true;
bool displayNormals = true;const std::vector<const char*> validationLayers = {"VK_LAYER_KHRONOS_validation"
};const std::vector<const char*> deviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME
};#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endifVkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");if (func != nullptr) {return func(instance, pCreateInfo, pAllocator, pDebugMessenger);}else {return VK_ERROR_EXTENSION_NOT_PRESENT;}
}void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) {auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");if (func != nullptr) {func(instance, debugMessenger, pAllocator);}
}struct QueueFamilyIndices {uint32_t graphicsFamily = -1;uint32_t presentFamily = -1;bool isComplete() {return graphicsFamily >= 0 && presentFamily >= 0;}
};struct SwapChainSupportDetails {VkSurfaceCapabilitiesKHR capabilities;std::vector<VkSurfaceFormatKHR> formats;std::vector<VkPresentModeKHR> presentModes;
};struct UniformBufferObject {glm::mat4 model;glm::mat4 view;glm::mat4 proj;glm::mat4 lightSpace;glm::vec3 baseLight;float ambientStrength;glm::vec3 lightPos;float specularStrength;glm::vec3 viewPos;float foo1 = 0.0f;glm::vec3 lightDirect;float foo2 = 0.0f;glm::vec3 flashColor;float foo3 = 0.0f;glm::vec3 flashPos;float outerCutOff;glm::vec3 flashDir;float flashCutOff;
};VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;
Camera camera(glm::vec3(0.0f, -20.0f, -30.0f), glm::radians(10.0f), glm::radians(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{if (fov >= 1.0f && fov <= 45.0f)fov -= yoffset;if (fov <= 1.0f)fov = 1.0f;if (fov >= 45.0f)fov = 45.0f;
}void processInput(GLFWwindow* window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {glfwSetWindowShouldClose(window, true);}if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {camera.speedZ = 1.0f;}else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {camera.speedZ = -1.0f;}else {camera.speedZ = 0.0f;}if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {camera.speedX = -1.0f;}else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {camera.speedX = 1.0f;}else {camera.speedX = 0.0f;}if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) {camera.speedY = 1.0f;}else if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) {camera.speedY = -1.0f;}else {camera.speedY = 0.0f;}if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {displayNormals = displayNormals == true ? false : true;}else {}
}void mouse_callback(GLFWwindow* window, double xPos, double yPos) {if (firstMouse) {lastX = xPos;lastY = yPos;firstMouse = false;}float deltaX, deltaY;deltaX = xPos - lastX;deltaY = yPos - lastY;lastX = xPos;lastY = yPos;camera.ProcessMouseMovement(deltaX, deltaY);
}class HelloTriangleApplication {public:void run() {initWindow();initVulkan();mainLoop();cleanup();}private:GLFWwindow* window;vks::VulkanDevice *vulkanDevice;VkInstance instance;VkDebugUtilsMessengerEXT debugMessenger;VkSurfaceKHR surface;VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;VkDevice device;VkQueue graphicsQueue;VkQueue presentQueue;VkSwapchainKHR swapChain;std::vector<VkImage> swapChainImages;VkFormat swapChainImageFormat;// Depth buffer format (selected during Vulkan initialization)VkFormat depthFormat;VkExtent2D swapChainExtent;std::vector<VkImageView> swapChainImageViews;VkRenderPass renderPass;VkDescriptorSetLayout descriptorSetLayout;VkPipelineLayout pipelineLayout;std::vector<VkFramebuffer> frameBuffers;VkCommandPool commandPool;std::vector<VkCommandBuffer> drawCmdBuffers;size_t currentFrame = 0;VkDeviceMemory textureImageMemory;VkImageView textureImageView;//保存纹理图像VkSampler textureSampler;//创建采样器VkBuffer indexBuffer;VkDeviceMemory indexBufferMemory;VkDescriptorPool descriptorPool;VkDescriptorSet descriptorSet;VkBuffer stagingBuffer;VkDeviceMemory stagingBufferMemory;VkImage colorImage;VkDeviceMemory colorImageMemory;VkImageView colorImageView;VkImage depthImage;VkDeviceMemory depthImageMemory;VkImageView depthImageView;VkPipelineCache pipelineCache;// Synchronization semaphoresstruct {// Swap chain image presentationVkSemaphore presentComplete;// Command buffer submission and executionVkSemaphore renderComplete;} semaphores;VkSubmitInfo submitInfo;// List of shader modules created (stored for cleanup)std::vector<VkShaderModule> shaderModules;uint32_t mipLevels;//Mip链VkImage textureImage;float zNear = 1.0f;float zFar = 96.0f;float zoom = 0;float lightFOV = 45.0f;VkClearColorValue defaultClearColor = { { 0.1f, 0.1f, 0.3f, 0.5f } };/** @brief Pipeline stages used to wait at for graphics queue submissions */VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;#pragma region particlefire#define VERTEX_BUFFER_BIND_ID 0struct {VkPipelineVertexInputStateCreateInfo inputState;std::vector<VkVertexInputBindingDescription> bindingDescriptions;std::vector<VkVertexInputAttributeDescription> attributeDescriptions;} vertices;// Vertex layout for the modelsvks::VertexLayout vertexLayout = vks::VertexLayout({vks::VERTEX_COMPONENT_POSITION,vks::VERTEX_COMPONENT_NORMAL,vks::VERTEX_COMPONENT_COLOR,});struct {vks::Model object;} models;struct {glm::mat4 projection;glm::mat4 model;} uboVS;struct {glm::mat4 projection;glm::mat4 model;glm::vec2 viewportDim;} uboGS;struct {vks::Buffer VS;vks::Buffer GS;} uniformBuffers;struct {VkPipeline solid;VkPipeline normals;} pipelines;
#pragma endregionvoid initWindow() {glfwInit();glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);//glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan_Shader--geometry", nullptr, nullptr);glfwSetWindowUserPointer(window, this);//glfwMakeContextCurrent(window);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//禁用鼠标悬浮glfwSetCursorPosCallback(window, mouse_callback);//注册键盘输入glfwSetScrollCallback(window, scroll_callback); //注册鼠标滚轮glfwSetWindowSizeCallback(window, HelloTriangleApplication::onWindowResized);}void initVulkan() {createInstance();setupDebugMessenger();createSurface();pickPhysicalDevice();createLogicalDevice();assert(getSupportedDepthFormat());createSwapChain();createImageViews();createRenderPass();createPipelineCache();createCommandPool();createColorResources();createDepthResources();createFramebuffers();loadAssets();setupVertexDescriptions();prepareUniformBuffers();setupDescriptorSetLayout();preparePipelines();setupDescriptorPool();setupDescriptorSets();buildCommandBuffers();createSemaphores();}void mainLoop() {while (!glfwWindowShouldClose(window)) {glfwPollEvents();processInput(window);updateUniformBuffers();draw();camera.UpdataCameraPosition();}vkDeviceWaitIdle(device);}void draw(){//prepareFrame// Acquire the next image from the swap chainuint32_t imageIndex;// Active frame buffer indexVkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, semaphores.presentComplete, VK_NULL_HANDLE, &imageIndex);// Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE) or no longer optimal for presentation (SUBOPTIMAL)if (result == VK_ERROR_OUT_OF_DATE_KHR) {recreateSwapChain();return;}else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {throw std::runtime_error("failed to acquire swap chain image!");}submitInfo.commandBufferCount = 1;submitInfo.pCommandBuffers = &drawCmdBuffers[imageIndex];vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); Reset stage masksubmitInfo.pWaitDstStageMask = &submitPipelineStages;// Reset wait and signal semaphores for rendering next frame// Wait for swap chain presentation to finishsubmitInfo.waitSemaphoreCount = 1;submitInfo.pWaitSemaphores = &semaphores.presentComplete;// Signal ready with offscreen semaphoresubmitInfo.signalSemaphoreCount = 1;submitInfo.pSignalSemaphores = &semaphores.renderComplete;VkPresentInfoKHR presentInfo = {};presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;presentInfo.pNext = NULL;presentInfo.waitSemaphoreCount = 1;presentInfo.pWaitSemaphores = &semaphores.renderComplete;VkSwapchainKHR swapChains[] = { swapChain };presentInfo.swapchainCount = 1;presentInfo.pSwapchains = swapChains;presentInfo.pImageIndices = &imageIndex;//vkQueuePresentKHR函数提交请求呈现交换链中的图像result = vkQueuePresentKHR(presentQueue, &presentInfo);if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {recreateSwapChain();}else if (result != VK_SUCCESS) {throw std::runtime_error("failed to present swap chain image!");}vkQueueWaitIdle(presentQueue);currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;}void cleanup() {cleanupSwapChain();vkDestroySampler(device, textureSampler, nullptr);vkDestroyImageView(device, textureImageView, nullptr);vkDestroyImage(device, textureImage, nullptr);vkFreeMemory(device, textureImageMemory, nullptr);vkDestroyDescriptorPool(device, descriptorPool, nullptr);vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);// Uniform buffersuniformBuffers.GS.destroy();uniformBuffers.VS.destroy();vkDestroyBuffer(device, indexBuffer, nullptr);vkFreeMemory(device, indexBufferMemory, nullptr);vkDestroyBuffer(device, vertexBuffer, nullptr);vkFreeMemory(device, vertexBufferMemory, nullptr);vkDestroyCommandPool(device, commandPool, nullptr);vkDestroySemaphore(device, semaphores.presentComplete, nullptr);vkDestroySemaphore(device, semaphores.renderComplete, nullptr);for (auto shaderModule : shaderModules) {vkDestroyShaderModule(device, shaderModule, nullptr);}vkDestroyPipelineCache(device, pipelineCache, nullptr);models.object.destroy();vkDestroyDevice(device, nullptr);if (enableValidationLayers) {DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);}vkDestroySurfaceKHR(instance, surface, nullptr);vkDestroyInstance(instance, nullptr);glfwDestroyWindow(window);glfwTerminate();}void cleanupSwapChain() {vkDestroyImageView(device, colorImageView, nullptr);vkDestroyImage(device, colorImage, nullptr);vkFreeMemory(device, colorImageMemory, nullptr);vkDestroyImageView(device, depthImageView, nullptr);vkDestroyImage(device, depthImage, nullptr);vkFreeMemory(device, depthImageMemory, nullptr);for (auto framebuffer : frameBuffers) {vkDestroyFramebuffer(device, framebuffer, nullptr);}vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(drawCmdBuffers.size()), drawCmdBuffers.data());vkDestroyPipeline(device, pipelines.solid, nullptr);vkDestroyPipeline(device, pipelines.normals, nullptr);vkDestroyPipelineLayout(device, pipelineLayout, nullptr);vkDestroyRenderPass(device, renderPass, nullptr);for (auto imageView : swapChainImageViews) {vkDestroyImageView(device, imageView, nullptr);}vkDestroySwapchainKHR(device, swapChain, nullptr);}void updateUniformBuffers(){// Vertex shaderglm::mat4 viewMatrix = glm::mat4(1.0f);uboVS.projection = glm::perspective(glm::radians(fov), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 1000.0f);viewMatrix = camera.GetViewMatrix();uboVS.model = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f));uboVS.model = viewMatrix * uboVS.model;memcpy(uniformBuffers.VS.mapped, &uboVS, sizeof(uboVS));// Geometry shaderuboGS.model = uboVS.model;uboGS.projection = uboVS.projection;uboGS.viewportDim = glm::vec2(swapChainExtent.width, swapChainExtent.height);memcpy(uniformBuffers.GS.mapped, &uboGS, sizeof(uboGS));}static void onWindowResized(GLFWwindow* window, int width, int height) {if (width == 0 || height == 0) return;HelloTriangleApplication* app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));app->recreateSwapChain();}void recreateSwapChain() {int width = 0, height = 0;glfwGetFramebufferSize(window, &width, &height);while (width == 0 || height == 0) {glfwGetFramebufferSize(window, &width, &height);glfwWaitEvents();}vkDeviceWaitIdle(device);cleanupSwapChain();createSwapChain();createImageViews();createRenderPass();preparePipelines();createColorResources();createDepthResources();createFramebuffers();buildCommandBuffers();}void createInstance() {if (enableValidationLayers && !checkValidationLayerSupport()) {throw std::runtime_error("validation layers requested, but not available!");}VkApplicationInfo appInfo = {};appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pApplicationName = "Hello Triangle";appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.pEngineName = "No Engine";appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.apiVersion = VK_API_VERSION_1_0;VkInstanceCreateInfo createInfo = {};createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;createInfo.pApplicationInfo = &appInfo;auto extensions = getRequiredExtensions();createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());createInfo.ppEnabledExtensionNames = extensions.data();VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;if (enableValidationLayers) {createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());createInfo.ppEnabledLayerNames = validationLayers.data();populateDebugMessengerCreateInfo(debugCreateInfo);createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;}else {createInfo.enabledLayerCount = 0;createInfo.pNext = nullptr;}if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");}}void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {createInfo = {};createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;createInfo.pfnUserCallback = debugCallback;}void setupDebugMessenger() {if (!enableValidationLayers) return;VkDebugUtilsMessengerCreateInfoEXT createInfo;populateDebugMessengerCreateInfo(createInfo);if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {throw std::runtime_error("failed to set up debug messenger!");}}void createImageViews() {swapChainImageViews.resize(swapChainImages.size());for (size_t i = 0; i < swapChainImages.size(); i++) {swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);}}VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels) {VkImageViewCreateInfo viewInfo = {};viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;viewInfo.image = image;viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;viewInfo.format = format;viewInfo.subresourceRange.aspectMask = aspectFlags;viewInfo.subresourceRange.baseMipLevel = 0;viewInfo.subresourceRange.levelCount = mipLevels;viewInfo.subresourceRange.baseArrayLayer = 0;viewInfo.subresourceRange.layerCount = 1;VkImageView imageView;if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) {throw std::runtime_error("failed to create texture image view!");}return imageView;}void createSurface() {if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {throw std::runtime_error("failed to create window surface!");}}void pickPhysicalDevice() {uint32_t deviceCount = 0;vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);if (deviceCount == 0) {throw std::runtime_error("failed to find GPUs with Vulkan support!");}std::vector<VkPhysicalDevice> devices(deviceCount);vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());for (const auto& device : devices) {if (isDeviceSuitable(device)) {physicalDevice = device;msaaSamples = getMaxUsableSampleCount();break;}}if (physicalDevice == VK_NULL_HANDLE) {throw std::runtime_error("failed to find a suitable GPU!");}vulkanDevice = new vks::VulkanDevice(physicalDevice);VkPhysicalDeviceFeatures enabledFeatures{};std::vector<const char*> enabledDeviceExtensions;VkResult res = vulkanDevice->createLogicalDevice(enabledFeatures, enabledDeviceExtensions);}void createLogicalDevice() {QueueFamilyIndices indices = findQueueFamilies(physicalDevice);std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily, indices.presentFamily };float queuePriority = 1.0f;for (int queueFamily : uniqueQueueFamilies) {VkDeviceQueueCreateInfo queueCreateInfo = {};queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;queueCreateInfo.queueFamilyIndex = queueFamily;queueCreateInfo.queueCount = 1;queueCreateInfo.pQueuePriorities = &queuePriority;queueCreateInfos.push_back(queueCreateInfo);}VkPhysicalDeviceFeatures deviceFeatures = {};deviceFeatures.samplerAnisotropy = VK_TRUE;//deviceFeatures.sampleRateShading = VK_TRUE; // enable sample shading feature for the deviceVkDeviceCreateInfo createInfo = {};createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;createInfo.pQueueCreateInfos = queueCreateInfos.data();createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());createInfo.pEnabledFeatures = &deviceFeatures;createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());createInfo.ppEnabledExtensionNames = deviceExtensions.data();if (enableValidationLayers) {createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());createInfo.ppEnabledLayerNames = validationLayers.data();}else {createInfo.enabledLayerCount = 0;}if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {throw std::runtime_error("failed to create logical device!");}vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);vkGetDeviceQueue(device, indices.presentFamily, 0, &presentQueue);vulkanDevice->setVkDevice(device);}void createSwapChain() {SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {imageCount = swapChainSupport.capabilities.maxImageCount;}VkSwapchainCreateInfoKHR createInfo = {};createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;createInfo.surface = surface;createInfo.minImageCount = imageCount;createInfo.imageFormat = surfaceFormat.format;createInfo.imageColorSpace = surfaceFormat.colorSpace;createInfo.imageExtent = extent;createInfo.imageArrayLayers = 1;createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;QueueFamilyIndices indices = findQueueFamilies(physicalDevice);uint32_t queueFamilyIndices[] = { (uint32_t)indices.graphicsFamily, (uint32_t)indices.presentFamily };if (indices.graphicsFamily != indices.presentFamily) {createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;createInfo.queueFamilyIndexCount = 2;createInfo.pQueueFamilyIndices = queueFamilyIndices;}else {createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;createInfo.queueFamilyIndexCount = 0; // OptionalcreateInfo.pQueueFamilyIndices = nullptr; // Optional}createInfo.preTransform = swapChainSupport.capabilities.currentTransform;createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;createInfo.presentMode = presentMode;createInfo.clipped = VK_TRUE;createInfo.oldSwapchain = VK_NULL_HANDLE;if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {throw std::runtime_error("failed to create swap chain!");}vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);swapChainImages.resize(imageCount);vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());swapChainImageFormat = surfaceFormat.format;swapChainExtent = extent;}bool isDeviceSuitable(VkPhysicalDevice device) {QueueFamilyIndices indices = findQueueFamilies(device);bool extensionsSupported = checkDeviceExtensionSupport(device);bool swapChainAdequate = false;if (extensionsSupported) {SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();}//各向异性滤波器VkPhysicalDeviceFeatures supportedFeatures;vkGetPhysicalDeviceFeatures(device, &supportedFeatures);return indices.isComplete() && extensionsSupported && swapChainAdequate&& supportedFeatures.samplerAnisotropy;}VkSampleCountFlagBits getMaxUsableSampleCount() {return VK_SAMPLE_COUNT_1_BIT;VkPhysicalDeviceProperties physicalDeviceProperties;vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts;if (counts & VK_SAMPLE_COUNT_64_BIT) { return VK_SAMPLE_COUNT_64_BIT; }if (counts & VK_SAMPLE_COUNT_32_BIT) { return VK_SAMPLE_COUNT_32_BIT; }if (counts & VK_SAMPLE_COUNT_16_BIT) { return VK_SAMPLE_COUNT_16_BIT; }if (counts & VK_SAMPLE_COUNT_8_BIT) { return VK_SAMPLE_COUNT_8_BIT; }if (counts & VK_SAMPLE_COUNT_4_BIT) { return VK_SAMPLE_COUNT_4_BIT; }if (counts & VK_SAMPLE_COUNT_2_BIT) { return VK_SAMPLE_COUNT_2_BIT; }return VK_SAMPLE_COUNT_1_BIT;}void createRenderPass() {VkAttachmentDescription colorAttachment = {};colorAttachment.format = swapChainImageFormat;colorAttachment.samples = msaaSamples;//多重采样colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;//我们已经将finalLayout从VK_IMAGE_LAYOUT_PRESENT_SRC_KHR修改为VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL。//这是因为多采样图像不能直接呈现。我们首先需要将它们解析为一个常规图像。这个要求不适用于深度缓冲区,因为它在任何时候都不会显示。因此,我们只需要添加一个新的颜色附件,即所谓的解析附件colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;// Depth attachmentVkAttachmentDescription depthAttachment = {};depthAttachment.format = depthFormat;depthAttachment.samples = msaaSamples;//多重采样depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;//添加一个新的颜色附件VkAttachmentDescription colorAttachmentResolve = {};colorAttachmentResolve.format = swapChainImageFormat;colorAttachmentResolve.samples = msaaSamples;colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;VkAttachmentReference colorAttachmentRef = {};colorAttachmentRef.attachment = 0;colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;VkAttachmentReference depthAttachmentRef = {};depthAttachmentRef.attachment = 1;depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;//创建一个新的附件引用,指向作为解析目标的颜色缓冲区VkAttachmentReference colorAttachmentResolveRef = {};colorAttachmentResolveRef.attachment = 2;colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;VkSubpassDescription subpass = {};subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;subpass.colorAttachmentCount = 1;subpass.pColorAttachments = &colorAttachmentRef;subpass.pDepthStencilAttachment = &depthAttachmentRef;subpass.pResolveAttachments = &colorAttachmentResolveRef;//让渲染通道定义一个多采样解析操作,让我们渲染图像到屏幕std::array<VkAttachmentDescription, 3> attachments = { colorAttachment, depthAttachment, colorAttachmentResolve };VkRenderPassCreateInfo renderPassInfo = {};renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());renderPassInfo.pAttachments = attachments.data();renderPassInfo.subpassCount = 1;renderPassInfo.pSubpasses = &subpass;VkSubpassDependency dependency = {};dependency.srcSubpass = VK_SUBPASS_EXTERNAL;dependency.dstSubpass = 0;dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;dependency.srcAccessMask = 0;dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;renderPassInfo.dependencyCount = 1;renderPassInfo.pDependencies = &dependency;if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {throw std::runtime_error("failed to create render pass!");}}VkShaderModule createShaderModule(const std::vector<char>& code) {VkShaderModuleCreateInfo createInfo = {};createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;createInfo.codeSize = code.size();createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());VkShaderModule shaderModule;if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {throw std::runtime_error("failed to create shader module!");}return shaderModule;}static 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!");}size_t fileSize = (size_t)file.tellg();std::vector<char> buffer(fileSize);file.seekg(0);file.read(buffer.data(), fileSize);file.close();return buffer;}void createSemaphores() {// Create synchronization objectsVkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo();// Create a semaphore used to synchronize image presentation// Ensures that the image is displayed before we start submitting new commands to the queuif (vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.presentComplete)) {throw std::runtime_error("failed to create synchronization objects for a frame!");}// Create a semaphore used to synchronize command submission// Ensures that the image is not presented until all commands have been sumbitted and executedif (vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.renderComplete)) {throw std::runtime_error("failed to create synchronization objects for a frame!");}// Set up submit info structure// Semaphores will stay the same during application lifetime// Command buffer submission info is set by each examplesubmitInfo = vks::initializers::submitInfo();submitInfo.pWaitDstStageMask = &submitPipelineStages;submitInfo.waitSemaphoreCount = 1;submitInfo.pWaitSemaphores = &semaphores.presentComplete;submitInfo.signalSemaphoreCount = 1;submitInfo.pSignalSemaphores = &semaphores.renderComplete;}void buildCommandBuffers(){drawCmdBuffers.resize(frameBuffers.size());VkCommandBufferAllocateInfo allocInfo = {};allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;allocInfo.commandPool = commandPool;allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;allocInfo.commandBufferCount = (uint32_t)drawCmdBuffers.size();if (vkAllocateCommandBuffers(device, &allocInfo, drawCmdBuffers.data()) != VK_SUCCESS) {throw std::runtime_error("failed to allocate command buffers!");}VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();VkClearValue clearValues[2];clearValues[0].color = { { 0.1f, 0.1f, 0.3f, 0.5f } };clearValues[1].depthStencil = { 1.0f, 0 };VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();renderPassBeginInfo.renderPass = renderPass;renderPassBeginInfo.renderArea.offset.x = 0;renderPassBeginInfo.renderArea.offset.y = 0;renderPassBeginInfo.renderArea.extent.width = swapChainExtent.width;renderPassBeginInfo.renderArea.extent.height = swapChainExtent.height;renderPassBeginInfo.clearValueCount = 2;renderPassBeginInfo.pClearValues = clearValues;for (int32_t i = 0; i < drawCmdBuffers.size(); ++i){// Set target frame bufferrenderPassBeginInfo.framebuffer = frameBuffers[i];VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);VkViewport viewport = vks::initializers::viewport((float)swapChainExtent.width, (float)swapChainExtent.height, 0.0f, 1.0f);vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);VkRect2D scissor = vks::initializers::rect2D(swapChainExtent.width, swapChainExtent.height, 0, 0);vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);vkCmdSetLineWidth(drawCmdBuffers[i], 1.0f);vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);VkDeviceSize offsets[1] = { 0 };vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.object.vertices.buffer, offsets);vkCmdBindIndexBuffer(drawCmdBuffers[i], models.object.indices.buffer, 0, VK_INDEX_TYPE_UINT32);// Solid shadingvkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid);vkCmdDrawIndexed(drawCmdBuffers[i], models.object.indexCount, 1, 0, 0, 0);// Normal debuggingif (displayNormals){vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.normals);vkCmdDrawIndexed(drawCmdBuffers[i], models.object.indexCount, 1, 0, 0, 0);}vkCmdEndRenderPass(drawCmdBuffers[i]);VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));}}void createCommandPool() {QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);VkCommandPoolCreateInfo poolInfo = {};poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily;poolInfo.flags = 0; // Optionalif (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {throw std::runtime_error("failed to create command pool!");}vulkanDevice->setVkCommandPool(commandPool);}bool hasStencilComponent(VkFormat format) {return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;}void createColorResources() {VkFormat colorFormat = swapChainImageFormat;createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, colorFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, colorImage, colorImageMemory);colorImageView = createImageView(colorImage, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);transitionImageLayout(colorImage, colorFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1);}void createDepthResources() {createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);//createImage(swapChainExtent.width, swapChainExtent.height, 1, VK_SAMPLE_COUNT_1_BIT, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1);}void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {VkImageCreateInfo imageInfo = {};imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;imageInfo.imageType = VK_IMAGE_TYPE_2D;imageInfo.extent.width = width;imageInfo.extent.height = height;imageInfo.extent.depth = 1;imageInfo.mipLevels = mipLevels;imageInfo.arrayLayers = 1;imageInfo.format = format;imageInfo.tiling = tiling;imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;imageInfo.usage = usage;imageInfo.samples = numSamples;imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) {throw std::runtime_error("failed to create image!");}VkMemoryRequirements memRequirements;vkGetImageMemoryRequirements(device, image, &memRequirements);VkMemoryAllocateInfo allocInfo = {};allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;allocInfo.allocationSize = memRequirements.size;allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {throw std::runtime_error("failed to allocate image memory!");}vkBindImageMemory(device, image, imageMemory, 0);}void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels) {VkCommandBuffer commandBuffer = beginSingleTimeCommands();VkImageMemoryBarrier barrier = {};barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;barrier.oldLayout = oldLayout;barrier.newLayout = newLayout;barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;barrier.image = image;barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;barrier.subresourceRange.baseMipLevel = 0;barrier.subresourceRange.levelCount = mipLevels;barrier.subresourceRange.baseArrayLayer = 0;barrier.subresourceRange.layerCount = 1;if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;if (hasStencilComponent(format)) {barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;}}else {barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;}VkPipelineStageFlags sourceStage;VkPipelineStageFlags destinationStage;if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {barrier.srcAccessMask = 0;barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;}else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;}else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {barrier.srcAccessMask = 0;barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;}else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {barrier.srcAccessMask = 0;barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;}else {throw std::invalid_argument("unsupported layout transition!");}vkCmdPipelineBarrier(commandBuffer,sourceStage, destinationStage,0,0, nullptr,0, nullptr,1, &barrier);endSingleTimeCommands(commandBuffer);}void loadAssets(){//std::vector<std::string> filenames = { "sphere.obj", "teapot.dae", "torusknot.obj", "venus.fbx" };models.object.loadFromFile("models/teapot.dae", vertexLayout, 10.0f, vulkanDevice, graphicsQueue);}void setupVertexDescriptions(){// Binding descriptionvertices.bindingDescriptions.resize(1);vertices.bindingDescriptions[0] =vks::initializers::vertexInputBindingDescription(VERTEX_BUFFER_BIND_ID,vertexLayout.stride(),VK_VERTEX_INPUT_RATE_VERTEX);// Attribute descriptions// Describes memory layout and shader positionsvertices.attributeDescriptions.resize(3);// Location 0 : Positionvertices.attributeDescriptions[0] =vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID,0,VK_FORMAT_R32G32B32_SFLOAT,0);// Location 1 : Normalsvertices.attributeDescriptions[1] =vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID,1,VK_FORMAT_R32G32B32_SFLOAT,sizeof(float) * 3);// Location 2 : Colorvertices.attributeDescriptions[2] =vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID,2,VK_FORMAT_R32G32B32_SFLOAT,sizeof(float) * 6);// Assign to vertex buffervertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo();vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size();vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size();vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();}// Prepare and initialize uniform buffer containing shader uniformsvoid prepareUniformBuffers(){// Vertex shader uniform buffer blockVK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,&uniformBuffers.VS,sizeof(uboVS)));// Geometry shader uniform buffer blockVK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,&uniformBuffers.GS,sizeof(uboGS)));// Map persistentVK_CHECK_RESULT(uniformBuffers.VS.map());VK_CHECK_RESULT(uniformBuffers.GS.map());updateUniformBuffers();}void setupDescriptorPool(){// Example uses two ubosstd::vector<VkDescriptorPoolSize> poolSizes ={vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2),};VkDescriptorPoolCreateInfo descriptorPoolInfo =vks::initializers::descriptorPoolCreateInfo(poolSizes.size(),poolSizes.data(),2);VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));}void setupDescriptorSetLayout(){std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings ={// Binding 0 : Vertex shader ubovks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,VK_SHADER_STAGE_VERTEX_BIT,0),// Binding 1 : Geometry shader ubovks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,VK_SHADER_STAGE_GEOMETRY_BIT,1)};VkDescriptorSetLayoutCreateInfo descriptorLayout =vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(),setLayoutBindings.size());VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout,1);VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));}void setupDescriptorSets(){VkDescriptorSetAllocateInfo allocInfo =vks::initializers::descriptorSetAllocateInfo(descriptorPool,&descriptorSetLayout,1);VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));std::vector<VkWriteDescriptorSet> writeDescriptorSets ={// Binding 0 : Vertex shader shader ubovks::initializers::writeDescriptorSet(descriptorSet,VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,0,&uniformBuffers.VS.descriptor),// Binding 1 : Geometry shader ubovks::initializers::writeDescriptorSet(descriptorSet,VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,1,&uniformBuffers.GS.descriptor)};vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);}//创建缓冲区void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {//创建缓冲区VkBufferCreateInfo bufferInfo = {};bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;bufferInfo.size = size;bufferInfo.usage = usage;bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {throw std::runtime_error("failed to create buffer!");}//内存需求VkMemoryRequirements memRequirements;vkGetBufferMemoryRequirements(device, buffer, &memRequirements);//内存分配VkMemoryAllocateInfo allocInfo = {};allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;allocInfo.allocationSize = memRequirements.size;allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {throw std::runtime_error("failed to allocate buffer memory!");}//将内存关联到缓冲区vkBindBufferMemory(device, buffer, bufferMemory, 0);}//用于从一个缓冲区拷贝数据到另一个缓冲区void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {VkCommandBufferAllocateInfo allocInfo = {};allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;allocInfo.commandPool = commandPool;allocInfo.commandBufferCount = 1;VkCommandBuffer commandBuffer;vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);VkCommandBufferBeginInfo beginInfo = {};beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;vkBeginCommandBuffer(commandBuffer, &beginInfo);VkBufferCopy copyRegion = {};copyRegion.size = size;vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);vkEndCommandBuffer(commandBuffer);VkSubmitInfo submitInfo = {};submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;submitInfo.commandBufferCount = 1;submitInfo.pCommandBuffers = &commandBuffer;vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);vkQueueWaitIdle(graphicsQueue);vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);}VkCommandBuffer beginSingleTimeCommands() {VkCommandBufferAllocateInfo allocInfo = {};allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;allocInfo.commandPool = commandPool;allocInfo.commandBufferCount = 1;VkCommandBuffer commandBuffer;vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);VkCommandBufferBeginInfo beginInfo = {};beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;vkBeginCommandBuffer(commandBuffer, &beginInfo);return commandBuffer;}void endSingleTimeCommands(VkCommandBuffer commandBuffer) {vkEndCommandBuffer(commandBuffer);VkSubmitInfo submitInfo = {};submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;submitInfo.commandBufferCount = 1;submitInfo.pCommandBuffers = &commandBuffer;vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);vkQueueWaitIdle(graphicsQueue);vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);}uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {VkPhysicalDeviceMemoryProperties memProperties;vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {return i;}}throw std::runtime_error("failed to find suitable memory type!");}void createFramebuffers() {frameBuffers.resize(swapChainImageViews.size());for (size_t i = 0; i < swapChainImageViews.size(); i++) {//渲染通道就绪后,修改createframebuffer并将新的图像视图添加到列表中:std::array<VkImageView, 3> attachments = {colorImageView,depthImageView,swapChainImageViews[i]};VkFramebufferCreateInfo framebufferInfo = {};framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;framebufferInfo.renderPass = renderPass;framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());framebufferInfo.pAttachments = attachments.data();framebufferInfo.width = swapChainExtent.width;framebufferInfo.height = swapChainExtent.height;framebufferInfo.layers = 1;if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &frameBuffers[i]) != VK_SUCCESS) {throw std::runtime_error("failed to create framebuffer!");}}}void preparePipelines(){VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,0,VK_FALSE);VkPipelineRasterizationStateCreateInfo rasterizationState =vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL,VK_CULL_MODE_NONE,VK_FRONT_FACE_CLOCKWISE,0);VkPipelineColorBlendAttachmentState blendAttachmentState =vks::initializers::pipelineColorBlendAttachmentState(0xf,VK_FALSE);VkPipelineColorBlendStateCreateInfo colorBlendState =vks::initializers::pipelineColorBlendStateCreateInfo(1,&blendAttachmentState);VkPipelineDepthStencilStateCreateInfo depthStencilState =vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE,VK_TRUE,VK_COMPARE_OP_LESS_OR_EQUAL);VkPipelineViewportStateCreateInfo viewportState =vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);VkPipelineMultisampleStateCreateInfo multisampleState =vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT,0);std::vector<VkDynamicState> dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT,VK_DYNAMIC_STATE_SCISSOR,VK_DYNAMIC_STATE_LINE_WIDTH};VkPipelineDynamicStateCreateInfo dynamicState =vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(),dynamicStateEnables.size(),0);// Tessellation pipeline// Load shadersstd::array<VkPipelineShaderStageCreateInfo, 3> shaderStages;shaderStages[0] = loadShader("shaders/geometryshader/base.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);shaderStages[1] = loadShader("shaders/geometryshader/base.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);shaderStages[2] = loadShader("shaders/geometryshader/normaldebug.geom.spv", VK_SHADER_STAGE_GEOMETRY_BIT);VkGraphicsPipelineCreateInfo pipelineCreateInfo =vks::initializers::pipelineCreateInfo(pipelineLayout,renderPass,0);pipelineCreateInfo.pVertexInputState = &vertices.inputState;pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;pipelineCreateInfo.pRasterizationState = &rasterizationState;pipelineCreateInfo.pColorBlendState = &colorBlendState;pipelineCreateInfo.pMultisampleState = &multisampleState;pipelineCreateInfo.pViewportState = &viewportState;pipelineCreateInfo.pDepthStencilState = &depthStencilState;pipelineCreateInfo.pDynamicState = &dynamicState;pipelineCreateInfo.stageCount = shaderStages.size();pipelineCreateInfo.pStages = shaderStages.data();pipelineCreateInfo.renderPass = renderPass;// Normal debugging pipelineVK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.normals));// Solid rendering pipelineshaderStages[0] = loadShader("shaders/geometryshader/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);shaderStages[1] = loadShader("shaders/geometryshader/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);pipelineCreateInfo.stageCount = 2;VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid));}bool checkDeviceExtensionSupport(VkPhysicalDevice device) {uint32_t extensionCount;vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);std::vector<VkExtensionProperties> availableExtensions(extensionCount);vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());for (const auto& extension : availableExtensions) {requiredExtensions.erase(extension.extensionName);}return requiredExtensions.empty();}VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {return capabilities.currentExtent;}else {int width, height;glfwGetFramebufferSize(window, &width, &height);VkExtent2D actualExtent = {static_cast<uint32_t>(width),static_cast<uint32_t>(height)};//VkExtent2D actualExtent = { WIDTH, HEIGHT };actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));return actualExtent;}}SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {SwapChainSupportDetails details;vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);uint32_t formatCount;vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);if (formatCount != 0) {details.formats.resize(formatCount);vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());}uint32_t presentModeCount;vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);if (presentModeCount != 0) {details.presentModes.resize(presentModeCount);vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());}return details;}VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) {return { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };}for (const auto& availableFormat : availableFormats) {if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {return availableFormat;}}return availableFormats[0];}VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes) {VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;for (const auto& availablePresentMode : availablePresentModes) {if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {return availablePresentMode;}else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {bestMode = availablePresentMode;}}return bestMode;}QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {QueueFamilyIndices indices;uint32_t queueFamilyCount = 0;vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());int i = 0;for (const auto& queueFamily : queueFamilies) {if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {indices.graphicsFamily = i;}VkBool32 presentSupport = false;vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);if (presentSupport) {indices.presentFamily = i;}if (indices.isComplete()) {break;}i++;}return indices;}std::vector<const char*> getRequiredExtensions() {uint32_t glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);if (enableValidationLayers) {extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);}return extensions;}bool checkValidationLayerSupport() {uint32_t layerCount;vkEnumerateInstanceLayerProperties(&layerCount, nullptr);std::vector<VkLayerProperties> availableLayers(layerCount);vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());for (const char* layerName : validationLayers) {bool layerFound = false;for (const auto& layerProperties : availableLayers) {if (strcmp(layerName, layerProperties.layerName) == 0) {layerFound = true;break;}}if (!layerFound) {return false;}}return true;}static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;return VK_FALSE;}VkBool32 getSupportedDepthFormat(){// Since all depth formats may be optional, we need to find a suitable depth format to use// Start with the highest precision packed formatstd::vector<VkFormat> depthFormats = {VK_FORMAT_D32_SFLOAT_S8_UINT,VK_FORMAT_D32_SFLOAT,VK_FORMAT_D24_UNORM_S8_UINT,VK_FORMAT_D16_UNORM_S8_UINT,VK_FORMAT_D16_UNORM};for (auto& format : depthFormats){VkFormatProperties formatProps;vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);// Format must support depth stencil attachment for optimal tilingif (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT){depthFormat = format;return true;}}return false;}void createPipelineCache(){VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;if (vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache)) {throw std::runtime_error("failed to create image!");}}/*** Create a buffer on the device** @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)* @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)* @param buffer Pointer to a vk::Vulkan buffer object* @param size Size of the buffer in byes* @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)** @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied*/VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vks::Buffer *buffer, VkDeviceSize size, void *data = nullptr){buffer->device = device;// Create the buffer handleVkBufferCreateInfo bufferCreateInfo{};bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;bufferCreateInfo.usage = usageFlags;bufferCreateInfo.size = size;if (vkCreateBuffer(device, &bufferCreateInfo, nullptr, &buffer->buffer)) {throw std::runtime_error("failed to create!");}// Create the memory backing up the buffer handleVkMemoryRequirements memReqs;VkMemoryAllocateInfo memAlloc{};memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;vkGetBufferMemoryRequirements(device, buffer->buffer, &memReqs);memAlloc.allocationSize = memReqs.size;// Find a memory type index that fits the properties of the buffermemAlloc.memoryTypeIndex = findMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);if (vkAllocateMemory(device, &memAlloc, nullptr, &buffer->memory)) {throw std::runtime_error("failed to create!");}buffer->alignment = memReqs.alignment;buffer->size = memAlloc.allocationSize;buffer->usageFlags = usageFlags;buffer->memoryPropertyFlags = memoryPropertyFlags;// If a pointer to the buffer data has been passed, map the buffer and copy over the dataif (data != nullptr){if (buffer->map()) {throw std::runtime_error("failed to create!");}memcpy(buffer->mapped, data, size);buffer->unmap();}// Initialize a default descriptor that covers the whole buffer sizebuffer->setupDescriptor();// Attach the memory to the buffer objectreturn buffer->bind();}VkShaderModule loadShader(const char *fileName, VkDevice device){std::ifstream is(fileName, std::ios::binary | std::ios::in | std::ios::ate);if (is.is_open()){size_t size = is.tellg();is.seekg(0, std::ios::beg);char* shaderCode = new char[size];is.read(shaderCode, size);is.close();assert(size > 0);VkShaderModule shaderModule;VkShaderModuleCreateInfo moduleCreateInfo{};moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;moduleCreateInfo.codeSize = size;moduleCreateInfo.pCode = (uint32_t*)shaderCode;if (vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule)){}delete[] shaderCode;return shaderModule;}else{std::cerr << "Error: Could not open shader file \"" << fileName << "\"" << std::endl;return VK_NULL_HANDLE;}}VkPipelineShaderStageCreateInfo loadShader(std::string fileName, VkShaderStageFlagBits stage){VkPipelineShaderStageCreateInfo shaderStage = {};shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;shaderStage.stage = stage;shaderStage.module = loadShader(fileName.c_str(), device);shaderStage.pName = "main"; // todo : make paramassert(shaderStage.module != VK_NULL_HANDLE);shaderModules.push_back(shaderStage.module);return shaderStage;}/*** Allocate a command buffer from the command pool** @param level Level of the new command buffer (primary or secondary)* @param (Optional) begin If true, recording on the new command buffer will be started (vkBeginCommandBuffer) (Defaults to false)** @return A handle to the allocated command buffer*/VkCommandBuffer createCommandBuffer(VkCommandBufferLevel level, bool begin = false){VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(commandPool, level, 1);VkCommandBuffer cmdBuffer;if (vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &cmdBuffer) != VK_SUCCESS) {throw std::runtime_error("failed to record command buffer!");}// If requested, also start recording for the new command bufferif (begin){VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();if (vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo) != VK_SUCCESS) {throw std::runtime_error("failed to record command buffer!");}}return cmdBuffer;}void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free){if (commandBuffer == VK_NULL_HANDLE){return;}VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));VkSubmitInfo submitInfo = {};submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;submitInfo.commandBufferCount = 1;submitInfo.pCommandBuffers = &commandBuffer;VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));VK_CHECK_RESULT(vkQueueWaitIdle(queue));if (free){vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);}}};int main() {HelloTriangleApplication app;try {app.run();}catch (const std::exception& e) {std::cerr << e.what() << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}

Vulkan_Shader—几何着色器之法线可视化相关推荐

  1. 翻译:探索GLSL-用几何着色器(着色器库)实现法线可视化

    翻译:探索GLSL-用几何着色器(着色器库)实现法线可视化 翻译自: Exploring GLSL – Normal Visualizer with Geometry Shaders (Shader ...

  2. 第二十二章 opengl之高级OpenGL(几何着色器)

    OpenGL 使用几何着色器 用点造物体 爆破物体 法向量可视化 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader), 几何着色器的输入是一个图元(如点或三角形)的一组顶点 ...

  3. 【OpenGL】笔记二十七、几何着色器

    1. 流程 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点.几何着色器可以在顶点发送到下一着色器阶段之前对它们随意 ...

  4. LearnOpenGL学习笔记——几何着色器

    几何着色器 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点.几何着色器可以在顶点发送到下一着色器阶段之前对它们随意 ...

  5. LearnOpenGL-高级OpenGL-9.几何着色器

    本人初学者,文中定有代码.术语等错误,欢迎指正 文章目录 几何着色器 使用几何着色器 造几个房子 爆破物体 法向量可视化 几何着色器 简介 在顶点和片段着色器之间有一个可选的几何着色器 几何着色器的输 ...

  6. OpenGL学习笔记(十)-几何着色器-实例化

    参考网址:LearnOpenGL 中文版 4.7 几何着色器 4.7.1 基本概念 1.顶点和片段着色器之间有一个可选的几何着色器,几何着色器的输入是一个图元(如点或三角形)的一组顶点,顶点发送到下一 ...

  7. OpenGL 几何着色器Geometry Shader

    OpenGL几何着色器Geometry Shader 几何着色器Geometry Shader简介 使用几何着色器 造几个房子 爆破物体 法向量可视化 几何着色器Geometry Shader简介 在 ...

  8. OpenGL基础41:几何着色器

    在顶点着色器之后,片段着色器之前,还有几何着色器,它是可选的,在<OpenGL基础3:渲染管线>这一章中就有提到了,有了几何着色器后可以做很多骚操作,更容易实现很多有意思的效果 一.最简单 ...

  9. Shader入门---曲面细分着色器和几何着色器

    Shader入门-曲面细分着色器和几何着色器 前记:学不可以停止-------------------------------mx 基础知识: 曲面细分着色器:可以将一个几何体细化为一个球体也能将一根 ...

最新文章

  1. mysql触发器执行失败_mysql-Mysql数据库触发器执行不成功
  2. UA OPTI501 电磁波4 电介质及其极化
  3. mi2 android 5.0 方法,小米2/2S怎么刷Android5.0 小米2/2S刷Android5.0教程【详解】
  4. jquery.placeholder.min.js让你的IE浏览器支持placeholder
  5. Java 自定义排序 Comparator
  6. 链接ftp,把文件或图片上传到ftp指定的文件夹中
  7. java字面量和符号引用_JVM中的直接引用和符号引用
  8. java修改.class重新打包jar
  9. 使用Windows迁移工具迁移2003至2012R2 二、IP迁移
  10. 阿里云发布ET环境大脑 对抗雾霾、排污和自然灾害
  11. VFIO IOMMU简介
  12. Oracle BI系统排名?Oracle BI办公系统怎么选?什么是用户口碑最好的Oracle BI系统?
  13. 学习笔记:12864液晶模块的详细使用
  14. char数组打印地址和内容;
  15. Linux命令总结大全,包含所有linux命令
  16. linux系统怎样设置分屏显示器,话说你们的双屏显示器是怎样设置的 尤其是外接显示器分辨率设置...
  17. 论如何成为技术大牛,GitHub中国区前20名详解
  18. 雅虎首席产品官Blake Irving:打造个性化产品的“架子鼓手”
  19. opengl 知识点2
  20. 三维模型obj文件解析

热门文章

  1. android videoview截屏,如何进行网络视频截图/获取视频的缩略图
  2. Android 关于8.0的Service问题(Not allowed to start service Intent)
  3. 销售管理的工作原理(ERP的工作原理5)------(转)
  4. 怎样正确使用和维护微型计算机,微型计算机使用注意事项及保养的一般方法
  5. Python Flask中的jsonify
  6. MindManager22专业版思维导图工具
  7. 网页设计排版的10个小技巧!
  8. 仿开眼app—Kotlin+MVVM+DataBinding
  9. linux|管道符号
  10. 三坐标测头标定原理和标准球实操