mirror of
https://github.com/redstrate/Novus.git
synced 2025-04-23 20:47: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:
parent
606c2f97cd
commit
9688c091af
9 changed files with 314 additions and 11 deletions
|
@ -2,7 +2,9 @@ find_package(assimp REQUIRED)
|
|||
|
||||
add_executable(mdlviewer
|
||||
src/main.cpp
|
||||
src/mainwindow.cpp)
|
||||
src/mainwindow.cpp
|
||||
src/vec3edit.cpp
|
||||
include/vec3edit.h)
|
||||
target_include_directories(mdlviewer
|
||||
PUBLIC
|
||||
include)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "renderer.hpp"
|
||||
#include "types/slot.h"
|
||||
#include "types/race.h"
|
||||
#include "havokxmlparser.h"
|
||||
|
||||
struct ModelInfo {
|
||||
int primaryID;
|
||||
|
@ -47,10 +48,14 @@ private:
|
|||
|
||||
Race currentRace = Race::HyurMidlanderMale;
|
||||
int currentLod = 0;
|
||||
glm::vec3 currentScale = glm::vec3(1);
|
||||
Bone* currentEditedBone = nullptr;
|
||||
|
||||
GameData& data;
|
||||
|
||||
Renderer* renderer;
|
||||
VulkanWindow* vkWindow;
|
||||
StandaloneWindow* standaloneWindow;
|
||||
|
||||
Skeleton skeleton;
|
||||
};
|
23
mdlviewer/include/vec3edit.h
Normal file
23
mdlviewer/include/vec3edit.h
Normal 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;
|
||||
};
|
|
@ -17,11 +17,16 @@
|
|||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
#include <magic_enum.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "gamedata.h"
|
||||
#include "exhparser.h"
|
||||
#include "exdparser.h"
|
||||
#include "mdlparser.h"
|
||||
#include "equipment.h"
|
||||
#include "glm/glm.hpp"
|
||||
#include "vec3edit.h"
|
||||
|
||||
#ifndef USE_STANDALONE_WINDOW
|
||||
class VulkanWindow : public QWindow
|
||||
|
@ -78,6 +83,22 @@ private:
|
|||
|
||||
#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) {
|
||||
setWindowTitle("mdlviewer");
|
||||
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) {
|
||||
|
@ -292,9 +343,47 @@ void MainWindow::reloadGearModel() {
|
|||
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() {
|
||||
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
|
||||
vkWindow->models = {loadedGear.renderModel};
|
||||
#else
|
||||
|
|
58
mdlviewer/src/vec3edit.cpp
Normal file
58
mdlviewer/src/vec3edit.cpp
Normal 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();
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include <vulkan/vulkan.h>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <glm/ext/matrix_float4x4.hpp>
|
||||
|
||||
#include "mdlparser.h"
|
||||
|
||||
|
@ -11,11 +12,14 @@ struct RenderPart {
|
|||
|
||||
VkBuffer vertexBuffer, indexBuffer;
|
||||
VkDeviceMemory vertexMemory, indexMemory;
|
||||
|
||||
std::vector<PartSubmesh> submeshes;
|
||||
};
|
||||
|
||||
struct RenderModel {
|
||||
Model model;
|
||||
std::vector<RenderPart> parts;
|
||||
std::array<glm::mat4, 128> boneData;
|
||||
};
|
||||
|
||||
class Renderer {
|
||||
|
@ -23,6 +27,7 @@ public:
|
|||
Renderer();
|
||||
|
||||
void initPipeline();
|
||||
void initDescriptors();
|
||||
bool initSwapchain(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<VkSemaphore, 3> imageAvailableSemaphores, renderFinishedSemaphores;
|
||||
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;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
|
||||
|
|
|
@ -2,16 +2,33 @@
|
|||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
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 = 1) out vec3 outFragPos;
|
||||
|
||||
layout(push_constant) uniform PushConstant {
|
||||
mat4 mvp;
|
||||
mat4 vp, model;
|
||||
int boneOffset;
|
||||
};
|
||||
|
||||
layout(std430, binding = 2) buffer readonly BoneInformation {
|
||||
mat4 bones[128];
|
||||
};
|
||||
|
||||
void main() {
|
||||
gl_Position = mvp * vec4(inPosition, 1.0);
|
||||
outNormal = inNormal;
|
||||
outFragPos = inNormal;
|
||||
mat4 BoneTransform = bones[boneOffset + inBoneIds[0]] * inBoneWeights[0];
|
||||
BoneTransform += bones[boneOffset + inBoneIds[1]] * inBoneWeights[1];
|
||||
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.
|
@ -306,6 +306,7 @@ bool Renderer::initSwapchain(VkSurfaceKHR surface, int width, int height) {
|
|||
|
||||
vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass);
|
||||
|
||||
initDescriptors();
|
||||
initPipeline();
|
||||
|
||||
swapchainFramebuffers.resize(swapchainViews.size());
|
||||
|
@ -402,6 +403,25 @@ void Renderer::render(std::vector<RenderModel> models) {
|
|||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
|
||||
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) {
|
||||
VkDeviceSize offsets[] = {0};
|
||||
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,
|
||||
0.1f, 100.0f);
|
||||
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 mvp = p * v;
|
||||
glm::mat4 v = glm::lookAt(glm::vec3(3), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0));
|
||||
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);
|
||||
}
|
||||
|
@ -517,6 +544,7 @@ RenderModel Renderer::addModel(const Model& model, int lod) {
|
|||
|
||||
for(auto part : model.lods[lod].parts) {
|
||||
RenderPart renderPart;
|
||||
renderPart.submeshes = part.submeshes;
|
||||
|
||||
size_t vertexSize = part.vertices.size() * sizeof(Vertex);
|
||||
auto[vertexBuffer, vertexMemory] = createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
|
@ -590,6 +618,7 @@ void Renderer::initPipeline() {
|
|||
|
||||
VkVertexInputAttributeDescription positionAttribute = {};
|
||||
positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
positionAttribute.offset = offsetof(Vertex, position);
|
||||
|
||||
VkVertexInputAttributeDescription normalAttribute = {};
|
||||
|
@ -597,7 +626,17 @@ void Renderer::initPipeline() {
|
|||
normalAttribute.location = 1;
|
||||
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 = {};
|
||||
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;
|
||||
|
||||
VkPushConstantRange pushConstantRange = {};
|
||||
pushConstantRange.size = sizeof(glm::mat4);
|
||||
pushConstantRange.size = (sizeof(glm::mat4) * 2) + sizeof(int);
|
||||
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
|
||||
pipelineLayoutInfo.setLayoutCount = 1;
|
||||
pipelineLayoutInfo.pSetLayouts = &setLayout;
|
||||
|
||||
vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
|
||||
|
||||
|
@ -700,4 +741,59 @@ VkShaderModule Renderer::loadShaderFromDisk(const std::string_view path) {
|
|||
file.read(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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue