Skip to content
Snippets Groups Projects
Commit a51ca6e3 authored by Mara Vogt's avatar Mara Vogt
Browse files

Added implementation for asset loader

a very basic implementation of a small asset loader using the fx-gltf library
a few bugs still remain and are marked with comments
parent 811cab54
Branches
Tags
1 merge request!19Resolve "Asset Loading"
Pipeline #25013 passed
...@@ -4,24 +4,105 @@ ...@@ -4,24 +4,105 @@
#include <fx/gltf.h> #include <fx/gltf.h>
namespace vkcv::asset { namespace vkcv::asset {
/**
* convert the accessor type from the fx-gltf library to an unsigned int
* @param type
* @return unsigned integer representation
*/
uint8_t convertTypeToInt(const fx::gltf::Accessor::Type type){
switch (type){
case fx::gltf::Accessor::Type::None :
return 0;
case fx::gltf::Accessor::Type::Scalar :
return 1;
case fx::gltf::Accessor::Type::Vec2 :
return 2;
case fx::gltf::Accessor::Type::Vec3 :
return 3;
case fx::gltf::Accessor::Type::Vec4 :
return 4;
default: return 10; // TODO add cases for matrices (or maybe change the type in the struct itself)
}
}
int loadMesh(const std::string &path, Mesh &mesh) { int loadMesh(const std::string &path, Mesh &mesh) {
// TODO load the gltf file using the library, return 0 if there is an // load the gltf file using the library, return 0 if there is an
// error. // error.
// If the library throws excaptions, catch them and maybe print an // If the library throws exceptions, catch them and maybe print an
// error, but do not pass on the exception to the caller! // error, but do not pass on the exception to the caller!
// Looking at the example code of fx-gltf I would assume that // Looking at the example code of fx-gltf I would assume that
// fx::gltf::LoadFromText(); is a good starting point. // fx::gltf::LoadFromText(); is a good starting point.
// TODO Verify that all required information can be found in the fx::gltf::Document object = {};
std::vector<VertexAttribute> vertexAttributes = {};
std::vector<VertexGroup> vertexGroups = {};
std::vector<Material> materials = {};
try {
if (path.rfind(".glb") != std::string::npos){
object = fx::gltf::LoadFromBinary(path);
} else {
object = fx::gltf::LoadFromText(path);
}
}
catch (std::system_error){ // catch exception of invalid file path
return 0;
}
catch (...){
return 0;
}
// Verify that all required information can be found in the
// struct/class returned by fx-gltf (eg. check if there is exactly one // struct/class returned by fx-gltf (eg. check if there is exactly one
// mesh and that it has at least 3 vertices or something like that) and // mesh and that it has at least 3 vertices or something like that) and
// return 0 if something is missing. // return 0 if something is missing.
// The important thing here is that we don't create an incomplete mesh // The important thing here is that we don't create an incomplete mesh
// because we start copying data before making sure all the required // because we start copying data before making sure all the required
// data is available. // data is available.
// TODO Fill the output argument 'mesh' with the data from the loaded std::cout << "Number of Meshes loaded: " << object.meshes.size() << std::endl;
std::cout << "Number of Primitives loaded: " << object.meshes[0].primitives.size() << std::endl;
if (object.meshes.size() != 1){ // only continue if exactly one mesh is loaded
return 0;
}
fx::gltf::Mesh const &objectMesh = object.meshes[0];
fx::gltf::Primitive const &objectPrimitive = objectMesh.primitives[0];
fx::gltf::Accessor posAccessor;
// fill vertex attributes vector
// for some reason the loop seems to run through the attributes the wrong way round. It starts with 2 and ends on 0.
for (auto const & attrib : objectPrimitive.attributes){
//std::cout << "AttType: " << attrib.second << std::endl;
fx::gltf::Accessor accessor = object.accessors[attrib.second];
vertexAttributes.push_back(VertexAttribute{});
// Primitive Type
if (attrib.first == "POSITION"){
vertexAttributes.back().type = POSITION;
posAccessor = accessor;
} else if (attrib.first == "NORMAL"){
vertexAttributes.back().type = NORMAL;
} else if (attrib.first == "TEXCOORD_0"){
vertexAttributes.back().type = TEXCOORD_0;
} else {
return 0;
}
// Offset
vertexAttributes.back().offset = object.bufferViews[accessor.bufferView].byteOffset;
// Length
vertexAttributes.back().length = object.bufferViews[accessor.bufferView].byteLength;
// Stride
vertexAttributes.back().stride = object.bufferViews[accessor.bufferView].byteStride;
// Component Type
vertexAttributes.back().componentType = static_cast<uint16_t>(accessor.componentType);
// Component Count
vertexAttributes.back().componentCount = convertTypeToInt(accessor.type); // Conversion doesn't work, don't know why
std::cout << "Should be a number: " << vertexAttributes.back().componentCount << std::endl;
}
// Fill the output argument 'mesh' with the data from the loaded
// glTF file. // glTF file.
// Look at the structs 'Mesh', 'VertexGroup' and 'VertexAttribute' // Look at the structs 'Mesh', 'VertexGroup' and 'VertexAttribute'
// defined in asset_loader.hpp and compare it to the glTF cheat sheet: // defined in asset_loader.hpp and compare it to the glTF cheat sheet:
...@@ -37,7 +118,44 @@ namespace vkcv::asset { ...@@ -37,7 +118,44 @@ namespace vkcv::asset {
// Once this works, we can add support for materials/textures, but I // Once this works, we can add support for materials/textures, but I
// wouldn't include this feature until loading of vertices+indices is // wouldn't include this feature until loading of vertices+indices is
// proven to work // proven to work
// indexBuffer
fx::gltf::Accessor & indexAccessor = object.accessors[objectPrimitive.indices];
fx::gltf::BufferView & indexBufferView = object.bufferViews[indexAccessor.bufferView];
fx::gltf::Buffer & indexBuffer = object.buffers[indexBufferView.buffer];
// vertexBuffer
fx::gltf::BufferView& vertexBufferView = object.bufferViews[posAccessor.bufferView];
fx::gltf::Buffer& vertexBuffer = object.buffers[vertexBufferView.buffer];
// fill vertex groups vector
vertexGroups.push_back(VertexGroup{});
vertexGroups.back() = {
static_cast<PrimitiveMode>(objectPrimitive.mode), // mode
object.accessors[objectPrimitive.indices].count, // num indices
posAccessor.count, // num vertices
{ //index buffer
&indexBuffer.data[static_cast<uint64_t>(indexBufferView.byteOffset) + indexAccessor.byteOffset],
indexBufferView.byteLength,
indexBufferView.byteOffset
},
{ //vertex buffer
&vertexBuffer.data[static_cast<uint64_t>(vertexBufferView.byteOffset) + posAccessor.byteOffset],
vertexBufferView.byteLength,
vertexAttributes
},
{posAccessor.min[0], posAccessor.min[1], posAccessor.min[2]}, // bounding box min
{posAccessor.max[0], posAccessor.max[1], posAccessor.max[2]}, // bounding box max
static_cast<uint8_t>(objectPrimitive.material) // material index
};
// fill mesh struct
mesh = {
object.meshes[0].name,
vertexGroups,
materials
};
// Finally return 1 to signal that all is fine // Finally return 1 to signal that all is fine
return 1; return 1;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment