707 lines
25 KiB
C++
707 lines
25 KiB
C++
#include "dl_model_loader.h"
|
||
|
||
|
||
namespace dl
|
||
{
|
||
|
||
std::vector<ModelObject*> ModelLoader::_load_gltf(std::string_view path_name, std::string_view res_name, bool is_glb)
|
||
{
|
||
tinygltf::Model model;
|
||
tinygltf::TinyGLTF loader;
|
||
std::string err;
|
||
std::string warn;
|
||
|
||
log_info("开始加载gltf文件:{},{}", res_name, path_name);
|
||
|
||
bool load_ok;
|
||
if (is_glb)
|
||
load_ok = loader.LoadBinaryFromFile(&model, &err, &warn, std::string{ path_name });
|
||
else
|
||
load_ok = loader.LoadASCIIFromFile(&model, &err, &warn, std::string{ path_name });
|
||
|
||
|
||
if (!warn.empty())
|
||
log_warn("{}", warn);
|
||
|
||
if (!err.empty())
|
||
log_err("{}", err);
|
||
|
||
if (!load_ok)
|
||
{
|
||
log_err("解析gltf格式失败:{}", err);
|
||
return {};
|
||
}
|
||
log_info("子模型数:{}", model.meshes.size());
|
||
log_info("材质数:{}", model.materials.size());
|
||
|
||
// 只生成一个ModelObject(animation可能是节点动画,暂不支持)
|
||
bool has_bone = !model.skins.empty();
|
||
|
||
std::vector<ModelObject*> ret;
|
||
ModelObject* model_object = new ModelObject;
|
||
std::vector<Vertex>& mo_vertices = model_object->_allVertex;
|
||
std::vector<VertexBone>& mo_vertices_bone = model_object->_allVertexBone;
|
||
std::vector<uint32_t>& mo_indices = model_object->_allIndex;
|
||
std::vector<ModelObjectMaterial>& mo_material = model_object->_allMaterial;
|
||
ret.push_back(model_object);
|
||
|
||
_gltf_load_material();
|
||
_gltf_load_scene(model);
|
||
|
||
//子网格合并
|
||
if (false)
|
||
{//合并网格连续,且材质相同的项
|
||
std::vector<ModelObjectSub> vec_sub;
|
||
ModelObjectSub* pre = nullptr;
|
||
//
|
||
for (auto iter = model_object->_allSub.begin();
|
||
iter != model_object->_allSub.end(); ++iter)
|
||
{
|
||
ModelObjectSub& sub = *iter;
|
||
|
||
if (pre
|
||
&& sub._indexMaterial == pre->_indexMaterial
|
||
&& (sub._range._offsetIndex
|
||
== pre->_range._offsetIndex + pre->_range._countTriangle * 3))
|
||
{//是连续的
|
||
pre->_range._countTriangle += sub._range._countTriangle;
|
||
}
|
||
else
|
||
{
|
||
vec_sub.push_back(sub);
|
||
pre = &vec_sub.back();
|
||
}
|
||
}
|
||
log_info("子网格合并:{}->{}", model_object->_allSub.size(), vec_sub.size());
|
||
for (ModelObjectSub& sub : vec_sub)
|
||
{
|
||
log_info("合并后网格,起始:{},三角数:{},材质:{}",
|
||
sub._range._offsetIndex, sub._range._countTriangle, sub._indexMaterial);
|
||
}
|
||
|
||
std::swap(model_object->_allSub, vec_sub);
|
||
int pause = 3;
|
||
}
|
||
|
||
if (!has_bone)
|
||
{
|
||
assert(mo_vertices_bone.empty());
|
||
}
|
||
else
|
||
{
|
||
assert(mo_vertices.empty());
|
||
}
|
||
|
||
|
||
log_msg("解析gltf模型完成:v_{},i_{}",
|
||
!has_bone ? mo_vertices.size() : mo_vertices_bone.size(),
|
||
mo_indices.size());
|
||
return ret;
|
||
}
|
||
|
||
void ModelLoader::_gltf_load_material()
|
||
{
|
||
//mo_material.resize(model.materials.size());
|
||
//for (size_t i = 0; i < model.materials.size(); ++i)
|
||
//{
|
||
// tinygltf::Material& m = model.materials[i];
|
||
// log_info("材质:{},{}", i, m.name);
|
||
// tinygltf::PbrMetallicRoughness& pbr = m.pbrMetallicRoughness;
|
||
|
||
// ModelObjectMaterial& material = mo_material[i];
|
||
// material._materialName = m.name;
|
||
|
||
// material._material._diffuseAlbedo = {
|
||
// (float)pbr.baseColorFactor[0],
|
||
// (float)pbr.baseColorFactor[1],
|
||
// (float)pbr.baseColorFactor[2], 1.0f };
|
||
// material._material._fresnelR0 = {
|
||
// (float)pbr.metallicFactor, (float)pbr.metallicFactor, (float)pbr.metallicFactor };
|
||
// material._material._roughness = (float)pbr.roughnessFactor;
|
||
|
||
// // 纹理导出
|
||
// auto fn_texture = [&](int index, std::string_view tag) {
|
||
// if (index == -1)
|
||
// return std::string{};
|
||
// tinygltf::Image& img = model.images[index];
|
||
// if (!img.uri.empty())
|
||
// return img.uri;
|
||
|
||
// std::string path_name = fmt::format("{}{}{}#{}.png",
|
||
// File::PathTemp(), res_name, tag, i);
|
||
// stbi_write_png(CodeCvt::Utf8ToMultiByte(path_name).c_str(),
|
||
// img.width, img.height,
|
||
// 4, img.image.data(), 0);
|
||
|
||
// return path_name;
|
||
// };
|
||
// material._pathTexDiffuse = fn_texture(pbr.baseColorTexture.index, "");
|
||
// material._pathTexNormal = fn_texture(m.normalTexture.index, "_normal");
|
||
//}
|
||
for (tinygltf::Material& mat : gltfModel.materials) {
|
||
vkglTF::Material material{};
|
||
material.doubleSided = mat.doubleSided;
|
||
if (mat.values.find("baseColorTexture") != mat.values.end()) {
|
||
material.baseColorTexture = &textures[mat.values["baseColorTexture"].TextureIndex()];
|
||
material.texCoordSets.baseColor = mat.values["baseColorTexture"].TextureTexCoord();
|
||
}
|
||
if (mat.values.find("metallicRoughnessTexture") != mat.values.end()) {
|
||
material.metallicRoughnessTexture = &textures[mat.values["metallicRoughnessTexture"].TextureIndex()];
|
||
material.texCoordSets.metallicRoughness = mat.values["metallicRoughnessTexture"].TextureTexCoord();
|
||
}
|
||
if (mat.values.find("roughnessFactor") != mat.values.end()) {
|
||
material.roughnessFactor = static_cast<float>(mat.values["roughnessFactor"].Factor());
|
||
}
|
||
if (mat.values.find("metallicFactor") != mat.values.end()) {
|
||
material.metallicFactor = static_cast<float>(mat.values["metallicFactor"].Factor());
|
||
}
|
||
if (mat.values.find("baseColorFactor") != mat.values.end()) {
|
||
material.baseColorFactor = glm::make_vec4(mat.values["baseColorFactor"].ColorFactor().data());
|
||
}
|
||
if (mat.additionalValues.find("normalTexture") != mat.additionalValues.end()) {
|
||
material.normalTexture = &textures[mat.additionalValues["normalTexture"].TextureIndex()];
|
||
material.texCoordSets.normal = mat.additionalValues["normalTexture"].TextureTexCoord();
|
||
}
|
||
if (mat.additionalValues.find("emissiveTexture") != mat.additionalValues.end()) {
|
||
material.emissiveTexture = &textures[mat.additionalValues["emissiveTexture"].TextureIndex()];
|
||
material.texCoordSets.emissive = mat.additionalValues["emissiveTexture"].TextureTexCoord();
|
||
}
|
||
if (mat.additionalValues.find("occlusionTexture") != mat.additionalValues.end()) {
|
||
material.occlusionTexture = &textures[mat.additionalValues["occlusionTexture"].TextureIndex()];
|
||
material.texCoordSets.occlusion = mat.additionalValues["occlusionTexture"].TextureTexCoord();
|
||
}
|
||
if (mat.additionalValues.find("alphaMode") != mat.additionalValues.end()) {
|
||
tinygltf::Parameter param = mat.additionalValues["alphaMode"];
|
||
if (param.string_value == "BLEND") {
|
||
material.alphaMode = Material::ALPHAMODE_BLEND;
|
||
}
|
||
if (param.string_value == "MASK") {
|
||
material.alphaCutoff = 0.5f;
|
||
material.alphaMode = Material::ALPHAMODE_MASK;
|
||
}
|
||
}
|
||
if (mat.additionalValues.find("alphaCutoff") != mat.additionalValues.end()) {
|
||
material.alphaCutoff = static_cast<float>(mat.additionalValues["alphaCutoff"].Factor());
|
||
}
|
||
if (mat.additionalValues.find("emissiveFactor") != mat.additionalValues.end()) {
|
||
material.emissiveFactor = glm::vec4(glm::make_vec3(mat.additionalValues["emissiveFactor"].ColorFactor().data()), 1.0);
|
||
}
|
||
|
||
// Extensions
|
||
if (mat.extensions.find("KHR_materials_pbrSpecularGlossiness") != mat.extensions.end()) {
|
||
auto ext = mat.extensions.find("KHR_materials_pbrSpecularGlossiness");
|
||
if (ext->second.Has("specularGlossinessTexture")) {
|
||
auto index = ext->second.Get("specularGlossinessTexture").Get("index");
|
||
material.extension.specularGlossinessTexture = &textures[index.Get<int>()];
|
||
auto texCoordSet = ext->second.Get("specularGlossinessTexture").Get("texCoord");
|
||
material.texCoordSets.specularGlossiness = texCoordSet.Get<int>();
|
||
material.pbrWorkflows.specularGlossiness = true;
|
||
material.pbrWorkflows.metallicRoughness = false;
|
||
}
|
||
if (ext->second.Has("diffuseTexture")) {
|
||
auto index = ext->second.Get("diffuseTexture").Get("index");
|
||
material.extension.diffuseTexture = &textures[index.Get<int>()];
|
||
}
|
||
if (ext->second.Has("diffuseFactor")) {
|
||
auto factor = ext->second.Get("diffuseFactor");
|
||
for (uint32_t i = 0; i < factor.ArrayLen(); i++) {
|
||
auto val = factor.Get(i);
|
||
material.extension.diffuseFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
|
||
}
|
||
}
|
||
if (ext->second.Has("specularFactor")) {
|
||
auto factor = ext->second.Get("specularFactor");
|
||
for (uint32_t i = 0; i < factor.ArrayLen(); i++) {
|
||
auto val = factor.Get(i);
|
||
material.extension.specularFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
|
||
}
|
||
}
|
||
}
|
||
|
||
if (mat.extensions.find("KHR_materials_unlit") != mat.extensions.end()) {
|
||
material.unlit = true;
|
||
}
|
||
|
||
if (mat.extensions.find("KHR_materials_emissive_strength") != mat.extensions.end()) {
|
||
auto ext = mat.extensions.find("KHR_materials_emissive_strength");
|
||
if (ext->second.Has("emissiveStrength")) {
|
||
auto value = ext->second.Get("emissiveStrength");
|
||
material.emissiveStrength = (float)value.Get<double>();
|
||
}
|
||
}
|
||
|
||
material.index = static_cast<uint32_t>(materials.size());
|
||
materials.push_back(material);
|
||
}
|
||
// Push a default material at the end of the list for meshes with no material assigned
|
||
materials.push_back(Material());
|
||
}
|
||
|
||
void ModelLoader::_gltf_get_node_prop(const tinygltf::Model& model, const tinygltf::Node& node,
|
||
size_t& vertex_count, size_t& index_count)
|
||
{
|
||
if (node.children.size() > 0)
|
||
{
|
||
for (size_t i = 0; i < node.children.size(); ++i)
|
||
{
|
||
_gltf_get_node_prop(model, model.nodes[node.children[i]], vertex_count, index_count);
|
||
}
|
||
}
|
||
if (node.mesh > -1)
|
||
{
|
||
const tinygltf::Mesh& mesh = model.meshes[node.mesh];
|
||
for (size_t i = 0; i < mesh.primitives.size(); ++i)
|
||
{
|
||
const tinygltf::Primitive& primitive = mesh.primitives[i];
|
||
vertex_count += model.accessors[primitive.attributes.find("POSITION")->second].count;
|
||
if (primitive.indices > -1)
|
||
{
|
||
index_count += model.accessors[primitive.indices].count;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void ModelLoader::_gltf_load_scene(const tinygltf::Model& model, ModelData* data)
|
||
{
|
||
// 只读一个场景
|
||
const tinygltf::Scene& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0];
|
||
|
||
// 统计顶点和索引
|
||
LoaderInfo loader_info{};
|
||
size_t vertex_count = 0;
|
||
size_t index_count = 0;
|
||
for (size_t i = 0; i < scene.nodes.size(); i++)
|
||
{
|
||
_gltf_get_node_prop(model, model.nodes[scene.nodes[i]], vertex_count, index_count);
|
||
}
|
||
loader_info._vertexBuffer = new Vertex[vertex_count];
|
||
loader_info._indexBuffer = new uint32_t[index_count];
|
||
|
||
// 读取节点
|
||
for (size_t i = 0; i < scene.nodes.size(); i++) {
|
||
_gltf_load_node(model, scene.nodes[i], nullptr, loader_info, data);
|
||
}
|
||
// 读取动画
|
||
if (model.animations.size() > 0) {
|
||
_gltf_load_animation(model);
|
||
}
|
||
// 读取蒙皮
|
||
_gltf_load_skin(model);
|
||
|
||
for (ModelNode* model_node : linearNodes)
|
||
{
|
||
// Assign skins
|
||
if (model_node->skinIndex > -1)
|
||
{
|
||
model_node->skin = skins[model_node->skinIndex];
|
||
}
|
||
// Initial pose
|
||
if (model_node->mesh)
|
||
{
|
||
model_node->update();
|
||
}
|
||
}
|
||
}
|
||
|
||
void ModelLoader::_gltf_load_node(const tinygltf::Model& model, int node,
|
||
ModelNode* model_node_parent, LoaderInfo& loader_info, ModelData* data)
|
||
{
|
||
const tinygltf::Node& nn = model.nodes[node];
|
||
|
||
ModelNode* model_node = new ModelNode;
|
||
model_node._parent = model_node_parent;
|
||
model_node._trans2Parent = _gltf_get_node_trans(model, node);
|
||
|
||
for (size_t i = 0; i < nn.children.size(); ++i)
|
||
{
|
||
_gltf_load_node(model, nn.children[i], model_node_parent, loader_info);
|
||
}
|
||
|
||
// 读取mesh
|
||
if (nn.mesh > -1)
|
||
{
|
||
const tinygltf::Mesh& mesh = model.meshes[node.mesh];
|
||
ModelMesh* model_mesh = new Mesh;
|
||
|
||
for (size_t j = 0; j < mesh.primitives.size(); j++)
|
||
{
|
||
const tinygltf::Primitive& primitive = mesh.primitives[j];
|
||
uint32_t vertex_start = (uint32_t)loader_info._vertexPos;
|
||
uint32_t index_start = (uint32_t)loader_info._indexPos;
|
||
uint32_t vertex_count = 0;
|
||
uint32_t index_count = 0;
|
||
Position3 pos_min{};
|
||
Position3 pos_max{};
|
||
bool has_skin = false;
|
||
bool has_index = primitive.indices > -1;
|
||
// Vertices
|
||
{
|
||
const float* buffer_pos = nullptr;
|
||
const float* buffer_normal = nullptr;
|
||
const float* buffer_uv0 = nullptr;
|
||
const float* buffer_uv1 = nullptr;
|
||
const float* buffer_color = nullptr;
|
||
const void* buffer_joint = nullptr;
|
||
const float* buffer_weight = nullptr;
|
||
|
||
int stride_pos;
|
||
int stride_normal;
|
||
int stride_uv0;
|
||
int stride_uv1;
|
||
int stride_color0;
|
||
int stride_joint;
|
||
int stride_weight;
|
||
|
||
int joint_comp_type;
|
||
|
||
// 位置属性必须存在
|
||
assert(primitive.attributes.find("POSITION") != primitive.attributes.end());
|
||
|
||
const tinygltf::Accessor& accessor_pos = model.accessors[primitive.attributes.find("POSITION")->second];
|
||
const tinygltf::BufferView& view_pos = model.bufferViews[accessor_pos.bufferView];
|
||
buffer_pos = reinterpret_cast<const float*>(&(model.buffers[view_pos.buffer].data[accessor_pos.byteOffset + view_pos.byteOffset]));
|
||
pos_min = glm::vec3(accessor_pos.minValues[0], accessor_pos.minValues[1], accessor_pos.minValues[2]);
|
||
pos_max = glm::vec3(accessor_pos.maxValues[0], accessor_pos.maxValues[1], accessor_pos.maxValues[2]);
|
||
vertex_count = static_cast<uint32_t>(accessor_pos.count);
|
||
stride_pos = accessor_pos.ByteStride(view_pos) ? (accessor_pos.ByteStride(view_pos) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC3);
|
||
|
||
if (primitive.attributes.find("NORMAL") != primitive.attributes.end())
|
||
{
|
||
const tinygltf::Accessor& normAccessor = model.accessors[primitive.attributes.find("NORMAL")->second];
|
||
const tinygltf::BufferView& normView = model.bufferViews[normAccessor.bufferView];
|
||
buffer_normal = reinterpret_cast<const float*>(&(model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset]));
|
||
stride_normal = normAccessor.ByteStride(normView) ? (normAccessor.ByteStride(normView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC3);
|
||
}
|
||
|
||
// UVs
|
||
if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end())
|
||
{
|
||
const tinygltf::Accessor& uvAccessor = model.accessors[primitive.attributes.find("TEXCOORD_0")->second];
|
||
const tinygltf::BufferView& uvView = model.bufferViews[uvAccessor.bufferView];
|
||
buffer_uv0 = reinterpret_cast<const float*>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
|
||
stride_uv0 = uvAccessor.ByteStride(uvView) ? (uvAccessor.ByteStride(uvView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC2);
|
||
}
|
||
if (primitive.attributes.find("TEXCOORD_1") != primitive.attributes.end())
|
||
{
|
||
const tinygltf::Accessor& uvAccessor = model.accessors[primitive.attributes.find("TEXCOORD_1")->second];
|
||
const tinygltf::BufferView& uvView = model.bufferViews[uvAccessor.bufferView];
|
||
buffer_uv1 = reinterpret_cast<const float*>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
|
||
stride_uv1 = uvAccessor.ByteStride(uvView) ? (uvAccessor.ByteStride(uvView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC2);
|
||
}
|
||
|
||
// Vertex colors
|
||
if (primitive.attributes.find("COLOR_0") != primitive.attributes.end())
|
||
{
|
||
const tinygltf::Accessor& accessor = model.accessors[primitive.attributes.find("COLOR_0")->second];
|
||
const tinygltf::BufferView& view = model.bufferViews[accessor.bufferView];
|
||
buffer_color = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
||
stride_color0 = accessor.ByteStride(view) ? (accessor.ByteStride(view) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC3);
|
||
}
|
||
|
||
// Skinning
|
||
// Joints
|
||
if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end())
|
||
{
|
||
const tinygltf::Accessor& jointAccessor = model.accessors[primitive.attributes.find("JOINTS_0")->second];
|
||
const tinygltf::BufferView& jointView = model.bufferViews[jointAccessor.bufferView];
|
||
buffer_joint = &(model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset]);
|
||
joint_comp_type = jointAccessor.componentType;
|
||
stride_joint = jointAccessor.ByteStride(jointView) ? (jointAccessor.ByteStride(jointView) / tinygltf::GetComponentSizeInBytes(joint_comp_type)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC4);
|
||
}
|
||
|
||
if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end())
|
||
{
|
||
const tinygltf::Accessor& weightAccessor = model.accessors[primitive.attributes.find("WEIGHTS_0")->second];
|
||
const tinygltf::BufferView& weightView = model.bufferViews[weightAccessor.bufferView];
|
||
buffer_weight = reinterpret_cast<const float*>(&(model.buffers[weightView.buffer].data[weightAccessor.byteOffset + weightView.byteOffset]));
|
||
stride_weight = weightAccessor.ByteStride(weightView) ? (weightAccessor.ByteStride(weightView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC4);
|
||
}
|
||
|
||
has_skin = (buffer_joint && buffer_weight);
|
||
|
||
for (size_t i = 0; v < accessor_pos.count; ++i)
|
||
{
|
||
Vertex& v = loader_info._vertexBuffer[loader_info._vertexPos];
|
||
v._pos = *(Position3*)(&buffer_pos[v * stride_pos]);
|
||
if (!buffer_normal)
|
||
v._normal = {};
|
||
else
|
||
v._normal = *(Position3*)(&buffer_normal[v * stride_normal]);
|
||
if (!buffer_uv0)
|
||
v._uv0 = {};
|
||
else
|
||
v._uv0 = *(Position2*)&buffer_uv0[v * stride_uv0];
|
||
if (!buffer_uv1)
|
||
v._uv1 = {};
|
||
else
|
||
v._uv1 = *(Position2*)&buffer_uv1[v * stride_uv1];
|
||
if (!buffer_color)
|
||
v._color = {1, 1, 1, 1};
|
||
else
|
||
v._color = *(Position4*)&buffer_color[v * stride_color0];
|
||
|
||
if (!has_skin)
|
||
{
|
||
v._joint0 = {};
|
||
}
|
||
else
|
||
{
|
||
switch (joint_comp_type)
|
||
{
|
||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||
{
|
||
const uint16_t* buf = static_cast<const uint16_t*>(buffer_joint);
|
||
for(size_t i = 0; i < NUM_BONE; ++i)
|
||
v._joint0[i] = buf[v * stride_joint][i];
|
||
break;
|
||
}
|
||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||
{
|
||
const uint8_t* buf = static_cast<const uint8_t*>(buffer_joint);
|
||
for (size_t i = 0; i < NUM_BONE; ++i)
|
||
v._joint0[i] = (uint16_t)buf[v * stride_joint][i];
|
||
break;
|
||
}
|
||
default:
|
||
assert(0);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!has_skin)
|
||
v._weight0 = {};
|
||
else
|
||
v._weight0 = *(Position4*)(&buffer_weight[v * stride_weight]);
|
||
|
||
if (Every::Zero(v._weight0)) {
|
||
v._weight0[0] = 1.0_f;
|
||
}
|
||
++loader_info._vertexPos;
|
||
}
|
||
}
|
||
// Indices
|
||
if (has_index)
|
||
{
|
||
const tinygltf::Accessor& accessor = model.accessors[primitive.indices > -1 ? primitive.indices : 0];
|
||
const tinygltf::BufferView& bufferView = model.bufferViews[accessor.bufferView];
|
||
const tinygltf::Buffer& buffer = model.buffers[bufferView.buffer];
|
||
|
||
index_count = static_cast<uint32_t>(accessor.count);
|
||
const void* data_ptr = &(buffer.data[accessor.byteOffset + bufferView.byteOffset]);
|
||
|
||
switch (accessor.componentType) {
|
||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT:
|
||
{
|
||
const uint32_t* buf = static_cast<const uint32_t*>(data_ptr);
|
||
for (size_t index = 0; index < accessor.count; index++)
|
||
{
|
||
loader_info._indexBuffer[loader_info._indexPos] = buf[index] + vertex_start;
|
||
++loader_info._indexPos;
|
||
}
|
||
break;
|
||
}
|
||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT:
|
||
{
|
||
const uint16_t* buf = static_cast<const uint16_t*>(data_ptr);
|
||
for (size_t index = 0; index < accessor.count; index++)
|
||
{
|
||
loader_info._indexBuffer[loader_info._indexPos] = buf[index] + vertex_start;
|
||
++loader_info._indexPos;
|
||
}
|
||
break;
|
||
}
|
||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE:
|
||
{
|
||
const uint8_t* buf = static_cast<const uint8_t*>(data_ptr);
|
||
for (size_t index = 0; index < accessor.count; index++)
|
||
{
|
||
loader_info._indexBuffer[loader_info._indexPos] = buf[index] + vertex_start;
|
||
++loader_info._indexPos;
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
assert(0);
|
||
return;
|
||
}
|
||
}
|
||
ModelPrimitive* model_primitive = new Primitive(index_start, index_count,
|
||
vertex_count, primitive.material > -1 ? materials[primitive.material] : materials.back());
|
||
model_primitive->setBoundingBox(pos_min, pos_max);
|
||
model_mesh->primitives.push_back(model_primitive);
|
||
}
|
||
// Mesh BB from BBs of primitives
|
||
for (ModelPrimitive* p : model_mesh->primitives)
|
||
{
|
||
if (p->bb.valid && !model_mesh->bb.valid)
|
||
{
|
||
model_mesh->bb = p->bb;
|
||
model_mesh->bb.valid = true;
|
||
}
|
||
model_mesh->bb.min = glm::min(newMesh->bb.min, p->bb.min);
|
||
model_mesh->bb.max = glm::max(newMesh->bb.max, p->bb.max);
|
||
}
|
||
model_node->mesh = model_mesh;
|
||
}
|
||
if (model_node_parent) {
|
||
model_node_parent->children.push_back(model_node);
|
||
}
|
||
else {
|
||
nodes.push_back(model_node);
|
||
}
|
||
linearNodes.push_back(model_node);
|
||
}
|
||
|
||
void ModelLoader::_load_skin(tinygltf::Model& gltfModel)
|
||
{
|
||
for (tinygltf::Skin& source : gltfModel.skins) {
|
||
Skin* newSkin = new Skin{};
|
||
newSkin->name = source.name;
|
||
|
||
// Find skeleton root node
|
||
if (source.skeleton > -1) {
|
||
newSkin->skeletonRoot = nodeFromIndex(source.skeleton);
|
||
}
|
||
|
||
// Find joint nodes
|
||
for (int jointIndex : source.joints) {
|
||
Node* node = nodeFromIndex(jointIndex);
|
||
if (node) {
|
||
newSkin->joints.push_back(nodeFromIndex(jointIndex));
|
||
}
|
||
}
|
||
|
||
// Get inverse bind matrices from buffer
|
||
if (source.inverseBindMatrices > -1) {
|
||
const tinygltf::Accessor& accessor = gltfModel.accessors[source.inverseBindMatrices];
|
||
const tinygltf::BufferView& bufferView = gltfModel.bufferViews[accessor.bufferView];
|
||
const tinygltf::Buffer& buffer = gltfModel.buffers[bufferView.buffer];
|
||
newSkin->inverseBindMatrices.resize(accessor.count);
|
||
memcpy(newSkin->inverseBindMatrices.data(), &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(glm::mat4));
|
||
}
|
||
|
||
skins.push_back(newSkin);
|
||
}
|
||
}
|
||
|
||
void ModelLoader::_gltf_load_animation(tinygltf::Model& gltfModel)
|
||
{
|
||
for (tinygltf::Animation& anim : gltfModel.animations) {
|
||
vkglTF::Animation animation{};
|
||
animation.name = anim.name;
|
||
if (anim.name.empty()) {
|
||
animation.name = std::to_string(animations.size());
|
||
}
|
||
|
||
// Samplers
|
||
for (auto& samp : anim.samplers) {
|
||
vkglTF::AnimationSampler sampler{};
|
||
|
||
if (samp.interpolation == "LINEAR") {
|
||
sampler.interpolation = AnimationSampler::InterpolationType::LINEAR;
|
||
}
|
||
if (samp.interpolation == "STEP") {
|
||
sampler.interpolation = AnimationSampler::InterpolationType::STEP;
|
||
}
|
||
if (samp.interpolation == "CUBICSPLINE") {
|
||
sampler.interpolation = AnimationSampler::InterpolationType::CUBICSPLINE;
|
||
}
|
||
|
||
// Read sampler input time values
|
||
{
|
||
const tinygltf::Accessor& accessor = gltfModel.accessors[samp.input];
|
||
const tinygltf::BufferView& bufferView = gltfModel.bufferViews[accessor.bufferView];
|
||
const tinygltf::Buffer& buffer = gltfModel.buffers[bufferView.buffer];
|
||
|
||
assert(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
|
||
|
||
const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
|
||
const float* buf = static_cast<const float*>(dataPtr);
|
||
for (size_t index = 0; index < accessor.count; index++) {
|
||
sampler.inputs.push_back(buf[index]);
|
||
}
|
||
|
||
for (auto input : sampler.inputs) {
|
||
if (input < animation.start) {
|
||
animation.start = input;
|
||
};
|
||
if (input > animation.end) {
|
||
animation.end = input;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Read sampler output T/R/S values
|
||
{
|
||
const tinygltf::Accessor& accessor = gltfModel.accessors[samp.output];
|
||
const tinygltf::BufferView& bufferView = gltfModel.bufferViews[accessor.bufferView];
|
||
const tinygltf::Buffer& buffer = gltfModel.buffers[bufferView.buffer];
|
||
|
||
assert(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
|
||
|
||
const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
|
||
|
||
switch (accessor.type) {
|
||
case TINYGLTF_TYPE_VEC3: {
|
||
const glm::vec3* buf = static_cast<const glm::vec3*>(dataPtr);
|
||
for (size_t index = 0; index < accessor.count; index++) {
|
||
sampler.outputsVec4.push_back(glm::vec4(buf[index], 0.0f));
|
||
sampler.outputs.push_back(buf[index][0]);
|
||
sampler.outputs.push_back(buf[index][1]);
|
||
sampler.outputs.push_back(buf[index][2]);
|
||
}
|
||
break;
|
||
}
|
||
case TINYGLTF_TYPE_VEC4: {
|
||
const glm::vec4* buf = static_cast<const glm::vec4*>(dataPtr);
|
||
for (size_t index = 0; index < accessor.count; index++) {
|
||
sampler.outputsVec4.push_back(buf[index]);
|
||
sampler.outputs.push_back(buf[index][0]);
|
||
sampler.outputs.push_back(buf[index][1]);
|
||
sampler.outputs.push_back(buf[index][2]);
|
||
sampler.outputs.push_back(buf[index][3]);
|
||
}
|
||
break;
|
||
}
|
||
default: {
|
||
std::cout << "unknown type" << std::endl;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
animation.samplers.push_back(sampler);
|
||
}
|
||
|
||
// Channels
|
||
for (auto& source : anim.channels) {
|
||
vkglTF::AnimationChannel channel{};
|
||
|
||
if (source.target_path == "rotation") {
|
||
channel.path = AnimationChannel::PathType::ROTATION;
|
||
}
|
||
if (source.target_path == "translation") {
|
||
channel.path = AnimationChannel::PathType::TRANSLATION;
|
||
}
|
||
if (source.target_path == "scale") {
|
||
channel.path = AnimationChannel::PathType::SCALE;
|
||
}
|
||
if (source.target_path == "weights") {
|
||
std::cout << "weights not yet supported, skipping channel" << std::endl;
|
||
continue;
|
||
}
|
||
channel.samplerIndex = source.sampler;
|
||
channel.node = nodeFromIndex(source.target_node);
|
||
if (!channel.node) {
|
||
continue;
|
||
}
|
||
|
||
animation.channels.push_back(channel);
|
||
}
|
||
|
||
animations.push_back(animation);
|
||
}
|
||
}
|
||
|
||
} |