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:
parent
606c2f97cd
commit
9688c091af
9 changed files with 314 additions and 11 deletions
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
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 <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
|
||||||
|
|
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 <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;
|
||||||
|
|
||||||
|
|
|
@ -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.
|
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue