1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-04-24 04:57:45 +00:00

Add bone editing to mdlviewer

This is big, as it shows we are now correctly parsing the havok XML
sidecard data and you can edit the scale of the bones in the viewport.

This also pulls in a new libxiv version, which is required to fill out
the used bones list on a Model. Right now the bone editing is incredibly
basic, and the viewport suffers from a lack of depth testing still.
This commit is contained in:
Joshua Goins 2022-04-28 17:50:05 -04:00
parent 606c2f97cd
commit 9688c091af
9 changed files with 314 additions and 11 deletions

View file

@ -2,7 +2,9 @@ find_package(assimp REQUIRED)
add_executable(mdlviewer add_executable(mdlviewer
src/main.cpp src/main.cpp
src/mainwindow.cpp) src/mainwindow.cpp
src/vec3edit.cpp
include/vec3edit.h)
target_include_directories(mdlviewer target_include_directories(mdlviewer
PUBLIC PUBLIC
include) include)

View file

@ -7,6 +7,7 @@
#include "renderer.hpp" #include "renderer.hpp"
#include "types/slot.h" #include "types/slot.h"
#include "types/race.h" #include "types/race.h"
#include "havokxmlparser.h"
struct ModelInfo { struct ModelInfo {
int primaryID; int primaryID;
@ -47,10 +48,14 @@ private:
Race currentRace = Race::HyurMidlanderMale; Race currentRace = Race::HyurMidlanderMale;
int currentLod = 0; int currentLod = 0;
glm::vec3 currentScale = glm::vec3(1);
Bone* currentEditedBone = nullptr;
GameData& data; GameData& data;
Renderer* renderer; Renderer* renderer;
VulkanWindow* vkWindow; VulkanWindow* vkWindow;
StandaloneWindow* standaloneWindow; StandaloneWindow* standaloneWindow;
Skeleton skeleton;
}; };

View file

@ -0,0 +1,23 @@
#pragma once
#include <QSpinBox>
#include <QWidget>
#include <glm/glm.hpp>
class Vector3Edit : public QWidget {
Q_OBJECT
public:
explicit Vector3Edit(glm::vec3& vec, QWidget* parent = nullptr);
~Vector3Edit();
signals:
void onValueChanged();
private:
struct {
QDoubleSpinBox *x, *y, *z;
} spinBoxes;
glm::vec3& vec;
QTimer* updateTimer;
};

View file

