Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified assets/basicmesh.glb
Binary file not shown.
Binary file added assets/cube.glb
Binary file not shown.
Binary file added assets/sphere.glb
Binary file not shown.
29 changes: 26 additions & 3 deletions src/core/Mesh.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
// Mesh.cpp
#include "core/Mesh.h"

Mesh::Mesh(const std::string &filePath) {
Mesh::Mesh(const std::string &filePath) : _currentModelPath(filePath) {
VulkanEngine &engine = VulkanEngine::Get();

_rid = engine.registerMesh(filePath);
}

Mesh::~Mesh() {
remove_model();
}

void Mesh::set_model(const std::string &filePath) {
VulkanEngine &engine = VulkanEngine::Get();

engine.unregisterMesh(_rid);
// Unregister current model if exists
if (!_currentModelPath.empty()) {
engine.unregisterMesh(_rid);
}

// Register new model
_currentModelPath = filePath;
_rid = engine.registerMesh(filePath);

// Reapply transform to new model
engine.setMeshTransform(_rid, _transform);
}

void Mesh::remove_model() {
if (!_currentModelPath.empty()) {
VulkanEngine &engine = VulkanEngine::Get();
engine.unregisterMesh(_rid);
_currentModelPath.clear();
}
}


void Mesh::set_transform(glm::mat4 t) {
VulkanEngine &engine = VulkanEngine::Get();

Expand Down
6 changes: 4 additions & 2 deletions src/graphics/vulkan/vk_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1195,8 +1195,10 @@ int64_t VulkanEngine::registerMesh(const std::string& filePath) {
}

void VulkanEngine::unregisterMesh(int64_t id) {
meshes.erase(id);
transforms.erase(id);
if (meshes.find(id) != meshes.end()) {
meshes.erase(id);
transforms.erase(id);
}
}

void VulkanEngine::setMeshTransform(int64_t id, glm::mat4 mat) {
Expand Down
116 changes: 56 additions & 60 deletions src/graphics/vulkan/vk_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,26 +203,18 @@ VkSamplerMipmapMode extract_mipmap_mode(fastgltf::Filter filter) {
std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
std::string_view filePath) {
fmt::print("Loading GLTF: {}", filePath);

auto scene = std::make_shared<LoadedGLTF>();
scene->creator = engine;
LoadedGLTF& file = *scene;

fastgltf::Parser parser{};

constexpr auto gltfOptions =
fastgltf::Options::DontRequireValidAssetMember |
fastgltf::Options::AllowDouble | fastgltf::Options::LoadGLBBuffers |
fastgltf::Options::LoadExternalBuffers;
// fastgltf::Options::LoadExternalImages;

fastgltf::GltfDataBuffer data;
data.loadFromFile(filePath);

fastgltf::Asset gltf;

std::filesystem::path path = filePath;

auto type = fastgltf::determineGltfFileType(&data);
if (type == fastgltf::GltfType::glTF) {
auto load = parser.loadGltf(&data, path.parent_path(), gltfOptions);
Expand All @@ -248,35 +240,31 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
return {};
}

// we can stimate the descriptors we will need accurately
// Estimate descriptor pool size based on materials
std::vector<DescriptorAllocatorGrowable::PoolSizeRatio> sizes = {
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1}};
file.descriptorPool.init(
engine->_device,
static_cast<uint32_t>(std::max(gltf.materials.size(), size_t(1))),
sizes);

file.descriptorPool.init(engine->_device,
static_cast<uint32_t>(gltf.materials.size()),
sizes);

// load samplers
// Load samplers
for (fastgltf::Sampler& sampler : gltf.samplers) {
VkSamplerCreateInfo sampl = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = nullptr};
sampl.maxLod = VK_LOD_CLAMP_NONE;
sampl.minLod = 0;

sampl.magFilter = extract_filter(
sampler.magFilter.value_or(fastgltf::Filter::Nearest));
sampl.minFilter = extract_filter(
sampler.minFilter.value_or(fastgltf::Filter::Nearest));

sampl.mipmapMode = extract_mipmap_mode(
sampler.minFilter.value_or(fastgltf::Filter::Nearest));

VkSampler newSampler;
vkCreateSampler(engine->_device, &sampl, nullptr, &newSampler);

file.samplers.push_back(newSampler);
}

Expand All @@ -285,22 +273,24 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
std::vector<AllocatedImage> images;
std::vector<std::shared_ptr<GLTFMaterial>> materials;

// load all textures
// Load all textures
images.reserve(gltf.images.size());
for (size_t i = 0; i < gltf.images.size(); i++) {
images.push_back(engine->_errorCheckerboardImage->get());
}

// create buffer to hold the material data
// Create buffer to hold the material data
size_t materialCount = gltf.materials.size() ? gltf.materials.size() : 1;
file.materialDataBuffer = engine->create_buffer(
sizeof(GLTFMetallic_Roughness::MaterialConstants) *
gltf.materials.size(),
sizeof(GLTFMetallic_Roughness::MaterialConstants) * materialCount,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);

uint32_t data_index = 0;
auto* sceneMaterialConstants =
(GLTFMetallic_Roughness::MaterialConstants*)
file.materialDataBuffer.info.pMappedData;

// Process all materials from the GLTF
for (fastgltf::Material& mat : gltf.materials) {
auto newMat = std::make_shared<GLTFMaterial>();
materials.push_back(newMat);
Expand All @@ -311,10 +301,9 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
constants.colorFactors.y = mat.pbrData.baseColorFactor[1];
constants.colorFactors.z = mat.pbrData.baseColorFactor[2];
constants.colorFactors.w = mat.pbrData.baseColorFactor[3];

constants.metal_rough_factors.x = mat.pbrData.metallicFactor;
constants.metal_rough_factors.y = mat.pbrData.roughnessFactor;
// write material parameters to buffer

sceneMaterialConstants[data_index] = constants;

auto passType = MaterialPass::MainColor;
Expand All @@ -323,39 +312,57 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
}

GLTFMetallic_Roughness::MaterialResources materialResources;
// default the material textures

materialResources.colorImage = engine->_whiteImage->get();

materialResources.colorSampler = engine->_defaultSamplerLinear;
materialResources.metalRoughImage = engine->_whiteImage->get();
materialResources.metalRoughSampler = engine->_defaultSamplerLinear;

// set the uniform buffer for the material data
materialResources.dataBuffer = file.materialDataBuffer.buffer;
materialResources.dataBufferOffset =
data_index * sizeof(GLTFMetallic_Roughness::MaterialConstants);
// grab textures from gltf file

if (mat.pbrData.baseColorTexture.has_value()) {
size_t img = gltf.textures[mat.pbrData.baseColorTexture.value()
.textureIndex]
.imageIndex.value();
size_t sampler = gltf.textures[mat.pbrData.baseColorTexture.value()
.textureIndex]
.samplerIndex.value();

materialResources.colorImage = images[img];
materialResources.colorSampler = file.samplers[sampler];
}
// build material

newMat->data = engine->metalRoughMaterial.write_material(
engine->_device, passType, materialResources,
file.descriptorPool);

data_index++;
}

// use the same vectors for all meshes so that the memory doesnt reallocate
// as
// often
// Add a fallback material if no materials were defined in the GLTF
if (materials.empty()) {
auto defaultMat = std::make_shared<GLTFMaterial>();
materials.push_back(defaultMat);

GLTFMetallic_Roughness::MaterialConstants constants = {};
constants.colorFactors = glm::vec4(1.0f); // White base color
constants.metal_rough_factors = glm::vec4(0.0f); // Non-metallic, smooth

sceneMaterialConstants[0] = constants;

GLTFMetallic_Roughness::MaterialResources resources;
resources.colorImage = engine->_whiteImage->get();
resources.colorSampler = engine->_defaultSamplerLinear;
resources.metalRoughImage = engine->_whiteImage->get();
resources.metalRoughSampler = engine->_defaultSamplerLinear;
resources.dataBuffer = file.materialDataBuffer.buffer;
resources.dataBufferOffset = 0;

defaultMat->data = engine->metalRoughMaterial.write_material(
engine->_device, MaterialPass::MainColor, resources,
file.descriptorPool);
}

std::vector<uint32_t> indices;
std::vector<Vertex> vertices;

Expand All @@ -364,8 +371,6 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
meshes.push_back(newmesh);
file.meshes[name.c_str()] = newmesh;
newmesh->name = name;

// clear the mesh arrays each mesh, we dont want to merge them by error
indices.clear();
vertices.clear();

Expand All @@ -374,27 +379,24 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
newSurface.startIndex = (uint32_t)indices.size();
newSurface.count =
(uint32_t)gltf.accessors[p.indicesAccessor.value()].count;

auto initial_vtx = static_cast<uint32_t>(vertices.size());

// load indexes
// Load indices
{
fastgltf::Accessor& indexaccessor =
gltf.accessors[p.indicesAccessor.value()];
indices.reserve(indices.size() + indexaccessor.count);

fastgltf::iterateAccessor<std::uint32_t>(
gltf, indexaccessor, [&](std::uint32_t idx) {
indices.push_back(idx + initial_vtx);
});
}

// load vertex positions
// Load vertex positions
{
fastgltf::Accessor& posAccessor =
gltf.accessors[p.findAttribute("POSITION")->second];
vertices.resize(vertices.size() + posAccessor.count);

fastgltf::iterateAccessorWithIndex<glm::vec3>(
gltf, posAccessor, [&](glm::vec3 v, size_t index) {
Vertex newvtx;
Expand All @@ -407,7 +409,7 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
});
}

// load vertex normals
// Load vertex normals
auto normals = p.findAttribute("NORMAL");
if (normals != p.attributes.end()) {
fastgltf::iterateAccessorWithIndex<glm::vec3>(
Expand All @@ -417,7 +419,7 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
});
}

