Multiple Object renderinggit add .git add . Completely revamped the model loading system using Model class instances, uses a Material class to build textures, clean slated descriptor sets for bindless rendering, significantly shortening the amount of code needed to load VkImage, VkImageView, and VkSampler. Added multiple texture rendering, abstracted out model loading process to automatically collect all Model instances and render for each object.
This commit is contained in:
parent
e2ef2e4134
commit
d862068c6e
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/material.h.3635D536A26B1F7D.idx
Normal file
BIN
.cache/clangd/index/material.h.3635D536A26B1F7D.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
4
Makefile
4
Makefile
@ -4,7 +4,7 @@ LDFLAGS=-lglfw -Ilib -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi -ltinyobjloade
|
|||||||
MAKEFLAGS += -j16
|
MAKEFLAGS += -j16
|
||||||
SRC = $(shell find . -name "*.cpp")
|
SRC = $(shell find . -name "*.cpp")
|
||||||
CSRC = $(shell find . -name "*.c")
|
CSRC = $(shell find . -name "*.c")
|
||||||
SHDRSRC = $(shell find . -name "*.frag" -o -name "*vert")
|
SHDRSRC = $(shell find . -name "*.frag" -o -name "*.vert")
|
||||||
SPV = $(SHDRSRC:%.vert=%.spv) $(SHDRSRC:%.frag=%.spv)
|
SPV = $(SHDRSRC:%.vert=%.spv) $(SHDRSRC:%.frag=%.spv)
|
||||||
OBJ = $(SRC:%.cpp=%.o)
|
OBJ = $(SRC:%.cpp=%.o)
|
||||||
COBJ=$(CSRC:%.c=%.o)
|
COBJ=$(CSRC:%.c=%.o)
|
||||||
@ -48,6 +48,8 @@ $(BIN): $(OBJ) $(COBJ) $(SPV)
|
|||||||
glslc $< -o $@
|
glslc $< -o $@
|
||||||
%.spv: %.vert
|
%.spv: %.vert
|
||||||
glslc $< -o $@
|
glslc $< -o $@
|
||||||
|
%.spv: %.glsl
|
||||||
|
glslc $< -o $@
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
@ -3,6 +3,6 @@ Pos=60,60
|
|||||||
Size=400,400
|
Size=400,400
|
||||||
|
|
||||||
[Window][Agnosia Debug]
|
[Window][Agnosia Debug]
|
||||||
Pos=522,0
|
Pos=40,377
|
||||||
Size=583,202
|
Size=623,438
|
||||||
|
|
||||||
|
@ -2,23 +2,32 @@
|
|||||||
#include "devicelibrary.h"
|
#include "devicelibrary.h"
|
||||||
#include "entrypoint.h"
|
#include "entrypoint.h"
|
||||||
#include "graphics/buffers.h"
|
#include "graphics/buffers.h"
|
||||||
|
#include "graphics/graphicspipeline.h"
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imgui_impl_glfw.h"
|
#include "imgui_impl_glfw.h"
|
||||||
#include "imgui_impl_vulkan.h"
|
#include "imgui_impl_vulkan.h"
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
VkDescriptorPool imGuiDescriptorPool;
|
VkDescriptorPool imGuiDescriptorPool;
|
||||||
|
|
||||||
void initImGuiWindow() {
|
void initImGuiWindow() {
|
||||||
|
if (ImGui::TreeNode("Model Transforms")) {
|
||||||
|
for (Model *model : Model::getInstances()) {
|
||||||
|
|
||||||
ImGui::DragFloat3("Object Position", Buffers::getObjPos());
|
ImGui::DragFloat3(model->getID().c_str(),
|
||||||
ImGui::DragFloat3("Camera Position", Buffers::getCamPos());
|
const_cast<float *>(glm::value_ptr(model->getPos())));
|
||||||
ImGui::DragFloat3("Center Position", Buffers::getCenterPos());
|
}
|
||||||
ImGui::DragFloat3("Up Direction", Buffers::getUpDir());
|
ImGui::TreePop();
|
||||||
ImGui::DragFloat("Depth of Field", &Buffers::getDepthField(), 0.1f, 1.0f,
|
}
|
||||||
|
|
||||||
|
ImGui::DragFloat3("Camera Position", Graphics::getCamPos());
|
||||||
|
ImGui::DragFloat3("Center Position", Graphics::getCenterPos());
|
||||||
|
ImGui::DragFloat3("Up Direction", Graphics::getUpDir());
|
||||||
|
ImGui::DragFloat("Depth of Field", &Graphics::getDepthField(), 0.1f, 1.0f,
|
||||||
180.0f, NULL, ImGuiSliderFlags_AlwaysClamp);
|
180.0f, NULL, ImGuiSliderFlags_AlwaysClamp);
|
||||||
ImGui::DragFloat2("Near and Far fields", Buffers::getDistanceField());
|
ImGui::DragFloat2("Near and Far fields", Graphics::getDistanceField());
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawTabs() {
|
void drawTabs() {
|
||||||
@ -37,8 +46,6 @@ void Gui::drawImGui() {
|
|||||||
ImGui_ImplVulkan_NewFrame();
|
ImGui_ImplVulkan_NewFrame();
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
// 2. Show a simple window that we create ourselves. We use a Begin/End pair
|
|
||||||
// to create a named window.
|
|
||||||
|
|
||||||
ImGui::Begin("Agnosia Debug");
|
ImGui::Begin("Agnosia Debug");
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vulkan/vulkan_core.h>
|
|
||||||
|
|
||||||
VkPhysicalDeviceProperties deviceProperties;
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
@ -303,18 +302,31 @@ void DeviceControl::createLogicalDevice() {
|
|||||||
VkPhysicalDeviceVulkan12Features features12{
|
VkPhysicalDeviceVulkan12Features features12{
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
|
.shaderSampledImageArrayNonUniformIndexing = true,
|
||||||
|
.shaderStorageBufferArrayNonUniformIndexing = true,
|
||||||
|
.shaderStorageImageArrayNonUniformIndexing = true,
|
||||||
|
.descriptorBindingSampledImageUpdateAfterBind = true,
|
||||||
|
.descriptorBindingStorageImageUpdateAfterBind = true,
|
||||||
|
.descriptorBindingStorageBufferUpdateAfterBind = true,
|
||||||
|
.descriptorBindingUpdateUnusedWhilePending = true,
|
||||||
|
.descriptorBindingPartiallyBound = true,
|
||||||
|
.runtimeDescriptorArray = true,
|
||||||
|
.scalarBlockLayout = true,
|
||||||
.bufferDeviceAddress = true,
|
.bufferDeviceAddress = true,
|
||||||
|
|
||||||
};
|
};
|
||||||
VkPhysicalDeviceVulkan13Features features13{
|
VkPhysicalDeviceVulkan13Features features13{
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
|
||||||
.pNext = &features12,
|
.pNext = &features12,
|
||||||
.synchronization2 = true,
|
.synchronization2 = true,
|
||||||
.dynamicRendering = true,
|
.dynamicRendering = true,
|
||||||
|
|
||||||
};
|
};
|
||||||
VkPhysicalDeviceFeatures featuresBase{
|
VkPhysicalDeviceFeatures featuresBase{
|
||||||
.robustBufferAccess = true,
|
.robustBufferAccess = true,
|
||||||
.sampleRateShading = true,
|
.sampleRateShading = true,
|
||||||
.samplerAnisotropy = true,
|
.samplerAnisotropy = true,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures2 deviceFeatures{
|
VkPhysicalDeviceFeatures2 deviceFeatures{
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "entrypoint.h"
|
#include "entrypoint.h"
|
||||||
#include "graphics/buffers.h"
|
#include "graphics/buffers.h"
|
||||||
#include "graphics/graphicspipeline.h"
|
#include "graphics/graphicspipeline.h"
|
||||||
|
|
||||||
#include "graphics/model.h"
|
#include "graphics/model.h"
|
||||||
#include "graphics/render.h"
|
#include "graphics/render.h"
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
@ -88,6 +89,22 @@ void createInstance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initVulkan() {
|
void initVulkan() {
|
||||||
|
Material *vikingRoomMaterial =
|
||||||
|
new Material("vikingRoomMaterial", "assets/textures/viking_room.png");
|
||||||
|
Material *stanfordDragonMaterial =
|
||||||
|
new Material("stanfordDragonMaterial", "assets/textures/checkermap.png");
|
||||||
|
Material *teapotMaterial =
|
||||||
|
new Material("teapotMaterial", "assets/textures/checkermap.png");
|
||||||
|
Model *vikingRoom =
|
||||||
|
new Model("vikingRoom", *vikingRoomMaterial,
|
||||||
|
"assets/models/viking_room.obj", glm::vec3(0.0f, 0.0f, 0.0f));
|
||||||
|
Model *stanfordDragon = new Model("stanfordDragon", *stanfordDragonMaterial,
|
||||||
|
"assets/models/StanfordDragon800k.obj",
|
||||||
|
glm::vec3(0.0f, 2.0f, 0.0f));
|
||||||
|
Model *teapot =
|
||||||
|
new Model("teapot", *teapotMaterial, "assets/models/teapot.obj",
|
||||||
|
glm::vec3(1.0f, -3.0f, -1.0f));
|
||||||
|
|
||||||
// Initialize volk and continue if successful.
|
// Initialize volk and continue if successful.
|
||||||
volkInitialize();
|
volkInitialize();
|
||||||
// Initialize vulkan and set up pipeline.
|
// Initialize vulkan and set up pipeline.
|
||||||
@ -98,20 +115,22 @@ void initVulkan() {
|
|||||||
DeviceControl::createLogicalDevice();
|
DeviceControl::createLogicalDevice();
|
||||||
volkLoadDevice(DeviceControl::getDevice());
|
volkLoadDevice(DeviceControl::getDevice());
|
||||||
DeviceControl::createSwapChain(window);
|
DeviceControl::createSwapChain(window);
|
||||||
Buffers::createMemoryAllocator(vulkaninstance);
|
Model::createMemoryAllocator(vulkaninstance);
|
||||||
DeviceControl::createImageViews();
|
DeviceControl::createImageViews();
|
||||||
Buffers::createDescriptorSetLayout();
|
Buffers::createDescriptorSetLayout();
|
||||||
Graphics::createGraphicsPipeline();
|
Graphics::createGraphicsPipeline();
|
||||||
Graphics::createCommandPool();
|
Graphics::createCommandPool();
|
||||||
|
// Image creation MUST be after command pool, because command
|
||||||
|
// buffers.
|
||||||
|
vikingRoom->populateData();
|
||||||
|
stanfordDragon->populateData();
|
||||||
|
teapot->populateData();
|
||||||
|
Texture::createMaterialTextures(Model::getInstances());
|
||||||
Texture::createColorResources();
|
Texture::createColorResources();
|
||||||
Texture::createDepthResources();
|
Texture::createDepthResources();
|
||||||
Texture::createTextureImage();
|
|
||||||
Texture::createTextureImageView();
|
|
||||||
Texture::createTextureSampler();
|
|
||||||
Model::loadModel(glm::vec3(0.0, 0.0, 0.0));
|
|
||||||
Buffers::createUniformBuffers();
|
|
||||||
Buffers::createDescriptorPool();
|
Buffers::createDescriptorPool();
|
||||||
Buffers::createDescriptorSets();
|
Buffers::createDescriptorSet(Model::getInstances());
|
||||||
Graphics::createCommandBuffer();
|
Graphics::createCommandBuffer();
|
||||||
Render::createSyncObject();
|
Render::createSyncObject();
|
||||||
|
|
||||||
@ -131,12 +150,7 @@ void mainLoop() {
|
|||||||
void cleanup() {
|
void cleanup() {
|
||||||
Render::cleanupSwapChain();
|
Render::cleanupSwapChain();
|
||||||
Graphics::destroyGraphicsPipeline();
|
Graphics::destroyGraphicsPipeline();
|
||||||
Buffers::destroyUniformBuffer();
|
|
||||||
Buffers::destroyDescriptorPool();
|
|
||||||
Texture::destroyTextureSampler();
|
|
||||||
Texture::destroyTextureImage();
|
|
||||||
vkDestroyDescriptorSetLayout(DeviceControl::getDevice(),
|
|
||||||
Buffers::getDescriptorSetLayout(), nullptr);
|
|
||||||
Buffers::destroyBuffers();
|
Buffers::destroyBuffers();
|
||||||
Render::destroyFenceSemaphores();
|
Render::destroyFenceSemaphores();
|
||||||
Graphics::destroyCommandPool();
|
Graphics::destroyCommandPool();
|
||||||
@ -163,6 +177,7 @@ void EntryApp::initialize() { initialized = true; }
|
|||||||
bool EntryApp::isInitialized() const { return initialized; }
|
bool EntryApp::isInitialized() const { return initialized; }
|
||||||
GLFWwindow *EntryApp::getWindow() { return window; }
|
GLFWwindow *EntryApp::getWindow() { return window; }
|
||||||
void EntryApp::run() {
|
void EntryApp::run() {
|
||||||
|
|
||||||
initWindow();
|
initWindow();
|
||||||
initVulkan();
|
initVulkan();
|
||||||
mainLoop();
|
mainLoop();
|
||||||
|
@ -1,58 +1,165 @@
|
|||||||
#include "../devicelibrary.h"
|
#include "../devicelibrary.h"
|
||||||
#include "../types.h"
|
|
||||||
#include "buffers.h"
|
|
||||||
#include "texture.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include "buffers.h"
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
|
||||||
#include <glm/ext/matrix_clip_space.hpp>
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
std::vector<VkDescriptorSetLayout> modelSetLayouts;
|
||||||
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
|
||||||
#define VMA_IMPLEMENTATION
|
|
||||||
#include "vk_mem_alloc.h"
|
|
||||||
|
|
||||||
VkBuffer vertexBuffer;
|
VkBuffer vertexBuffer;
|
||||||
VkDeviceMemory vertexBufferMemory;
|
VkDeviceMemory vertexBufferMemory;
|
||||||
VkBuffer indexBuffer;
|
VkBuffer indexBuffer;
|
||||||
VkDeviceMemory indexBufferMemory;
|
VkDeviceMemory indexBufferMemory;
|
||||||
|
|
||||||
std::vector<Agnosia_T::Vertex> vertices;
|
uint32_t indicesSize;
|
||||||
// Index buffer definition, showing which points to reuse.
|
|
||||||
std::vector<uint32_t> indices;
|
|
||||||
|
|
||||||
VmaAllocator _allocator;
|
// Select a binding for each descriptor type
|
||||||
Agnosia_T::GPUPushConstants pushConstants;
|
constexpr int STORAGE_BINDING = 0;
|
||||||
|
constexpr int SAMPLER_BINDING = 1;
|
||||||
|
constexpr int IMAGE_BINDING = 2;
|
||||||
|
// Max count of each descriptor type
|
||||||
|
// You can query the max values for these with
|
||||||
|
// physicalDevice.getProperties().limits.maxDescriptrorSet*******
|
||||||
|
constexpr int STORAGE_COUNT = 65536;
|
||||||
|
constexpr int SAMPLER_COUNT = 65536;
|
||||||
|
constexpr int IMAGE_COUNT = 65536;
|
||||||
|
|
||||||
|
// Create descriptor pool
|
||||||
|
|
||||||
VkDescriptorPool descriptorPool;
|
VkDescriptorPool descriptorPool;
|
||||||
VkDescriptorSetLayout descriptorSetLayout;
|
VkDescriptorSetLayout descriptorSetLayout;
|
||||||
std::vector<VkDescriptorSet> descriptorSets;
|
VkDescriptorSet descriptorSet;
|
||||||
|
|
||||||
VkCommandPool commandPool;
|
VkCommandPool commandPool;
|
||||||
std::vector<VkCommandBuffer> commandBuffers;
|
std::vector<VkCommandBuffer> commandBuffers;
|
||||||
std::vector<VkBuffer> uniformBuffers;
|
|
||||||
std::vector<VkDeviceMemory> uniformBuffersMemory;
|
|
||||||
std::vector<void *> uniformBuffersMapped;
|
|
||||||
|
|
||||||
float objPos[4] = {0.0f, 0.0f, 0.0f, 0.44f};
|
|
||||||
float camPos[4] = {2.0f, 2.0f, 2.0f, 0.44f};
|
|
||||||
float centerPos[4] = {0.0f, 0.0f, 0.0f, 0.44f};
|
|
||||||
float upDir[4] = {0.0f, 0.0f, 1.0f, 0.44f};
|
|
||||||
float depthField = 45.0f;
|
|
||||||
float distanceField[2] = {0.1f, 100.0f};
|
|
||||||
|
|
||||||
const int MAX_FRAMES_IN_FLIGHT = 2;
|
const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||||
struct UniformBufferObject {
|
|
||||||
float time;
|
void Buffers::createDescriptorSetLayout() {
|
||||||
alignas(16) glm::mat4 model;
|
// Create a table of pointers to data, a Descriptor Set!
|
||||||
alignas(16) glm::mat4 view;
|
|
||||||
alignas(16) glm::mat4 proj;
|
VkDescriptorSetLayoutBinding storageLayoutBinding = {
|
||||||
};
|
.binding = STORAGE_BINDING,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.descriptorCount = STORAGE_COUNT,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_ALL,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding samplerLayoutBinding = {
|
||||||
|
.binding = SAMPLER_BINDING,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.descriptorCount = SAMPLER_COUNT,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_ALL,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding imageLayoutBinding = {
|
||||||
|
.binding = IMAGE_BINDING,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
|
.descriptorCount = IMAGE_COUNT,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_ALL,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSetLayoutBinding> bindings = {
|
||||||
|
storageLayoutBinding, imageLayoutBinding, samplerLayoutBinding};
|
||||||
|
|
||||||
|
std::vector<VkDescriptorBindingFlags> bindingFlags = {
|
||||||
|
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT |
|
||||||
|
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
|
||||||
|
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT |
|
||||||
|
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
|
||||||
|
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT |
|
||||||
|
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
|
||||||
|
};
|
||||||
|
VkDescriptorSetLayoutBindingFlagsCreateInfo setLayoutBindingsFlags = {
|
||||||
|
.sType =
|
||||||
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
|
||||||
|
.bindingCount = 3,
|
||||||
|
.pBindingFlags = bindingFlags.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo layoutInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
|
||||||
|
.pNext = &setLayoutBindingsFlags,
|
||||||
|
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
|
||||||
|
.bindingCount = static_cast<uint32_t>(bindings.size()),
|
||||||
|
.pBindings = bindings.data(),
|
||||||
|
|
||||||
|
};
|
||||||
|
if (vkCreateDescriptorSetLayout(DeviceControl::getDevice(), &layoutInfo,
|
||||||
|
nullptr,
|
||||||
|
&descriptorSetLayout) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("Failed to create descriptor set layout!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Buffers::createDescriptorPool() {
|
||||||
|
|
||||||
|
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||||
|
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, STORAGE_COUNT},
|
||||||
|
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, SAMPLER_COUNT},
|
||||||
|
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, IMAGE_COUNT},
|
||||||
|
};
|
||||||
|
VkDescriptorPoolCreateInfo poolInfo{};
|
||||||
|
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
|
||||||
|
poolInfo.pPoolSizes = poolSizes.data();
|
||||||
|
poolInfo.maxSets = 1;
|
||||||
|
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
|
||||||
|
|
||||||
|
if (vkCreateDescriptorPool(DeviceControl::getDevice(), &poolInfo, nullptr,
|
||||||
|
&descriptorPool) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to create descriptor pool!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Buffers::createDescriptorSet(std::vector<Model *> models) {
|
||||||
|
VkDescriptorSetAllocateInfo allocInfo{};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocInfo.descriptorPool = descriptorPool;
|
||||||
|
allocInfo.descriptorSetCount = 1;
|
||||||
|
allocInfo.pSetLayouts = &descriptorSetLayout;
|
||||||
|
|
||||||
|
if (vkAllocateDescriptorSets(DeviceControl::getDevice(), &allocInfo,
|
||||||
|
&descriptorSet) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to allocate descriptor sets!");
|
||||||
|
}
|
||||||
|
std::vector<VkDescriptorImageInfo> imageInfoSet;
|
||||||
|
imageInfoSet.resize(models.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < models.size(); i++) {
|
||||||
|
imageInfoSet[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageInfoSet[i].imageView = models[i]->getMaterial().getTextureView();
|
||||||
|
imageInfoSet[i].sampler = models[i]->getMaterial().getTextureSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkWriteDescriptorSet> descriptorWrites{};
|
||||||
|
descriptorWrites.resize(models.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < models.size(); i++) {
|
||||||
|
descriptorWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
descriptorWrites[i].dstSet = descriptorSet;
|
||||||
|
descriptorWrites[i].dstBinding = SAMPLER_BINDING;
|
||||||
|
descriptorWrites[i].dstArrayElement = i;
|
||||||
|
descriptorWrites[i].descriptorType =
|
||||||
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
descriptorWrites[i].descriptorCount = 1;
|
||||||
|
descriptorWrites[i].pImageInfo = &imageInfoSet[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
vkUpdateDescriptorSets(DeviceControl::getDevice(),
|
||||||
|
static_cast<uint32_t>(descriptorWrites.size()),
|
||||||
|
descriptorWrites.data(), 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t Buffers::findMemoryType(uint32_t typeFilter,
|
uint32_t Buffers::findMemoryType(uint32_t typeFilter,
|
||||||
VkMemoryPropertyFlags properties) {
|
VkMemoryPropertyFlags properties) {
|
||||||
@ -73,40 +180,6 @@ uint32_t Buffers::findMemoryType(uint32_t typeFilter,
|
|||||||
throw std::runtime_error("failed to find suitable memory type!");
|
throw std::runtime_error("failed to find suitable memory type!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void immediate_submit(std::function<void(VkCommandBuffer cmd)> &&function) {
|
|
||||||
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(DeviceControl::getDevice(), &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);
|
|
||||||
|
|
||||||
function(commandBuffer);
|
|
||||||
|
|
||||||
vkEndCommandBuffer(commandBuffer);
|
|
||||||
|
|
||||||
VkSubmitInfo submitInfo{};
|
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &commandBuffer;
|
|
||||||
|
|
||||||
vkQueueSubmit(DeviceControl::getGraphicsQueue(), 1, &submitInfo,
|
|
||||||
VK_NULL_HANDLE);
|
|
||||||
vkQueueWaitIdle(DeviceControl::getGraphicsQueue());
|
|
||||||
|
|
||||||
vkFreeCommandBuffers(DeviceControl::getDevice(), commandPool, 1,
|
|
||||||
&commandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
|
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
|
||||||
VkCommandBufferAllocateInfo allocInfo{};
|
VkCommandBufferAllocateInfo allocInfo{};
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
@ -142,101 +215,6 @@ void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
|
|||||||
vkFreeCommandBuffers(DeviceControl::getDevice(), commandPool, 1,
|
vkFreeCommandBuffers(DeviceControl::getDevice(), commandPool, 1,
|
||||||
&commandBuffer);
|
&commandBuffer);
|
||||||
}
|
}
|
||||||
void Buffers::createMemoryAllocator(VkInstance vkInstance) {
|
|
||||||
VmaVulkanFunctions vulkanFuncs{
|
|
||||||
.vkGetInstanceProcAddr = vkGetInstanceProcAddr,
|
|
||||||
.vkGetDeviceProcAddr = vkGetDeviceProcAddr,
|
|
||||||
};
|
|
||||||
VmaAllocatorCreateInfo allocInfo{
|
|
||||||
.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT,
|
|
||||||
.physicalDevice = DeviceControl::getPhysicalDevice(),
|
|
||||||
.device = DeviceControl::getDevice(),
|
|
||||||
.pVulkanFunctions = &vulkanFuncs,
|
|
||||||
.instance = vkInstance,
|
|
||||||
.vulkanApiVersion = VK_API_VERSION_1_3,
|
|
||||||
|
|
||||||
};
|
|
||||||
vmaCreateAllocator(&allocInfo, &_allocator);
|
|
||||||
}
|
|
||||||
Agnosia_T::AllocatedBuffer Buffers::createBuffer(size_t allocSize,
|
|
||||||
VkBufferUsageFlags usage,
|
|
||||||
VmaMemoryUsage memUsage) {
|
|
||||||
// Allocate the buffer we will use for Device Addresses
|
|
||||||
VkBufferCreateInfo bufferInfo{.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.size = allocSize,
|
|
||||||
.usage = usage};
|
|
||||||
VmaAllocationCreateInfo vmaAllocInfo{
|
|
||||||
.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, .usage = memUsage};
|
|
||||||
|
|
||||||
Agnosia_T::AllocatedBuffer newBuffer;
|
|
||||||
if (vmaCreateBuffer(_allocator, &bufferInfo, &vmaAllocInfo, &newBuffer.buffer,
|
|
||||||
&newBuffer.allocation, &newBuffer.info) != VK_SUCCESS) {
|
|
||||||
throw std::runtime_error("Failed to allocate a buffer using VMA!");
|
|
||||||
}
|
|
||||||
return newBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Agnosia_T::GPUMeshBuffers
|
|
||||||
Buffers::sendMesh(std::span<uint32_t> indices,
|
|
||||||
std::span<Agnosia_T::Vertex> vertices) {
|
|
||||||
|
|
||||||
const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex);
|
|
||||||
const size_t indexBufferSize = indices.size() * sizeof(uint32_t);
|
|
||||||
|
|
||||||
Agnosia_T::GPUMeshBuffers newSurface;
|
|
||||||
|
|
||||||
// Create a Vertex Buffer here, infinitely easier than the old Vulkan method!
|
|
||||||
newSurface.vertexBuffer = createBuffer(
|
|
||||||
vertexBufferSize,
|
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
|
||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
|
||||||
VMA_MEMORY_USAGE_GPU_ONLY);
|
|
||||||
// Find the address of the vertex buffer!
|
|
||||||
VkBufferDeviceAddressInfo deviceAddressInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
|
||||||
.buffer = newSurface.vertexBuffer.buffer,
|
|
||||||
};
|
|
||||||
newSurface.vertexBufferAddress =
|
|
||||||
vkGetBufferDeviceAddress(DeviceControl::getDevice(), &deviceAddressInfo);
|
|
||||||
|
|
||||||
// Create the index buffer to iterate over and check for duplicate vertices
|
|
||||||
newSurface.indexBuffer = createBuffer(indexBufferSize,
|
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
||||||
VMA_MEMORY_USAGE_GPU_ONLY);
|
|
||||||
|
|
||||||
Agnosia_T::AllocatedBuffer stagingBuffer =
|
|
||||||
createBuffer(vertexBufferSize + indexBufferSize,
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
|
|
||||||
|
|
||||||
void *data = stagingBuffer.allocation->GetMappedData();
|
|
||||||
|
|
||||||
// Copy the vertex buffer
|
|
||||||
memcpy(data, vertices.data(), vertexBufferSize);
|
|
||||||
// Copy the index buffer
|
|
||||||
memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize);
|
|
||||||
|
|
||||||
immediate_submit([&](VkCommandBuffer cmd) {
|
|
||||||
VkBufferCopy vertexCopy{0};
|
|
||||||
vertexCopy.dstOffset = 0;
|
|
||||||
vertexCopy.srcOffset = 0;
|
|
||||||
vertexCopy.size = vertexBufferSize;
|
|
||||||
|
|
||||||
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer,
|
|
||||||
1, &vertexCopy);
|
|
||||||
|
|
||||||
VkBufferCopy indexCopy{0};
|
|
||||||
indexCopy.dstOffset = 0;
|
|
||||||
indexCopy.srcOffset = vertexBufferSize;
|
|
||||||
indexCopy.size = indexBufferSize;
|
|
||||||
|
|
||||||
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, 1,
|
|
||||||
&indexCopy);
|
|
||||||
});
|
|
||||||
vmaDestroyBuffer(_allocator, stagingBuffer.buffer, stagingBuffer.allocation);
|
|
||||||
return newSurface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
VkMemoryPropertyFlags properties, VkBuffer &buffer,
|
VkMemoryPropertyFlags properties, VkBuffer &buffer,
|
||||||
@ -269,6 +247,11 @@ void Buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
|||||||
|
|
||||||
vkBindBufferMemory(DeviceControl::getDevice(), buffer, bufferMemory, 0);
|
vkBindBufferMemory(DeviceControl::getDevice(), buffer, bufferMemory, 0);
|
||||||
}
|
}
|
||||||
|
VkDescriptorPool &Buffers::getDescriptorPool() { return descriptorPool; }
|
||||||
|
VkDescriptorSet &Buffers::getDescriptorSet() { return descriptorSet; }
|
||||||
|
VkDescriptorSetLayout &Buffers::getDescriptorSetLayout() {
|
||||||
|
return descriptorSetLayout;
|
||||||
|
}
|
||||||
|
|
||||||
void Buffers::destroyBuffers() {
|
void Buffers::destroyBuffers() {
|
||||||
vkDestroyBuffer(DeviceControl::getDevice(), indexBuffer, nullptr);
|
vkDestroyBuffer(DeviceControl::getDevice(), indexBuffer, nullptr);
|
||||||
@ -278,202 +261,10 @@ void Buffers::destroyBuffers() {
|
|||||||
vkFreeMemory(DeviceControl::getDevice(), vertexBufferMemory, nullptr);
|
vkFreeMemory(DeviceControl::getDevice(), vertexBufferMemory, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------ Uniform Buffer Setup
|
|
||||||
// -------------------------------- //
|
|
||||||
void Buffers::createDescriptorSetLayout() {
|
|
||||||
// Create a table of pointers to data, a Descriptor Set!
|
|
||||||
// --------------------- UBO Layout --------------------- //
|
|
||||||
VkDescriptorSetLayoutBinding uboLayoutBinding{};
|
|
||||||
uboLayoutBinding.binding = 0;
|
|
||||||
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
// Model-View-Projection matrix is in a single uniform buffer, so just 1
|
|
||||||
// descriptor.
|
|
||||||
uboLayoutBinding.descriptorCount = 1;
|
|
||||||
// We are only using this buffer in the vertex shader, so set the flags thus.
|
|
||||||
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
// Immutable Samplers is relevant for image sampling.
|
|
||||||
uboLayoutBinding.pImmutableSamplers = nullptr;
|
|
||||||
|
|
||||||
// --------------- Texture Sampler Layout --------------- //
|
|
||||||
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
|
|
||||||
samplerLayoutBinding.binding = 1;
|
|
||||||
samplerLayoutBinding.descriptorCount = 1;
|
|
||||||
samplerLayoutBinding.descriptorType =
|
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
samplerLayoutBinding.pImmutableSamplers = nullptr;
|
|
||||||
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
|
|
||||||
std::array<VkDescriptorSetLayoutBinding, 2> bindings = {uboLayoutBinding,
|
|
||||||
samplerLayoutBinding};
|
|
||||||
VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
|
||||||
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
||||||
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
|
|
||||||
layoutInfo.pBindings = bindings.data();
|
|
||||||
|
|
||||||
if (vkCreateDescriptorSetLayout(DeviceControl::getDevice(), &layoutInfo,
|
|
||||||
nullptr,
|
|
||||||
&descriptorSetLayout) != VK_SUCCESS) {
|
|
||||||
throw std::runtime_error("Failed to create descriptor set layout!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Buffers::createUniformBuffers() {
|
|
||||||
// Map the uniform buffer to memory as a pointer we can use to write data to
|
|
||||||
// later. This stays mapped to memory for the applications lifetime. This
|
|
||||||
// technique is called "persistent mapping", not having to map the buffer
|
|
||||||
// every time we need to update it increases performance, though not free
|
|
||||||
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
|
|
||||||
|
|
||||||
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
||||||
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
||||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
uniformBuffers[i], uniformBuffersMemory[i]);
|
|
||||||
vkMapMemory(DeviceControl::getDevice(), uniformBuffersMemory[i], 0,
|
|
||||||
bufferSize, 0, &uniformBuffersMapped[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Buffers::updateUniformBuffer(uint32_t currentImage) {
|
|
||||||
// Update the uniform buffer every frame to change the position, but notably,
|
|
||||||
// use chrono to know exactly how much to move so we aren't locked to the
|
|
||||||
// framerate as the world time.
|
|
||||||
|
|
||||||
static auto startTime = std::chrono::high_resolution_clock::now();
|
|
||||||
// Calculate the time in seconds since rendering has began to floating point
|
|
||||||
// precision.
|
|
||||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
|
||||||
float time = std::chrono::duration<float, std::chrono::seconds::period>(
|
|
||||||
currentTime - startTime)
|
|
||||||
.count();
|
|
||||||
|
|
||||||
UniformBufferObject ubo{};
|
|
||||||
ubo.time = time;
|
|
||||||
// Modify the model projection transformation to rotate around the Z over
|
|
||||||
// time.
|
|
||||||
ubo.model = glm::translate(glm::mat4(1.0f),
|
|
||||||
glm::vec3(objPos[0], objPos[1], objPos[2]));
|
|
||||||
// ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(30.0f),
|
|
||||||
// glm::vec3(0.0f, 0.0f, 1.0f));
|
|
||||||
// Modify the view transformation to look at the object from above at a 45
|
|
||||||
// degree angle. This takes the eye position, center position, and the up
|
|
||||||
// direction.
|
|
||||||
ubo.view = glm::lookAt(glm::vec3(camPos[0], camPos[1], camPos[2]),
|
|
||||||
glm::vec3(centerPos[0], centerPos[1], centerPos[2]),
|
|
||||||
glm::vec3(upDir[0], upDir[1], upDir[2]));
|
|
||||||
// 45 degree field of view, set aspect ratio, and near and far clipping range.
|
|
||||||
ubo.proj =
|
|
||||||
glm::perspective(glm::radians(depthField),
|
|
||||||
DeviceControl::getSwapChainExtent().width /
|
|
||||||
(float)DeviceControl::getSwapChainExtent().height,
|
|
||||||
distanceField[0], distanceField[1]);
|
|
||||||
|
|
||||||
// GLM was created for OpenGL, where the Y coordinate was inverted. This
|
|
||||||
// simply flips the sign.
|
|
||||||
ubo.proj[1][1] *= -1;
|
|
||||||
|
|
||||||
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
|
|
||||||
}
|
|
||||||
void Buffers::destroyUniformBuffer() {
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
||||||
vkDestroyBuffer(DeviceControl::getDevice(), uniformBuffers[i], nullptr);
|
|
||||||
vkFreeMemory(DeviceControl::getDevice(), uniformBuffersMemory[i], nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Buffers::createDescriptorPool() {
|
|
||||||
// Create a pool to be used to allocate descriptor sets.
|
|
||||||
std::array<VkDescriptorPoolSize, 2> poolSizes{};
|
|
||||||
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
poolSizes[0].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
poolSizes[1].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
|
|
||||||
VkDescriptorPoolCreateInfo poolInfo{};
|
|
||||||
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
||||||
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
|
|
||||||
poolInfo.pPoolSizes = poolSizes.data();
|
|
||||||
poolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
|
|
||||||
if (vkCreateDescriptorPool(DeviceControl::getDevice(), &poolInfo, nullptr,
|
|
||||||
&descriptorPool) != VK_SUCCESS) {
|
|
||||||
throw std::runtime_error("failed to create descriptor pool!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Buffers::createDescriptorSets() {
|
|
||||||
std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT,
|
|
||||||
descriptorSetLayout);
|
|
||||||
VkDescriptorSetAllocateInfo allocInfo{};
|
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
||||||
allocInfo.descriptorPool = descriptorPool;
|
|
||||||
allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
allocInfo.pSetLayouts = layouts.data();
|
|
||||||
|
|
||||||
descriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
if (vkAllocateDescriptorSets(DeviceControl::getDevice(), &allocInfo,
|
|
||||||
descriptorSets.data()) != VK_SUCCESS) {
|
|
||||||
throw std::runtime_error("failed to allocate descriptor sets!");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
||||||
VkDescriptorBufferInfo bufferInfo{};
|
|
||||||
bufferInfo.buffer = uniformBuffers[i];
|
|
||||||
bufferInfo.offset = 0;
|
|
||||||
bufferInfo.range = sizeof(UniformBufferObject);
|
|
||||||
|
|
||||||
VkDescriptorImageInfo imageInfo{};
|
|
||||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
imageInfo.imageView = Texture::getTextureImageView();
|
|
||||||
imageInfo.sampler = Texture::getTextureSampler();
|
|
||||||
|
|
||||||
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
|
|
||||||
|
|
||||||
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
||||||
descriptorWrites[0].dstSet = descriptorSets[i];
|
|
||||||
descriptorWrites[0].dstBinding = 0;
|
|
||||||
descriptorWrites[0].dstArrayElement = 0;
|
|
||||||
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
descriptorWrites[0].descriptorCount = 1;
|
|
||||||
descriptorWrites[0].pBufferInfo = &bufferInfo;
|
|
||||||
|
|
||||||
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
||||||
descriptorWrites[1].dstSet = descriptorSets[i];
|
|
||||||
descriptorWrites[1].dstBinding = 1;
|
|
||||||
descriptorWrites[1].dstArrayElement = 0;
|
|
||||||
descriptorWrites[1].descriptorType =
|
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
descriptorWrites[1].descriptorCount = 1;
|
|
||||||
descriptorWrites[1].pImageInfo = &imageInfo;
|
|
||||||
|
|
||||||
vkUpdateDescriptorSets(DeviceControl::getDevice(),
|
|
||||||
static_cast<uint32_t>(descriptorWrites.size()),
|
|
||||||
descriptorWrites.data(), 0, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Buffers::destroyDescriptorPool() {
|
|
||||||
vkDestroyDescriptorPool(DeviceControl::getDevice(), descriptorPool, nullptr);
|
|
||||||
}
|
|
||||||
VkDescriptorPool &Buffers::getDescriptorPool() { return descriptorPool; }
|
|
||||||
std::vector<VkDescriptorSet> &Buffers::getDescriptorSets() {
|
|
||||||
return descriptorSets;
|
|
||||||
}
|
|
||||||
float *Buffers::getObjPos() { return objPos; }
|
|
||||||
float *Buffers::getCamPos() { return camPos; }
|
|
||||||
float *Buffers::getCenterPos() { return centerPos; }
|
|
||||||
float *Buffers::getUpDir() { return upDir; }
|
|
||||||
float &Buffers::getDepthField() { return depthField; }
|
|
||||||
float *Buffers::getDistanceField() { return distanceField; }
|
|
||||||
uint32_t Buffers::getMaxFramesInFlight() { return MAX_FRAMES_IN_FLIGHT; }
|
uint32_t Buffers::getMaxFramesInFlight() { return MAX_FRAMES_IN_FLIGHT; }
|
||||||
std::vector<VkCommandBuffer> &Buffers::getCommandBuffers() {
|
std::vector<VkCommandBuffer> &Buffers::getCommandBuffers() {
|
||||||
return commandBuffers;
|
return commandBuffers;
|
||||||
}
|
}
|
||||||
std::vector<VkBuffer> &Buffers::getUniformBuffers() { return uniformBuffers; }
|
|
||||||
std::vector<VkDeviceMemory> &Buffers::getUniformBuffersMemory() {
|
|
||||||
return uniformBuffersMemory;
|
|
||||||
}
|
|
||||||
VkCommandPool &Buffers::getCommandPool() { return commandPool; }
|
VkCommandPool &Buffers::getCommandPool() { return commandPool; }
|
||||||
VkDescriptorSetLayout &Buffers::getDescriptorSetLayout() {
|
uint32_t Buffers::getIndicesSize() { return indicesSize; }
|
||||||
return descriptorSetLayout;
|
|
||||||
}
|
|
||||||
std::vector<Agnosia_T::Vertex> &Buffers::getVertices() { return vertices; }
|
|
||||||
std::vector<uint32_t> &Buffers::getIndices() { return indices; }
|
|
||||||
|
@ -1,51 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <span>
|
|
||||||
#define VK_NO_PROTOTYPES
|
#define VK_NO_PROTOTYPES
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
|
#include "model.h"
|
||||||
#include "volk.h"
|
#include "volk.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
class Buffers {
|
class Buffers {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Agnosia_T::AllocatedBuffer createBuffer(size_t allocSize,
|
static Agnosia_T::AllocatedBuffer createBuffer(size_t allocSize,
|
||||||
VkBufferUsageFlags usage,
|
VkBufferUsageFlags usage,
|
||||||
VmaMemoryUsage memUsage);
|
VmaMemoryUsage memUsage);
|
||||||
static void createMemoryAllocator(VkInstance vkInstance);
|
static void createMemoryAllocator(VkInstance vkInstance);
|
||||||
static Agnosia_T::GPUMeshBuffers
|
static void createDescriptorSetLayout();
|
||||||
sendMesh(std::span<uint32_t> indices, std::span<Agnosia_T::Vertex> vertices);
|
static void createDescriptorSet(std::vector<Model *> models);
|
||||||
|
static void createDescriptorPool();
|
||||||
static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
VkMemoryPropertyFlags props, VkBuffer &buffer,
|
VkMemoryPropertyFlags props, VkBuffer &buffer,
|
||||||
VkDeviceMemory &bufferMemory);
|
VkDeviceMemory &bufferMemory);
|
||||||
static uint32_t findMemoryType(uint32_t typeFilter,
|
static uint32_t findMemoryType(uint32_t typeFilter,
|
||||||
VkMemoryPropertyFlags flags);
|
VkMemoryPropertyFlags flags);
|
||||||
static void destroyBuffers();
|
static void destroyBuffers();
|
||||||
static void createDescriptorSetLayout();
|
|
||||||
static void createUniformBuffers();
|
|
||||||
static void updateUniformBuffer(uint32_t currentImage);
|
|
||||||
static void destroyUniformBuffer();
|
|
||||||
static void createDescriptorPool();
|
|
||||||
static void createDescriptorSets();
|
|
||||||
static void destroyDescriptorPool();
|
|
||||||
static VkDescriptorPool &getDescriptorPool();
|
static VkDescriptorPool &getDescriptorPool();
|
||||||
static VkDescriptorSetLayout &getDescriptorSetLayout();
|
static VkDescriptorSet &getDescriptorSet();
|
||||||
static std::vector<VkDescriptorSet> &getDescriptorSets();
|
|
||||||
|
|
||||||
static float *getObjPos();
|
static VkDescriptorSetLayout &getDescriptorSetLayout();
|
||||||
static float *getCamPos();
|
|
||||||
static float *getCenterPos();
|
|
||||||
static float *getUpDir();
|
|
||||||
static float &getDepthField();
|
|
||||||
static float *getDistanceField();
|
|
||||||
static uint32_t getMaxFramesInFlight();
|
static uint32_t getMaxFramesInFlight();
|
||||||
static std::vector<VkCommandBuffer> &getCommandBuffers();
|
static std::vector<VkCommandBuffer> &getCommandBuffers();
|
||||||
static std::vector<VkBuffer> &getUniformBuffers();
|
|
||||||
static std::vector<VkDeviceMemory> &getUniformBuffersMemory();
|
|
||||||
static VkCommandPool &getCommandPool();
|
static VkCommandPool &getCommandPool();
|
||||||
static std::vector<Agnosia_T::Vertex> &getVertices();
|
static uint32_t getIndicesSize();
|
||||||
static std::vector<uint32_t> &getIndices();
|
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,18 @@
|
|||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
float camPos[4] = {3.0f, 3.0f, 3.0f, 0.44f};
|
||||||
|
float centerPos[4] = {0.0f, 0.0f, 0.0f, 0.44f};
|
||||||
|
float upDir[4] = {0.0f, 0.0f, 1.0f, 0.44f};
|
||||||
|
float depthField = 45.0f;
|
||||||
|
float distanceField[2] = {0.1f, 100.0f};
|
||||||
|
|
||||||
std::vector<VkDynamicState> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT,
|
std::vector<VkDynamicState> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
VK_DYNAMIC_STATE_SCISSOR};
|
VK_DYNAMIC_STATE_SCISSOR};
|
||||||
@ -84,15 +95,6 @@ void Graphics::createGraphicsPipeline() {
|
|||||||
vertexInputInfo.sType =
|
vertexInputInfo.sType =
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
|
||||||
auto bindingDescription = Agnosia_T::Vertex::getBindingDescription();
|
|
||||||
auto attributeDescriptions = Agnosia_T::Vertex::getAttributeDescriptions();
|
|
||||||
|
|
||||||
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
|
||||||
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
|
|
||||||
vertexInputInfo.vertexAttributeDescriptionCount =
|
|
||||||
static_cast<uint32_t>(attributeDescriptions.size());
|
|
||||||
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
|
|
||||||
|
|
||||||
// ------------------- STAGE 5 - RASTERIZATION ----------------- //
|
// ------------------- STAGE 5 - RASTERIZATION ----------------- //
|
||||||
// Take Vertex shader vertices and fragmentize them for the frament shader.
|
// Take Vertex shader vertices and fragmentize them for the frament shader.
|
||||||
// The rasterizer also can perform depth testing, face culling, and scissor
|
// The rasterizer also can perform depth testing, face culling, and scissor
|
||||||
@ -176,7 +178,7 @@ void Graphics::createGraphicsPipeline() {
|
|||||||
dynamicState.pDynamicStates = dynamicStates.data();
|
dynamicState.pDynamicStates = dynamicStates.data();
|
||||||
|
|
||||||
VkPushConstantRange pushConstant{
|
VkPushConstantRange pushConstant{
|
||||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
.stageFlags = VK_SHADER_STAGE_ALL,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = sizeof(Agnosia_T::GPUPushConstants),
|
.size = sizeof(Agnosia_T::GPUPushConstants),
|
||||||
};
|
};
|
||||||
@ -351,26 +353,45 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
|
|||||||
scissor.offset = {0, 0};
|
scissor.offset = {0, 0};
|
||||||
scissor.extent = DeviceControl::getSwapChainExtent();
|
scissor.extent = DeviceControl::getSwapChainExtent();
|
||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
int texID = 0;
|
||||||
|
for (Model *model : Model::getInstances()) {
|
||||||
|
|
||||||
Agnosia_T::GPUMeshBuffers Model =
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
Buffers::sendMesh(Buffers::getIndices(), Buffers::getVertices());
|
pipelineLayout, 0, 1, &Buffers::getDescriptorSet(),
|
||||||
|
0, nullptr);
|
||||||
|
|
||||||
Agnosia_T::GPUPushConstants pushConsts;
|
Agnosia_T::GPUPushConstants pushConsts;
|
||||||
pushConsts.vertexBuffer = Model.vertexBufferAddress;
|
pushConsts.vertexBuffer = model->getBuffers().vertexBufferAddress;
|
||||||
|
pushConsts.objPosition = model->getPos();
|
||||||
|
pushConsts.textureID = texID;
|
||||||
|
|
||||||
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT,
|
pushConsts.model =
|
||||||
0, sizeof(Agnosia_T::GPUPushConstants), &pushConsts);
|
glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
|
||||||
vkCmdBindIndexBuffer(commandBuffer, Model.indexBuffer.buffer, 0,
|
|
||||||
VK_INDEX_TYPE_UINT32);
|
|
||||||
|
|
||||||
vkCmdBindDescriptorSets(
|
pushConsts.view =
|
||||||
commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
|
glm::lookAt(glm::vec3(camPos[0], camPos[1], camPos[2]),
|
||||||
&Buffers::getDescriptorSets()[Render::getCurrentFrame()], 0, nullptr);
|
glm::vec3(centerPos[0], centerPos[1], centerPos[2]),
|
||||||
|
glm::vec3(upDir[0], upDir[1], upDir[2]));
|
||||||
|
|
||||||
vkCmdDrawIndexed(commandBuffer,
|
pushConsts.proj =
|
||||||
static_cast<uint32_t>(Buffers::getIndices().size()), 1, 0, 0,
|
glm::perspective(glm::radians(depthField),
|
||||||
0);
|
DeviceControl::getSwapChainExtent().width /
|
||||||
|
(float)DeviceControl::getSwapChainExtent().height,
|
||||||
|
distanceField[0], distanceField[1]);
|
||||||
|
// GLM was created for OpenGL, where the Y coordinate was inverted. This
|
||||||
|
// simply flips the sign.
|
||||||
|
pushConsts.proj[1][1] *= -1;
|
||||||
|
|
||||||
|
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_ALL, 0,
|
||||||
|
sizeof(Agnosia_T::GPUPushConstants), &pushConsts);
|
||||||
|
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, model->getBuffers().indexBuffer.buffer,
|
||||||
|
0, VK_INDEX_TYPE_UINT32);
|
||||||
|
|
||||||
|
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(model->getIndices()),
|
||||||
|
1, 0, 0, 0);
|
||||||
|
texID++;
|
||||||
|
}
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer);
|
||||||
|
|
||||||
vkCmdEndRendering(commandBuffer);
|
vkCmdEndRendering(commandBuffer);
|
||||||
@ -403,10 +424,16 @@ void Graphics::recordCommandBuffer(VkCommandBuffer commandBuffer,
|
|||||||
.pImageMemoryBarriers = &prePresentImageBarrier,
|
.pImageMemoryBarriers = &prePresentImageBarrier,
|
||||||
};
|
};
|
||||||
|
|
||||||
vkCmdPipelineBarrier2(
|
vkCmdPipelineBarrier2(Buffers::getCommandBuffers()[Render::getCurrentFrame()],
|
||||||
Buffers ::getCommandBuffers()[Render::getCurrentFrame()], &depInfo);
|
&depInfo);
|
||||||
|
|
||||||
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {
|
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {
|
||||||
throw std::runtime_error("failed to record command buffer!");
|
throw std::runtime_error("failed to record command buffer!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float *Graphics::getCamPos() { return camPos; }
|
||||||
|
float *Graphics::getCenterPos() { return centerPos; }
|
||||||
|
float *Graphics::getUpDir() { return upDir; }
|
||||||
|
float &Graphics::getDepthField() { return depthField; }
|
||||||
|
float *Graphics::getDistanceField() { return distanceField; }
|
||||||
|
@ -13,4 +13,10 @@ public:
|
|||||||
static void createCommandBuffer();
|
static void createCommandBuffer();
|
||||||
static void recordCommandBuffer(VkCommandBuffer cmndBuffer,
|
static void recordCommandBuffer(VkCommandBuffer cmndBuffer,
|
||||||
uint32_t imageIndex);
|
uint32_t imageIndex);
|
||||||
|
|
||||||
|
static float *getCamPos();
|
||||||
|
static float *getCenterPos();
|
||||||
|
static float *getUpDir();
|
||||||
|
static float &getDepthField();
|
||||||
|
static float *getDistanceField();
|
||||||
};
|
};
|
||||||
|
19
src/graphics/material.cpp
Normal file
19
src/graphics/material.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "material.h"
|
||||||
|
|
||||||
|
Material::Material(const std::string &matID, const std::string &texPath)
|
||||||
|
: ID(matID), texturePath(texPath) {}
|
||||||
|
|
||||||
|
std::string Material::getID() const { return ID; }
|
||||||
|
std::string Material::getTexturePath() const { return texturePath; }
|
||||||
|
|
||||||
|
VkImage &Material::getTextureImage() { return this->textureImage; }
|
||||||
|
VkImageView &Material::getTextureView() { return this->textureImageView; }
|
||||||
|
VkSampler &Material::getTextureSampler() { return this->textureSampler; }
|
||||||
|
|
||||||
|
void Material::setTextureImage(VkImage image) { this->textureImage = image; }
|
||||||
|
void Material::setTextureView(VkImageView imageView) {
|
||||||
|
this->textureImageView = imageView;
|
||||||
|
}
|
||||||
|
void Material::setTextureSampler(VkSampler sampler) {
|
||||||
|
this->textureSampler = sampler;
|
||||||
|
}
|
26
src/graphics/material.h
Normal file
26
src/graphics/material.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
#define VK_NO_PROTOTYPES
|
||||||
|
#include "volk.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Material {
|
||||||
|
protected:
|
||||||
|
std::string ID;
|
||||||
|
std::string texturePath;
|
||||||
|
|
||||||
|
VkImage textureImage;
|
||||||
|
VkImageView textureImageView;
|
||||||
|
VkSampler textureSampler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Material(const std::string &matID, const std::string &texPath);
|
||||||
|
std::string getID() const;
|
||||||
|
std::string getTexturePath() const;
|
||||||
|
VkImage &getTextureImage();
|
||||||
|
VkImageView &getTextureView();
|
||||||
|
VkSampler &getTextureSampler();
|
||||||
|
|
||||||
|
void setTextureImage(VkImage image);
|
||||||
|
void setTextureView(VkImageView imageView);
|
||||||
|
void setTextureSampler(VkSampler sampler);
|
||||||
|
};
|
@ -1,13 +1,25 @@
|
|||||||
#include "buffers.h"
|
#include "buffers.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include <stdexcept>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#define TINY_OBJ_IMPLEMENTATION
|
#define TINY_OBJ_IMPLEMENTATION
|
||||||
|
#include <stdexcept>
|
||||||
#include <tiny_obj_loader.h>
|
#include <tiny_obj_loader.h>
|
||||||
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
#include "../devicelibrary.h"
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtx/hash.hpp>
|
#include <glm/gtx/hash.hpp>
|
||||||
|
|
||||||
|
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||||
|
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
||||||
|
#define VMA_IMPLEMENTATION
|
||||||
|
#include "vk_mem_alloc.h"
|
||||||
|
|
||||||
|
std::vector<Model *> Model::instances;
|
||||||
|
VmaAllocator _allocator;
|
||||||
namespace std {
|
namespace std {
|
||||||
template <> struct hash<Agnosia_T::Vertex> {
|
template <> struct hash<Agnosia_T::Vertex> {
|
||||||
size_t operator()(Agnosia_T::Vertex const &vertex) const {
|
size_t operator()(Agnosia_T::Vertex const &vertex) const {
|
||||||
@ -18,15 +30,90 @@ template <> struct hash<Agnosia_T::Vertex> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
void Model::createMemoryAllocator(VkInstance vkInstance) {
|
||||||
|
VmaVulkanFunctions vulkanFuncs{
|
||||||
|
.vkGetInstanceProcAddr = vkGetInstanceProcAddr,
|
||||||
|
.vkGetDeviceProcAddr = vkGetDeviceProcAddr,
|
||||||
|
};
|
||||||
|
VmaAllocatorCreateInfo allocInfo{
|
||||||
|
.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT,
|
||||||
|
.physicalDevice = DeviceControl::getPhysicalDevice(),
|
||||||
|
.device = DeviceControl::getDevice(),
|
||||||
|
.pVulkanFunctions = &vulkanFuncs,
|
||||||
|
.instance = vkInstance,
|
||||||
|
.vulkanApiVersion = VK_API_VERSION_1_3,
|
||||||
|
|
||||||
const std::string MODEL_PATH = "assets/models/viking_room.obj";
|
};
|
||||||
|
vmaCreateAllocator(&allocInfo, &_allocator);
|
||||||
|
}
|
||||||
|
Agnosia_T::AllocatedBuffer createBuffer(size_t allocSize,
|
||||||
|
VkBufferUsageFlags usage,
|
||||||
|
VmaMemoryUsage memUsage) {
|
||||||
|
// Allocate the buffer we will use for Device Addresses
|
||||||
|
VkBufferCreateInfo bufferInfo{.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.size = allocSize,
|
||||||
|
.usage = usage};
|
||||||
|
VmaAllocationCreateInfo vmaAllocInfo{
|
||||||
|
.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, .usage = memUsage};
|
||||||
|
|
||||||
void Model::loadModel(glm::vec3 position) {
|
Agnosia_T::AllocatedBuffer newBuffer;
|
||||||
|
if (vmaCreateBuffer(_allocator, &bufferInfo, &vmaAllocInfo, &newBuffer.buffer,
|
||||||
|
&newBuffer.allocation, &newBuffer.info) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("Failed to allocate a buffer using VMA!");
|
||||||
|
}
|
||||||
|
return newBuffer;
|
||||||
|
}
|
||||||
|
void immediate_submit(std::function<void(VkCommandBuffer cmd)> &&function) {
|
||||||
|
VkCommandBufferAllocateInfo allocInfo{};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
allocInfo.commandPool = Buffers::getCommandPool();
|
||||||
|
allocInfo.commandBufferCount = 1;
|
||||||
|
|
||||||
|
VkCommandBuffer commandBuffer;
|
||||||
|
vkAllocateCommandBuffers(DeviceControl::getDevice(), &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);
|
||||||
|
|
||||||
|
function(commandBuffer);
|
||||||
|
|
||||||
|
vkEndCommandBuffer(commandBuffer);
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo{};
|
||||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &commandBuffer;
|
||||||
|
|
||||||
|
vkQueueSubmit(DeviceControl::getGraphicsQueue(), 1, &submitInfo,
|
||||||
|
VK_NULL_HANDLE);
|
||||||
|
vkQueueWaitIdle(DeviceControl::getGraphicsQueue());
|
||||||
|
|
||||||
|
vkFreeCommandBuffers(DeviceControl::getDevice(), Buffers::getCommandPool(), 1,
|
||||||
|
&commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Model::Model(const std::string &modelID, const Material &material,
|
||||||
|
const std::string &modelPath, const glm::vec3 &objPos)
|
||||||
|
: ID(modelID), material(material), objPosition(objPos),
|
||||||
|
modelPath(modelPath) {
|
||||||
|
instances.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::populateData() {
|
||||||
|
|
||||||
|
std::vector<Agnosia_T::Vertex> vertices;
|
||||||
|
// Index buffer definition, showing which points to reuse.
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
tinyobj::ObjReaderConfig readerConfig;
|
tinyobj::ObjReaderConfig readerConfig;
|
||||||
|
|
||||||
tinyobj::ObjReader reader;
|
tinyobj::ObjReader reader;
|
||||||
|
|
||||||
if (!reader.ParseFromFile(MODEL_PATH, readerConfig)) {
|
if (!reader.ParseFromFile(modelPath, readerConfig)) {
|
||||||
if (!reader.Error().empty()) {
|
if (!reader.Error().empty()) {
|
||||||
throw std::runtime_error(reader.Error());
|
throw std::runtime_error(reader.Error());
|
||||||
}
|
}
|
||||||
@ -38,15 +125,16 @@ void Model::loadModel(glm::vec3 position) {
|
|||||||
auto &attrib = reader.GetAttrib();
|
auto &attrib = reader.GetAttrib();
|
||||||
auto &shapes = reader.GetShapes();
|
auto &shapes = reader.GetShapes();
|
||||||
auto &materials = reader.GetMaterials();
|
auto &materials = reader.GetMaterials();
|
||||||
|
|
||||||
std::unordered_map<Agnosia_T::Vertex, uint32_t> uniqueVertices{};
|
std::unordered_map<Agnosia_T::Vertex, uint32_t> uniqueVertices{};
|
||||||
|
|
||||||
for (const auto &shape : shapes) {
|
for (const auto &shape : shapes) {
|
||||||
for (const auto &index : shape.mesh.indices) {
|
for (const auto &index : shape.mesh.indices) {
|
||||||
Agnosia_T::Vertex vertex{};
|
Agnosia_T::Vertex vertex{};
|
||||||
|
|
||||||
vertex.pos = {attrib.vertices[3 * index.vertex_index + 0] + position.x,
|
vertex.pos = {attrib.vertices[3 * index.vertex_index + 0],
|
||||||
attrib.vertices[3 * index.vertex_index + 1] + position.y,
|
attrib.vertices[3 * index.vertex_index + 1],
|
||||||
attrib.vertices[3 * index.vertex_index + 2] + position.z};
|
attrib.vertices[3 * index.vertex_index + 2]};
|
||||||
|
|
||||||
// TODO: Small fix here, handle if there are no UV's unwrapped for the
|
// TODO: Small fix here, handle if there are no UV's unwrapped for the
|
||||||
// model.
|
// model.
|
||||||
@ -58,11 +146,76 @@ void Model::loadModel(glm::vec3 position) {
|
|||||||
vertex.color = {1.0f, 1.0f, 1.0f};
|
vertex.color = {1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
if (uniqueVertices.count(vertex) == 0) {
|
if (uniqueVertices.count(vertex) == 0) {
|
||||||
uniqueVertices[vertex] =
|
uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
|
||||||
static_cast<uint32_t>(Buffers::getVertices().size());
|
vertices.push_back(vertex);
|
||||||
Buffers::getVertices().push_back(vertex);
|
|
||||||
}
|
}
|
||||||
Buffers::getIndices().push_back(uniqueVertices[vertex]);
|
indices.push_back(uniqueVertices[vertex]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex);
|
||||||
|
const size_t indexBufferSize = indices.size() * sizeof(uint32_t);
|
||||||
|
|
||||||
|
Agnosia_T::GPUMeshBuffers newSurface;
|
||||||
|
|
||||||
|
// Create a Vertex Buffer here, infinitely easier than the old Vulkan method!
|
||||||
|
newSurface.vertexBuffer = createBuffer(
|
||||||
|
vertexBufferSize,
|
||||||
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||||
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||||
|
VMA_MEMORY_USAGE_GPU_ONLY);
|
||||||
|
// Find the address of the vertex buffer!
|
||||||
|
VkBufferDeviceAddressInfo deviceAddressInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
||||||
|
.buffer = newSurface.vertexBuffer.buffer,
|
||||||
|
};
|
||||||
|
newSurface.vertexBufferAddress =
|
||||||
|
vkGetBufferDeviceAddress(DeviceControl::getDevice(), &deviceAddressInfo);
|
||||||
|
|
||||||
|
// Create the index buffer to iterate over and check for duplicate vertices
|
||||||
|
newSurface.indexBuffer = createBuffer(indexBufferSize,
|
||||||
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VMA_MEMORY_USAGE_GPU_ONLY);
|
||||||
|
|
||||||
|
Agnosia_T::AllocatedBuffer stagingBuffer =
|
||||||
|
createBuffer(vertexBufferSize + indexBufferSize,
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
|
||||||
|
|
||||||
|
void *data = stagingBuffer.allocation->GetMappedData();
|
||||||
|
|
||||||
|
// Copy the vertex buffer
|
||||||
|
memcpy(data, vertices.data(), vertexBufferSize);
|
||||||
|
// Copy the index buffer
|
||||||
|
memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize);
|
||||||
|
|
||||||
|
immediate_submit([&](VkCommandBuffer cmd) {
|
||||||
|
VkBufferCopy vertexCopy{0};
|
||||||
|
vertexCopy.dstOffset = 0;
|
||||||
|
vertexCopy.srcOffset = 0;
|
||||||
|
vertexCopy.size = vertexBufferSize;
|
||||||
|
|
||||||
|
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer,
|
||||||
|
1, &vertexCopy);
|
||||||
|
|
||||||
|
VkBufferCopy indexCopy{0};
|
||||||
|
indexCopy.dstOffset = 0;
|
||||||
|
indexCopy.srcOffset = vertexBufferSize;
|
||||||
|
indexCopy.size = indexBufferSize;
|
||||||
|
|
||||||
|
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, 1,
|
||||||
|
&indexCopy);
|
||||||
|
});
|
||||||
|
vmaDestroyBuffer(_allocator, stagingBuffer.buffer, stagingBuffer.allocation);
|
||||||
|
|
||||||
|
this->buffers = newSurface;
|
||||||
|
this->objPosition = objPosition;
|
||||||
|
this->indiceCount = indices.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Model::getID() { return this->ID; }
|
||||||
|
glm::vec3 &Model::getPos() { return this->objPosition; }
|
||||||
|
Material &Model::getMaterial() { return this->material; }
|
||||||
|
Agnosia_T::GPUMeshBuffers Model::getBuffers() { return this->buffers; }
|
||||||
|
uint32_t Model::getIndices() { return this->indiceCount; }
|
||||||
|
const std::vector<Model *> &Model::getInstances() { return instances; }
|
||||||
|
@ -1,8 +1,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define VK_NO_PROTOTYPES
|
||||||
|
|
||||||
|
#include "../types.h"
|
||||||
|
|
||||||
|
#include "material.h"
|
||||||
|
#include "volk.h"
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <string>
|
||||||
class Model {
|
class Model {
|
||||||
|
protected:
|
||||||
|
std::string ID;
|
||||||
|
Agnosia_T::GPUMeshBuffers buffers;
|
||||||
|
Material material;
|
||||||
|
glm::vec3 objPosition;
|
||||||
|
uint32_t indiceCount;
|
||||||
|
std::string modelPath;
|
||||||
|
static std::vector<Model *> instances;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void loadModel(glm::vec3 position);
|
Model(const std::string &modelID, const Material &material,
|
||||||
|
const std::string &modelPath, const glm::vec3 &opjPos);
|
||||||
|
|
||||||
|
static void createMemoryAllocator(VkInstance instance);
|
||||||
|
static const std::vector<Model *> &getInstances();
|
||||||
|
|
||||||
|
void populateData();
|
||||||
|
|
||||||
|
Agnosia_T::GPUMeshBuffers getBuffers();
|
||||||
|
std::string getID();
|
||||||
|
glm::vec3 &getPos();
|
||||||
|
Material &getMaterial();
|
||||||
|
std::string getModelPath();
|
||||||
|
uint32_t getIndices();
|
||||||
};
|
};
|
||||||
|
@ -59,16 +59,12 @@ void Render::drawFrame() {
|
|||||||
throw std::runtime_error("failed to acquire swap chain image!");
|
throw std::runtime_error("failed to acquire swap chain image!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffers::updateUniformBuffer(currentFrame);
|
|
||||||
|
|
||||||
vkResetFences(DeviceControl::getDevice(), 1, &inFlightFences[currentFrame]);
|
vkResetFences(DeviceControl::getDevice(), 1, &inFlightFences[currentFrame]);
|
||||||
|
|
||||||
vkResetCommandBuffer(Buffers::getCommandBuffers()[currentFrame],
|
vkResetCommandBuffer(Buffers::getCommandBuffers()[currentFrame],
|
||||||
/*VkCommandBufferResetFlagBits*/ 0);
|
/*VkCommandBufferResetFlagBits*/ 0);
|
||||||
Graphics::recordCommandBuffer(Buffers::getCommandBuffers()[currentFrame],
|
Graphics::recordCommandBuffer(Buffers::getCommandBuffers()[currentFrame],
|
||||||
imageIndex);
|
imageIndex);
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(),
|
|
||||||
Buffers::getCommandBuffers()[currentFrame]);
|
|
||||||
VkSubmitInfo submitInfo{};
|
VkSubmitInfo submitInfo{};
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "../devicelibrary.h"
|
#include "../devicelibrary.h"
|
||||||
#include "buffers.h"
|
#include "buffers.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
@ -8,14 +9,10 @@
|
|||||||
|
|
||||||
uint32_t mipLevels;
|
uint32_t mipLevels;
|
||||||
|
|
||||||
VkImage textureImage;
|
|
||||||
VkDeviceMemory textureImageMemory;
|
VkDeviceMemory textureImageMemory;
|
||||||
VkPipelineStageFlags sourceStage;
|
VkPipelineStageFlags sourceStage;
|
||||||
VkPipelineStageFlags destinationStage;
|
VkPipelineStageFlags destinationStage;
|
||||||
|
|
||||||
VkImageView textureImageView;
|
|
||||||
VkSampler textureSampler;
|
|
||||||
|
|
||||||
VkImage colorImage;
|
VkImage colorImage;
|
||||||
VkImageView colorImageView;
|
VkImageView colorImageView;
|
||||||
VkDeviceMemory colorImageMemory;
|
VkDeviceMemory colorImageMemory;
|
||||||
@ -24,8 +21,6 @@ VkImage depthImage;
|
|||||||
VkImageView depthImageView;
|
VkImageView depthImageView;
|
||||||
VkDeviceMemory depthImageMemory;
|
VkDeviceMemory depthImageMemory;
|
||||||
|
|
||||||
std::string TEXTURE_PATH = "assets/textures/viking_room.png";
|
|
||||||
|
|
||||||
void createImage(uint32_t width, uint32_t height, uint32_t mipLevels,
|
void createImage(uint32_t width, uint32_t height, uint32_t mipLevels,
|
||||||
VkSampleCountFlagBits sampleNum, VkFormat format,
|
VkSampleCountFlagBits sampleNum, VkFormat format,
|
||||||
VkImageTiling tiling, VkImageUsageFlags usage,
|
VkImageTiling tiling, VkImageUsageFlags usage,
|
||||||
@ -290,118 +285,119 @@ void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t textureWidth,
|
|||||||
}
|
}
|
||||||
// -------------------------------- Image Libraries
|
// -------------------------------- Image Libraries
|
||||||
// ------------------------------- //
|
// ------------------------------- //
|
||||||
void Texture::createTextureImage() {
|
void Texture::createMaterialTextures(std::vector<Model *> models) {
|
||||||
// Import pixels from image with data on color channels, width and height, and
|
// Import pixels from image with data on color channels, width and height, and
|
||||||
// colorspace! Its a lot of kind of complicated memory calls to bring it from
|
// colorspace! Its a lot of kind of complicated memory calls to bring it from
|
||||||
// a file -> to a buffer -> to a image object.
|
// a file -> to a buffer -> to a image object.
|
||||||
int textureWidth, textureHeight, textureChannels;
|
for (Model *model : models) {
|
||||||
stbi_uc *pixels = stbi_load(TEXTURE_PATH.c_str(), &textureWidth,
|
|
||||||
&textureHeight, &textureChannels, STBI_rgb_alpha);
|
|
||||||
mipLevels = static_cast<uint32_t>(std::floor(
|
|
||||||
std::log2(std::max(textureWidth, textureHeight)))) +
|
|
||||||
1;
|
|
||||||
|
|
||||||
VkDeviceSize imageSize = textureWidth * textureHeight * 4;
|
int textureWidth, textureHeight, textureChannels;
|
||||||
|
|
||||||
if (!pixels) {
|
stbi_uc *pixels =
|
||||||
throw std::runtime_error("Failed to load texture!");
|
stbi_load(model->getMaterial().getTexturePath().c_str(), &textureWidth,
|
||||||
}
|
&textureHeight, &textureChannels, STBI_rgb_alpha);
|
||||||
VkBuffer stagingBuffer;
|
|
||||||
VkDeviceMemory stagingBufferMemory;
|
|
||||||
Buffers::createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
||||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
stagingBuffer, stagingBufferMemory);
|
|
||||||
|
|
||||||
void *data;
|
mipLevels = static_cast<uint32_t>(std::floor(
|
||||||
vkMapMemory(DeviceControl::getDevice(), stagingBufferMemory, 0, imageSize, 0,
|
std::log2(std::max(textureWidth, textureHeight)))) +
|
||||||
&data);
|
1;
|
||||||
memcpy(data, pixels, static_cast<size_t>(imageSize));
|
|
||||||
vkUnmapMemory(DeviceControl::getDevice(), stagingBufferMemory);
|
|
||||||
|
|
||||||
stbi_image_free(pixels);
|
VkDeviceSize imageSize = textureWidth * textureHeight * 4;
|
||||||
|
|
||||||
createImage(textureWidth, textureHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT,
|
if (!pixels) {
|
||||||
VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL,
|
throw std::runtime_error("Failed to load texture!");
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
}
|
||||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
VkBuffer stagingBuffer;
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage,
|
VkDeviceMemory stagingBufferMemory;
|
||||||
textureImageMemory);
|
Buffers::createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
stagingBuffer, stagingBufferMemory);
|
||||||
|
|
||||||
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB,
|
void *data;
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
vkMapMemory(DeviceControl::getDevice(), stagingBufferMemory, 0, imageSize,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels);
|
0, &data);
|
||||||
copyBufferToImage(stagingBuffer, textureImage,
|
memcpy(data, pixels, static_cast<size_t>(imageSize));
|
||||||
static_cast<uint32_t>(textureWidth),
|
vkUnmapMemory(DeviceControl::getDevice(), stagingBufferMemory);
|
||||||
static_cast<uint32_t>(textureHeight));
|
|
||||||
|
|
||||||
vkDestroyBuffer(DeviceControl::getDevice(), stagingBuffer, nullptr);
|
stbi_image_free(pixels);
|
||||||
vkFreeMemory(DeviceControl::getDevice(), stagingBufferMemory, nullptr);
|
|
||||||
|
|
||||||
generateMipmaps(textureImage, VK_FORMAT_R8G8B8A8_SRGB, textureWidth,
|
createImage(textureWidth, textureHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT,
|
||||||
textureHeight, mipLevels);
|
VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL,
|
||||||
}
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||||
void Texture::createTextureImageView() {
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||||
// Create a texture image view, which is a struct of information about the
|
VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
// image.
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
textureImageView =
|
model->getMaterial().getTextureImage(), textureImageMemory);
|
||||||
DeviceControl::createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT, mipLevels);
|
|
||||||
}
|
|
||||||
void Texture::createTextureSampler() {
|
|
||||||
// Create a sampler to access and parse the texture object.
|
|
||||||
VkSamplerCreateInfo samplerInfo{};
|
|
||||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
// These two options define the filtering method when sampling the texture.
|
|
||||||
// It also handles zooming in versus out, min vs mag!
|
|
||||||
samplerInfo.magFilter = VK_FILTER_LINEAR; // TODO: CUBIC
|
|
||||||
samplerInfo.minFilter = VK_FILTER_LINEAR; // TODO: CUBIC
|
|
||||||
|
|
||||||
// These options define UVW edge modes, ClampToEdge extends the last pixels to
|
transitionImageLayout(model->getMaterial().getTextureImage(),
|
||||||
// the edges when larger than the UVW.
|
VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels);
|
||||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
copyBufferToImage(stagingBuffer, model->getMaterial().getTextureImage(),
|
||||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
static_cast<uint32_t>(textureWidth),
|
||||||
|
static_cast<uint32_t>(textureHeight));
|
||||||
|
|
||||||
VkPhysicalDeviceProperties properties{};
|
vkDestroyBuffer(DeviceControl::getDevice(), stagingBuffer, nullptr);
|
||||||
vkGetPhysicalDeviceProperties(DeviceControl::getPhysicalDevice(),
|
vkFreeMemory(DeviceControl::getDevice(), stagingBufferMemory, nullptr);
|
||||||
&properties);
|
|
||||||
// Enable or Disable Anisotropy, and set the amount.
|
|
||||||
samplerInfo.anisotropyEnable = VK_TRUE;
|
|
||||||
samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
|
||||||
|
|
||||||
// When sampling with Clamp to Border, the border color is defined here.
|
generateMipmaps(model->getMaterial().getTextureImage(),
|
||||||
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
VK_FORMAT_R8G8B8A8_SRGB, textureWidth, textureHeight,
|
||||||
// Normalizing coordinates changes texCoords from [0, texWidth] to [0, 1].
|
mipLevels);
|
||||||
// This is what should ALWAYS be used, because it means you can use varying
|
// Create a texture image view, which is a struct of information about the
|
||||||
// texture sizes. Another TODO: Normalizing
|
// image.
|
||||||
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
model->getMaterial().setTextureView(DeviceControl::createImageView(
|
||||||
// Compare texels to a value and use the output in filtering!
|
model->getMaterial().getTextureImage(), VK_FORMAT_R8G8B8A8_SRGB,
|
||||||
// This is mainly used in percentage-closer filtering on shadow maps, this
|
VK_IMAGE_ASPECT_COLOR_BIT, mipLevels));
|
||||||
// will be revisted eventually...
|
|
||||||
samplerInfo.compareEnable = VK_FALSE;
|
|
||||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
||||||
|
|
||||||
// Mipmaps are basically LoD's for textures, different resolutions to load
|
// Create a sampler to access and parse the texture object.
|
||||||
// based on distance. These settings simply describe how to apply mipmapping.
|
|
||||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerInfo.mipLodBias = 0.0f;
|
|
||||||
samplerInfo.minLod = 0.0f;
|
|
||||||
samplerInfo.maxLod = VK_LOD_CLAMP_NONE;
|
|
||||||
|
|
||||||
if (vkCreateSampler(DeviceControl::getDevice(), &samplerInfo, nullptr,
|
VkSamplerCreateInfo samplerInfo{};
|
||||||
&textureSampler) != VK_SUCCESS) {
|
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
throw std::runtime_error("failed to create texture sampler!");
|
// These two options define the filtering method when sampling the texture.
|
||||||
|
// It also handles zooming in versus out, min vs mag!
|
||||||
|
samplerInfo.magFilter = VK_FILTER_LINEAR; // TODO: CUBIC
|
||||||
|
samplerInfo.minFilter = VK_FILTER_LINEAR; // TODO: CUBIC
|
||||||
|
|
||||||
|
// These options define UVW edge modes, ClampToEdge extends the last pixels
|
||||||
|
// to the edges when larger than the UVW.
|
||||||
|
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
|
||||||
|
VkPhysicalDeviceProperties properties{};
|
||||||
|
vkGetPhysicalDeviceProperties(DeviceControl::getPhysicalDevice(),
|
||||||
|
&properties);
|
||||||
|
// Enable or Disable Anisotropy, and set the amount.
|
||||||
|
samplerInfo.anisotropyEnable = VK_TRUE;
|
||||||
|
samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
||||||
|
|
||||||
|
// When sampling with Clamp to Border, the border color is defined here.
|
||||||
|
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||||
|
// Normalizing coordinates changes texCoords from [0, texWidth] to [0, 1].
|
||||||
|
// This is what should ALWAYS be used, because it means you can use varying
|
||||||
|
// texture sizes. Another TODO: Normalizing
|
||||||
|
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
// Compare texels to a value and use the output in filtering!
|
||||||
|
// This is mainly used in percentage-closer filtering on shadow maps, this
|
||||||
|
// will be revisted eventually...
|
||||||
|
samplerInfo.compareEnable = VK_FALSE;
|
||||||
|
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
|
||||||
|
// Mipmaps are basically LoD's for textures, different resolutions to load
|
||||||
|
// based on distance. These settings simply describe how to apply
|
||||||
|
// mipmapping.
|
||||||
|
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
samplerInfo.mipLodBias = 0.0f;
|
||||||
|
samplerInfo.minLod = 0.0f;
|
||||||
|
samplerInfo.maxLod = VK_LOD_CLAMP_NONE;
|
||||||
|
|
||||||
|
if (vkCreateSampler(DeviceControl::getDevice(), &samplerInfo, nullptr,
|
||||||
|
&model->getMaterial().getTextureSampler()) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to create texture sampler!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Texture::destroyTextureSampler() {
|
|
||||||
vkDestroySampler(DeviceControl::getDevice(), textureSampler, nullptr);
|
|
||||||
vkDestroyImageView(DeviceControl::getDevice(), textureImageView, nullptr);
|
|
||||||
}
|
|
||||||
void Texture::destroyTextureImage() {
|
|
||||||
vkDestroyImage(DeviceControl::getDevice(), textureImage, nullptr);
|
|
||||||
vkFreeMemory(DeviceControl::getDevice(), textureImageMemory, nullptr);
|
|
||||||
}
|
|
||||||
VkFormat Texture::findDepthFormat() {
|
VkFormat Texture::findDepthFormat() {
|
||||||
return findSupportedFormat(
|
return findSupportedFormat(
|
||||||
{VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT,
|
{VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT,
|
||||||
@ -438,8 +434,6 @@ void Texture::createDepthResources() {
|
|||||||
// ---------------------------- Getters & Setters
|
// ---------------------------- Getters & Setters
|
||||||
// ---------------------------------//
|
// ---------------------------------//
|
||||||
uint32_t Texture::getMipLevels() { return mipLevels; }
|
uint32_t Texture::getMipLevels() { return mipLevels; }
|
||||||
VkImageView &Texture::getTextureImageView() { return textureImageView; }
|
|
||||||
VkSampler &Texture::getTextureSampler() { return textureSampler; }
|
|
||||||
|
|
||||||
VkImage &Texture::getColorImage() { return colorImage; }
|
VkImage &Texture::getColorImage() { return colorImage; }
|
||||||
VkImageView &Texture::getColorImageView() { return colorImageView; }
|
VkImageView &Texture::getColorImageView() { return colorImageView; }
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
#define VK_NO_PROTOTYPES
|
#define VK_NO_PROTOTYPES
|
||||||
|
|
||||||
#include "volk.h"
|
#include "volk.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
class Texture {
|
class Texture {
|
||||||
public:
|
public:
|
||||||
static void createTextureImage();
|
static const uint32_t TEXTURE_COUNT = 2;
|
||||||
static void createTextureImageView();
|
static void createMaterialTextures(std::vector<Model *> models);
|
||||||
static void createTextureSampler();
|
|
||||||
static void destroyTextureImage();
|
static void destroyTextureImage();
|
||||||
static void destroyTextureSampler();
|
static void destroyTextureSampler();
|
||||||
static VkFormat findDepthFormat();
|
static VkFormat findDepthFormat();
|
||||||
@ -14,8 +16,6 @@ public:
|
|||||||
static void createColorResources();
|
static void createColorResources();
|
||||||
// ------------ Getters & Setters ------------ //
|
// ------------ Getters & Setters ------------ //
|
||||||
static uint32_t getMipLevels();
|
static uint32_t getMipLevels();
|
||||||
static VkImageView &getTextureImageView();
|
|
||||||
static VkSampler &getTextureSampler();
|
|
||||||
|
|
||||||
static VkImage &getColorImage();
|
static VkImage &getColorImage();
|
||||||
static VkImageView &getColorImageView();
|
static VkImageView &getColorImageView();
|
||||||
|
21
src/shaders/common.glsl
Normal file
21
src/shaders/common.glsl
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#extension GL_EXT_buffer_reference : require
|
||||||
|
#extension GL_EXT_scalar_block_layout : require
|
||||||
|
#extension GL_EXT_nonuniform_qualifier : require
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
vec3 pos;
|
||||||
|
vec3 color;
|
||||||
|
vec2 texCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(buffer_reference, scalar) readonly buffer VertexBuffer{
|
||||||
|
Vertex vertices[];
|
||||||
|
};
|
||||||
|
layout( push_constant, scalar ) uniform constants {
|
||||||
|
VertexBuffer vertBuffer;
|
||||||
|
vec3 objPos;
|
||||||
|
int textureID;
|
||||||
|
mat4 model;
|
||||||
|
mat4 view;
|
||||||
|
mat4 proj;
|
||||||
|
} PushConstants;
|
@ -1,5 +1,9 @@
|
|||||||
#version 450
|
#version 450
|
||||||
layout(binding = 1) uniform sampler2D texSampler;
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
#include "common.glsl"
|
||||||
|
|
||||||
|
layout(binding = 1) uniform sampler2D texSampler[];
|
||||||
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
layout(location = 0) in vec3 fragColor;
|
||||||
layout(location = 1) in vec2 fragTexCoord;
|
layout(location = 1) in vec2 fragTexCoord;
|
||||||
@ -7,6 +11,5 @@ layout(location = 1) in vec2 fragTexCoord;
|
|||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
outColor = texture(texSampler[PushConstants.textureID], fragTexCoord);
|
||||||
outColor = vec4(texture(texSampler, fragTexCoord).rgb, 1.0);
|
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,15 @@
|
|||||||
#version 450
|
#version 450
|
||||||
#extension GL_EXT_buffer_reference : require
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
#include "common.glsl"
|
||||||
layout(binding = 0) uniform UniformBufferObject {
|
|
||||||
float time;
|
|
||||||
mat4 model;
|
|
||||||
mat4 view;
|
|
||||||
mat4 proj;
|
|
||||||
} ubo;
|
|
||||||
struct Vertex {
|
|
||||||
|
|
||||||
vec3 pos;
|
|
||||||
vec3 color;
|
|
||||||
vec2 texCoord;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(buffer_reference, std430) readonly buffer VertexBuffer{
|
|
||||||
Vertex vertices[];
|
|
||||||
};
|
|
||||||
layout( push_constant ) uniform constants {
|
|
||||||
VertexBuffer vertBuffer;
|
|
||||||
}PushConstants;
|
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
layout(location = 0) out vec3 fragColor;
|
||||||
layout(location = 1) out vec2 fragTexCoord;
|
layout(location = 1) out vec2 fragTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Vertex v = PushConstants.vertBuffer.vertices[gl_VertexIndex];
|
Vertex vertex = PushConstants.vertBuffer.vertices[gl_VertexIndex];
|
||||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(v.pos, 1.0f);
|
|
||||||
fragColor = v.color.xyz;
|
gl_Position = PushConstants.proj * PushConstants.view * PushConstants.model *
|
||||||
fragTexCoord = v.texCoord;
|
vec4(vertex.pos + PushConstants.objPos, 1.0f);
|
||||||
|
fragColor = vertex.color.rgb;
|
||||||
|
fragTexCoord = vertex.texCoord;
|
||||||
}
|
}
|
||||||
|
41
src/types.h
41
src/types.h
@ -1,9 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
|
||||||
#include "vk_mem_alloc.h"
|
#include "vk_mem_alloc.h"
|
||||||
#include <array>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
class Agnosia_T {
|
class Agnosia_T {
|
||||||
@ -11,38 +9,10 @@ public:
|
|||||||
struct Vertex {
|
struct Vertex {
|
||||||
// This defines what a vertex is!
|
// This defines what a vertex is!
|
||||||
// We control the position, color and texture coordinate here!
|
// We control the position, color and texture coordinate here!
|
||||||
alignas(16) glm::vec3 pos;
|
glm::vec3 pos;
|
||||||
alignas(16) glm::vec3 color;
|
glm::vec3 color;
|
||||||
alignas(8) glm::vec2 texCoord;
|
glm::vec2 texCoord;
|
||||||
|
|
||||||
static VkVertexInputBindingDescription getBindingDescription() {
|
|
||||||
VkVertexInputBindingDescription bindingDescription{};
|
|
||||||
bindingDescription.binding = 0;
|
|
||||||
bindingDescription.stride = sizeof(Vertex);
|
|
||||||
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
||||||
|
|
||||||
return bindingDescription;
|
|
||||||
}
|
|
||||||
static std::array<VkVertexInputAttributeDescription, 3>
|
|
||||||
getAttributeDescriptions() {
|
|
||||||
std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};
|
|
||||||
|
|
||||||
attributeDescriptions[0].binding = 0;
|
|
||||||
attributeDescriptions[0].location = 0;
|
|
||||||
attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
attributeDescriptions[0].offset = offsetof(Vertex, pos);
|
|
||||||
|
|
||||||
attributeDescriptions[1].binding = 0;
|
|
||||||
attributeDescriptions[1].location = 1;
|
|
||||||
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
attributeDescriptions[1].offset = offsetof(Vertex, color);
|
|
||||||
|
|
||||||
attributeDescriptions[2].binding = 0;
|
|
||||||
attributeDescriptions[2].location = 2;
|
|
||||||
attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
|
|
||||||
attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
|
|
||||||
return attributeDescriptions;
|
|
||||||
}
|
|
||||||
bool operator==(const Vertex &other) const {
|
bool operator==(const Vertex &other) const {
|
||||||
return pos == other.pos && color == other.color &&
|
return pos == other.pos && color == other.color &&
|
||||||
texCoord == other.texCoord;
|
texCoord == other.texCoord;
|
||||||
@ -60,5 +30,10 @@ public:
|
|||||||
};
|
};
|
||||||
struct GPUPushConstants {
|
struct GPUPushConstants {
|
||||||
VkDeviceAddress vertexBuffer;
|
VkDeviceAddress vertexBuffer;
|
||||||
|
glm::vec3 objPosition;
|
||||||
|
int textureID;
|
||||||
|
glm::mat4 model;
|
||||||
|
glm::mat4 view;
|
||||||
|
glm::mat4 proj;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user