@ -17,11 +17,16 @@
#include <QPushButton> #include <QPushButton>
#include <QFileDialog> #include <QFileDialog>
#include <magic_enum.hpp> #include <magic_enum.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "gamedata.h" #include "gamedata.h"
#include "exhparser.h" #include "exhparser.h"
#include "exdparser.h" #include "exdparser.h"
#include "mdlparser.h" #include "mdlparser.h"
#include "equipment.h"
#include "glm/glm.hpp"
#include "vec3edit.h"
#ifndef USE_STANDALONE_WINDOW #ifndef USE_STANDALONE_WINDOW
class VulkanWindow : public QWindow class VulkanWindow : public QWindow
@ -78,6 +83,22 @@ private:
#endif #endif
void calculate_bone_inverse_pose(Skeleton& skeleton, Bone& bone, Bone* parent_bone) {
const glm::mat4 parentMatrix = parent_bone == nullptr ? glm::mat4(1.0f) : parent_bone->inversePose;
glm::mat4 local(1.0f);
local = glm::translate(local, glm::vec3(bone.position[0], bone.position[1], bone.position[2]));
local *= glm::mat4_cast(glm::quat(bone.rotation[3], bone.rotation[0], bone.rotation[1], bone.rotation[2]));
local = glm::scale(local, glm::vec3(bone.scale[0], bone.scale[1], bone.scale[2]));
bone.inversePose = parentMatrix * local;
for(auto& b : skeleton.bones) {
if(b.parent != nullptr && b.parent->name == bone.name)
calculate_bone_inverse_pose(skeleton, b, &bone);
}
}
MainWindow::MainWindow(GameData& data) : data(data) { MainWindow::MainWindow(GameData& data) : data(data) {
setWindowTitle("mdlviewer"); setWindowTitle("mdlviewer");
setMinimumSize(QSize(640, 480)); setMinimumSize(QSize(640, 480));
@ -208,6 +229,36 @@ MainWindow::MainWindow(GameData& data) : data(data) {
} }
} }
}); });
skeleton = parseHavokXML("/home/josh/test.xml");
calculate_bone_inverse_pose(skeleton, *skeleton.root_bone, nullptr);
auto boneListWidget = new QListWidget();
for(auto& bone : skeleton.bones) {
bone.inversePose = glm::inverse(bone.inversePose);
boneListWidget->addItem(bone.name.c_str());
}
boneListWidget->setMaximumWidth(200);
connect(boneListWidget, &QListWidget::itemClicked, [this](QListWidgetItem* item) {
for(auto& bone : skeleton.bones) {
if(bone.name == item->text().toStdString()) {
currentScale = glm::make_vec3(bone.scale.data());
currentEditedBone = &bone;
}
}
});
layout->addWidget(boneListWidget);
Vector3Edit* scaleEdit = new Vector3Edit(currentScale);
connect(scaleEdit, &Vector3Edit::onValueChanged, [this] {
memcpy(currentEditedBone->scale.data(), glm::value_ptr(currentScale), sizeof(float) * 3);
reloadGearAppearance();
});
layout->addWidget(scaleEdit);
} }
void MainWindow::exportModel(Model& model, QString fileName) { void MainWindow::exportModel(Model& model, QString fileName) {
@ -292,9 +343,47 @@ void MainWindow::reloadGearModel() {
reloadGearAppearance(); reloadGearAppearance();
} }
void calculate_bone(Skeleton& skeleton, Bone& bone, const Bone* parent_bone) {
glm::mat4 parent_matrix = glm::mat4(1.0f);
if(parent_bone != nullptr)
parent_matrix = parent_bone->localTransform;
glm::mat4 local = glm::mat4(1.0f);
local = glm::translate(local, glm::vec3(bone.position[0], bone.position[1], bone.position[2]));
local *= glm::mat4_cast(glm::quat(bone.rotation[3], bone.rotation[0], bone.rotation[1], bone.rotation[2]));
local = glm::scale(local, glm::vec3(bone.scale[0], bone.scale[1], bone.scale[2]));
bone.localTransform = parent_matrix * local;
bone.finalTransform = bone.localTransform * bone.inversePose;
for(auto& b : skeleton.bones) {
if(b.parent != nullptr && b.parent->name == bone.name)
calculate_bone(skeleton, b, &bone);
}
}
void MainWindow::reloadGearAppearance() { void MainWindow::reloadGearAppearance() {
loadedGear.renderModel = renderer->addModel(loadedGear.model, currentLod); loadedGear.renderModel = renderer->addModel(loadedGear.model, currentLod);
calculate_bone(skeleton, *skeleton.root_bone, nullptr);
for(int i = 0; i < 128; i++) {
loadedGear.renderModel.boneData[i] = glm::mat4(1.0f);
}
// we want to map the actual affected bones to bone ids
std::map<int, int> boneMapping;
for(int i = 0; i < loadedGear.model.affectedBoneNames.size(); i++) {
for(int k = 0; k < skeleton.bones.size(); k++) {
if(skeleton.bones[k].name == loadedGear.model.affectedBoneNames[i])
boneMapping[i] = k;
}
}
for(int i = 0; i < loadedGear.model.affectedBoneNames.size(); i++) {
loadedGear.renderModel.boneData[i] = skeleton.bones[boneMapping[i]].finalTransform;
}
#ifndef USE_STANDALONE_WINDOW #ifndef USE_STANDALONE_WINDOW
vkWindow->models = {loadedGear.renderModel}; vkWindow->models = {loadedGear.renderModel};
#else #else

View file

@ -0,0 +1,58 @@
#include "vec3edit.h"
#include <QHBoxLayout>
#include <QTimer>
Vector3Edit::Vector3Edit(glm::vec3& vec, QWidget* parent) : QWidget(parent), vec(vec) {
QHBoxLayout* itemsLayout = new QHBoxLayout(this);
spinBoxes.x = new QDoubleSpinBox();
spinBoxes.y = new QDoubleSpinBox();
spinBoxes.z = new QDoubleSpinBox();
spinBoxes.x->setMinimum(-10000.0);
spinBoxes.x->setMaximum(10000.0);
spinBoxes.y->setMinimum(-10000.0);
spinBoxes.y->setMaximum(10000.0);
spinBoxes.z->setMinimum(-10000.0);
spinBoxes.z->setMaximum(10000.0);
itemsLayout->addWidget(spinBoxes.x);
itemsLayout->addWidget(spinBoxes.y);
itemsLayout->addWidget(spinBoxes.z);
spinBoxes.x->setValue(vec.x);
spinBoxes.y->setValue(vec.y);
spinBoxes.z->setValue(vec.z);
connect(spinBoxes.x, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) {
vec.x = d;
emit onValueChanged();
});
connect(spinBoxes.y, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) {
vec.y = d;
emit onValueChanged();
});
connect(spinBoxes.z, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) {
vec.z = d;
emit onValueChanged();
});
// TODO: find a better way to do this
updateTimer = new QTimer();
connect(updateTimer, &QTimer::timeout, [this, &vec]() {
if (vec.x != spinBoxes.x->value() || vec.y != spinBoxes.y->value() || vec.z != spinBoxes.z->value()) {
spinBoxes.x->setValue(vec.x);
spinBoxes.y->setValue(vec.y);
spinBoxes.z->setValue(vec.z);
}
});
updateTimer->start(1);
}
Vector3Edit::~Vector3Edit() {
updateTimer->stop();
}