// load UVs
// Load UVs
auto uv = p.findAttribute("TEXCOORD_0");
if (uv != p.attributes.end()) {
fastgltf::iterateAccessorWithIndex<glm::vec2>(
Expand All @@ -428,7 +430,7 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
});
}

// load vertex colors
// Load vertex colors
auto colors = p.findAttribute("COLOR_0");
if (colors != p.attributes.end()) {
fastgltf::iterateAccessorWithIndex<glm::vec4>(
Expand All @@ -438,32 +440,28 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
});
}

// Assign material safely
if (p.materialIndex.has_value()) {
newSurface.material = materials[p.materialIndex.value()];
} else {
newSurface.material = materials[0];
newSurface.material = materials[0]; // Always valid now
}

newmesh->surfaces.push_back(newSurface);
}

newmesh->meshBuffers = engine->uploadMesh(indices, vertices);
}

// load all nodes and their meshes
// Load all nodes and their meshes
for (fastgltf::Node& node : gltf.nodes) {
std::shared_ptr<ENode> newNode;

// find if the node has a mesh, and if it does hook it to the mesh
// pointer and allocate it with the meshnode class
if (node.meshIndex.has_value()) {
newNode = std::make_shared<MeshNode>();
dynamic_cast<MeshNode*>(newNode.get())->mesh =
meshes[*node.meshIndex];
} else {
newNode = std::make_shared<ENode>();
}

nodes.push_back(newNode);
file.nodes[node.name.c_str()];

Expand All @@ -483,36 +481,34 @@ std::optional<std::shared_ptr<LoadedGLTF>> loadGltf(VulkanEngine* engine,
const glm::vec3 sc(transform.scale[0],
transform.scale[1],
transform.scale[2]);

const glm::mat4 tm =
glm::translate(glm::mat4(1.f), tl);
const glm::mat4 rm = glm::toMat4(rot);
const glm::mat4 sm =
glm::scale(glm::mat4(1.f), sc);

newNode->localTransform = tm * rm * sm;
}},
node.transform);
}

// run loop again to setup transform hierarchy
// Setup transform hierarchy
for (size_t i = 0; i < gltf.nodes.size(); i++) {
fastgltf::Node& node = gltf.nodes[i];
std::shared_ptr<ENode>& sceneNode = nodes[i];

for (auto& c : node.children) {
sceneNode->children.push_back(nodes[c]);
nodes[c]->parent = sceneNode;
}
}

// find the top nodes, with no parents
for (auto& node : nodes) {
if (node->parent.lock() == nullptr) {
file.topNodes.push_back(node);
node->refreshTransform(glm::mat4{1.f});
// Find top-level nodes
for (auto& n : nodes) {
if (n->parent.lock() == nullptr) {
file.topNodes.push_back(n);
n->refreshTransform(glm::mat4{1.f});
}
}

return scene;
}

Expand Down
Loading
Loading