View file

@ -3,6 +3,7 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <vector> #include <vector>
#include <array> #include <array>
#include <glm/ext/matrix_float4x4.hpp>
#include "mdlparser.h" #include "mdlparser.h"
@ -11,11 +12,14 @@ struct RenderPart {
VkBuffer vertexBuffer, indexBuffer; VkBuffer vertexBuffer, indexBuffer;
VkDeviceMemory vertexMemory, indexMemory; VkDeviceMemory vertexMemory, indexMemory;
std::vector<PartSubmesh> submeshes;
}; };
struct RenderModel { struct RenderModel {
Model model; Model model;
std::vector<RenderPart> parts; std::vector<RenderPart> parts;
std::array<glm::mat4, 128> boneData;
}; };
class Renderer { class Renderer {
@ -23,6 +27,7 @@ public:
Renderer(); Renderer();
void initPipeline(); void initPipeline();
void initDescriptors();
bool initSwapchain(VkSurfaceKHR surface, int width, int height); bool initSwapchain(VkSurfaceKHR surface, int width, int height);
void resize(VkSurfaceKHR surface, int width, int height); void resize(VkSurfaceKHR surface, int width, int height);
@ -45,6 +50,14 @@ public:
std::array<VkFence, 3> inFlightFences; std::array<VkFence, 3> inFlightFences;
std::array<VkSemaphore, 3> imageAvailableSemaphores, renderFinishedSemaphores; std::array<VkSemaphore, 3> imageAvailableSemaphores, renderFinishedSemaphores;
uint32_t currentFrame = 0; uint32_t currentFrame = 0;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
VkBuffer boneInfoBuffer = VK_NULL_HANDLE;
VkDeviceMemory boneInfoMemory = VK_NULL_HANDLE;
VkDescriptorSetLayout setLayout = VK_NULL_HANDLE;
VkDescriptorSet set = VK_NULL_HANDLE;
VkPipeline pipeline; VkPipeline pipeline;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;

View file

@ -2,16 +2,33 @@
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec4 inBoneWeights;
layout(location = 3) in uvec4 inBoneIds;
layout(location = 0) out vec3 outNormal; layout(location = 0) out vec3 outNormal;
layout(location = 1) out vec3 outFragPos; layout(location = 1) out vec3 outFragPos;
layout(push_constant) uniform PushConstant { layout(push_constant) uniform PushConstant {
mat4 mvp; mat4 vp, model;
int boneOffset;
};
layout(std430, binding = 2) buffer readonly BoneInformation {
mat4 bones[128];
}; };
void main() { void main() {
gl_Position = mvp * vec4(inPosition, 1.0); mat4 BoneTransform = bones[boneOffset + inBoneIds[0]] * inBoneWeights[0];
outNormal = inNormal; BoneTransform += bones[boneOffset + inBoneIds[1]] * inBoneWeights[1];
outFragPos = inNormal; BoneTransform += bones[boneOffset + inBoneIds[2]] * inBoneWeights[2];
BoneTransform += bones[boneOffset + inBoneIds[3]] * inBoneWeights[3];
BoneTransform = model * BoneTransform;
vec4 bPos = BoneTransform * vec4(inPosition, 1.0);
vec4 bNor = BoneTransform * vec4(inNormal, 0.0);
gl_Position = vp * bPos;
outNormal = bNor.xyz;
outFragPos = vec3(model * vec4(inPosition, 1.0));
} }

Binary file not shown.

View file

@ -306,6 +306,7 @@ bool Renderer::initSwapchain(VkSurfaceKHR surface, int width, int height) {
vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass); vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass);
initDescriptors();
initPipeline(); initPipeline();
swapchainFramebuffers.resize(swapchainViews.size()); swapchainFramebuffers.resize(swapchainViews.size());
@ -402,6 +403,25 @@ void Renderer::render(std::vector<RenderModel> models) {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
for(auto model : models) { for(auto model : models) {
// copy bone data
{
const size_t bufferSize = sizeof(glm::mat4) * 128;
void *mapped_data = nullptr;
vkMapMemory(device, boneInfoMemory, 0, bufferSize, 0, &mapped_data);
memcpy(mapped_data, model.boneData.data(), bufferSize);
VkMappedMemoryRange range = {};
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.memory = boneInfoMemory;
range.size = bufferSize;
vkFlushMappedMemoryRanges(device, 1, &range);
vkUnmapMemory(device, boneInfoMemory);
}
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, 0, nullptr);
for(auto part : model.parts) { for(auto part : model.parts) {
VkDeviceSize offsets[] = {0}; VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets); vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets);
@ -410,10 +430,17 @@ void Renderer::render(std::vector<RenderModel> models) {
glm::mat4 p = glm::perspective(glm::radians(45.0f), swapchainExtent.width / (float) swapchainExtent.height, glm::mat4 p = glm::perspective(glm::radians(45.0f), swapchainExtent.width / (float) swapchainExtent.height,
0.1f, 100.0f); 0.1f, 100.0f);
p[1][1] *= -1; p[1][1] *= -1;
glm::mat4 v = glm::lookAt(glm::vec3(0, 1, -2.5), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); glm::mat4 v = glm::lookAt(glm::vec3(3), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0));
glm::mat4 mvp = p * v; glm::mat4 vp = p * v;
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp); vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &vp);
glm::mat4 m = glm::mat4(1.0f);
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), sizeof(glm::mat4), &m);
int test = 0;
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4) * 2, sizeof(int), &test);
vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0); vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0);
} }
@ -517,6 +544,7 @@ RenderModel Renderer::addModel(const Model& model, int lod) {
for(auto part : model.lods[lod].parts) { for(auto part : model.lods[lod].parts) {
RenderPart renderPart; RenderPart renderPart;
renderPart.submeshes = part.submeshes;
size_t vertexSize = part.vertices.size() * sizeof(Vertex); size_t vertexSize = part.vertices.size() * sizeof(Vertex);
auto[vertexBuffer, vertexMemory] = createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); auto[vertexBuffer, vertexMemory] = createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
@ -590,6 +618,7 @@ void Renderer::initPipeline() {
VkVertexInputAttributeDescription positionAttribute = {}; VkVertexInputAttributeDescription positionAttribute = {};
positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT; positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
positionAttribute.offset = offsetof(Vertex, position); positionAttribute.offset = offsetof(Vertex, position);
VkVertexInputAttributeDescription normalAttribute = {}; VkVertexInputAttributeDescription normalAttribute = {};
@ -597,7 +626,17 @@ void Renderer::initPipeline() {
normalAttribute.location = 1; normalAttribute.location = 1;
normalAttribute.offset = offsetof(Vertex, normal); normalAttribute.offset = offsetof(Vertex, normal);
std::array<VkVertexInputAttributeDescription, 2> attributes = {positionAttribute, normalAttribute}; VkVertexInputAttributeDescription boneWeightAttribute = {};
boneWeightAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
boneWeightAttribute.location = 2;
boneWeightAttribute.offset = offsetof(Vertex, boneWeights);
VkVertexInputAttributeDescription boneIdAttribute = {};
boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT;
boneIdAttribute.location = 3;
boneIdAttribute.offset = offsetof(Vertex, boneIds);
std::array<VkVertexInputAttributeDescription, 4> attributes = {positionAttribute, normalAttribute, boneWeightAttribute, boneIdAttribute};
VkPipelineVertexInputStateCreateInfo vertexInputState = {}; VkPipelineVertexInputStateCreateInfo vertexInputState = {};
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
@ -647,13 +686,15 @@ void Renderer::initPipeline() {
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
VkPushConstantRange pushConstantRange = {}; VkPushConstantRange pushConstantRange = {};
pushConstantRange.size = sizeof(glm::mat4); pushConstantRange.size = (sizeof(glm::mat4) * 2) + sizeof(int);
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &setLayout;
vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout); vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
@ -700,4 +741,59 @@ VkShaderModule Renderer::loadShaderFromDisk(const std::string_view path) {
file.read(buffer.data(), fileSize); file.read(buffer.data(), fileSize);
return createShaderModule(reinterpret_cast<const uint32_t *>(buffer.data()), fileSize); return createShaderModule(reinterpret_cast<const uint32_t *>(buffer.data()), fileSize);
} }
void Renderer::initDescriptors() {
VkDescriptorPoolSize poolSize = {};
poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
poolSize.descriptorCount = 1;
VkDescriptorPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolCreateInfo.poolSizeCount = 1;
poolCreateInfo.pPoolSizes = &poolSize;
poolCreateInfo.maxSets = 1;
vkCreateDescriptorPool(device, &poolCreateInfo, nullptr, &descriptorPool);
VkDescriptorSetLayoutBinding boneInfoBufferBinding = {};
boneInfoBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
boneInfoBufferBinding.descriptorCount = 1;
boneInfoBufferBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
boneInfoBufferBinding.binding = 2;
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = 1;
layoutInfo.pBindings = &boneInfoBufferBinding;
vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &setLayout);
const size_t bufferSize = sizeof(glm::mat4) * 128;
auto [buffer, memory] = createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
boneInfoBuffer = buffer;
boneInfoMemory = memory;
VkDescriptorSetAllocateInfo allocateInfo = {};
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocateInfo.descriptorPool = descriptorPool;
allocateInfo.descriptorSetCount = 1;
allocateInfo.pSetLayouts = &setLayout;
vkAllocateDescriptorSets(device, &allocateInfo, &set);
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = boneInfoBuffer;
bufferInfo.range = bufferSize;
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = set;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
descriptorWrite.dstBinding = 2;
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
}