Files
dl_old/dl/render/dl_model_loader.cpp
T
2026-03-10 11:39:00 +08:00

990 lines
33 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "dl_model_loader.h"
#ifndef DL_DISABLE_RENDER
#define TINYOBJLOADER_IMPLEMENTATION
#include <tiny_obj_loader.h>
#define TINYGLTF_IMPLEMENTATION
#include <tiny_gltf.h>
namespace dl
{
ModelLoader* g_modelLoader;
std::vector<ModelObject*> ModelLoader::_load_obj(std::string_view path_name)
{
std::string str_path = std::string{ path_name };
std::string str_base = String::EraseFilename(path_name);
const char* filename = str_path.c_str();
const char* basepath = str_base.c_str();
bool triangulate = true;
log_info("开始加载obj文件:{},{}", filename, basepath);
tinyobj::attrib_t attrib; // 所有的数据放在这里
std::vector<tinyobj::shape_t> shapes;// 子模型
std::vector<tinyobj::material_t> materials;
std::string warn;
std::string err;
bool b_read = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename,
basepath, triangulate);
// 打印错误
if (!warn.empty())
log_warn("{}", warn);
if (!err.empty())
log_warn("{}", err);
if (!b_read)
{
log_err("读取obj文件失败:{}", path_name);
return {};
}
log_info("顶点数:{}", attrib.vertices.size() / 3);
log_info("法线数:{}", attrib.normals.size() / 3);
log_info("UV数:{}", attrib.texcoords.size() / 2);
log_info("子模型数:{}", shapes.size());
log_info("材质数:{}", materials.size());
// 读取配置
bool is_axis_up_z = false;
{
Json::DisableLog l;
json j = Json::Parse(String::ReplaceExtension(path_name, "json"));
if (!j.is_null())
{
std::string str;
if (Json::Get(j, "axis_up", str))
{
if (str == "z")
is_axis_up_z = true;
}
}
}
// obj只有一个ModelObject
std::vector<ModelObject*> ret;
ModelObject* model_object = new ModelObject;
std::vector<Vertex>& mo_vertices = model_object->_allVertex;
std::vector<uint32_t>& mo_indices = model_object->_allIndex;
std::vector<ModelObjectMaterial>& mo_material = model_object->_allMaterial;
ret.push_back(model_object);
//------------------获取材质-------------------
mo_material.resize(materials.size());
for (size_t i = 0; i < materials.size(); ++i)
{
tinyobj::material_t m = materials[i];
log_info("材质:{},{}", i, m.name);
ModelObjectMaterial& material = mo_material[i];
material._materialName = m.name;
material._material._diffuseAlbedo = { m.diffuse[0], m.diffuse[1], m.diffuse[2], 1.0f };
material._material._fresnelR0 = { m.specular[0], m.specular[1], m.specular[2] };
material._material._roughness = ShininessToRoughness(m.shininess);
if (!m.diffuse_texname.empty())
material._pathTexDiffuse = str_base + m.diffuse_texname;
if (!m.normal_texname.empty())// 注意这里凹凸贴图(bump_texname)更常见
material._pathTexNormal = str_base + m.normal_texname;
}
//------------------获取模型-------------------
// 按 材质 放入面的顶点
std::vector<std::vector<tinyobj::index_t>> all_sub;
all_sub.resize(1 + materials.size());// 0为默认
for (size_t i = 0; i < shapes.size(); i++)
{// 每一个子shape
tinyobj::shape_t& shape = shapes[i];
size_t num_index = shape.mesh.indices.size();
size_t num_face = shape.mesh.num_face_vertices.size();
log_info("读取子模型:{},{}", i, shape.name);
log_info("索引数:{};面数:{}", num_index, num_face);
//当前mesh下标(每个面递增3)
size_t index_offset = 0;
//每一个面
for (size_t j = 0; j < num_face; ++j)
{
int index_mat = shape.mesh.material_ids[j];//每个面的材质
std::vector<tinyobj::index_t>& sub_idx = all_sub[1 + index_mat];
sub_idx.push_back(shape.mesh.indices[index_offset + 0]);
if (!is_axis_up_z)
{
sub_idx.push_back(shape.mesh.indices[index_offset + 1]);
sub_idx.push_back(shape.mesh.indices[index_offset + 2]);
}
else
{
sub_idx.push_back(shape.mesh.indices[index_offset + 2]);
sub_idx.push_back(shape.mesh.indices[index_offset + 1]);
}
index_offset += 3;
}
}
//生成子模型,并填入顶点
std::unordered_map<tinyobj::index_t, size_t, hash_idx, equal_idx>
uniqueVertices;//避免重复插入顶点
size_t i = 0;
size_t j = 0;
for (std::vector<tinyobj::index_t>& sub_idx : all_sub)
{
ModelObjectSub sub;
sub._range._offsetIndex = i;
sub._range._countTriangle = sub_idx.size() / 3;
sub._indexMaterial = j - 1;
++j;
model_object->_allSub.push_back(sub);
for (tinyobj::index_t& idx : sub_idx)
{
auto iter = uniqueVertices.find(idx);
if (iter == uniqueVertices.end())
{
Vertex v;
//v
v._pos[0] = attrib.vertices[idx.vertex_index * 3 + 0];
if (!is_axis_up_z)
{
v._pos[1] = attrib.vertices[idx.vertex_index * 3 + 1];
v._pos[2] = attrib.vertices[idx.vertex_index * 3 + 2];
}
else
{
v._pos[1] = attrib.vertices[idx.vertex_index * 3 + 2];
v._pos[2] = attrib.vertices[idx.vertex_index * 3 + 1];
}
// vt
v._uv[0] = attrib.texcoords[idx.texcoord_index * 2 + 0];
v._uv[1] = attrib.texcoords[idx.texcoord_index * 2 + 1];
v._uv[1] = 1.0f - v._uv[1];
uniqueVertices[idx] = mo_vertices.size();
mo_indices.push_back((uint32_t)mo_vertices.size());
mo_vertices.push_back(v);
}
else
{
mo_indices.push_back((uint32_t)iter->second);
}
++i;
}
}
log_msg("解析obj模型完成:v_{},i_{}", mo_vertices.size(), mo_indices.size());
return ret;
}
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(model, res_name, mo_material);
_gltf_load_scene(model, model_object->_modelData);
//子网格合并
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(const tinygltf::Model& model,
std::string_view res_name,
std::vector<ModelObjectMaterial>& mo_material)
{
mo_material.resize(model.materials.size());
for (size_t i = 0; i < model.materials.size(); ++i)
{
const tinygltf::Material& m = model.materials[i];
log_info("材质:{},{}", i, m.name);
const 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{};
const 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 VertexBone[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, data);
}
// 读取蒙皮
_gltf_load_skin(model, data);
for (ModelNode* model_node : data->_allNode)
{
// Assign skins
if (model_node->skinIndex > -1)
{
model_node->_skin = data->_allSkin[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;
for (size_t i = 0; i < nn.children.size(); ++i)
{
_gltf_load_node(model, nn.children[i], model_node_parent, loader_info, data);
}
// 读取mesh
if (nn.mesh > -1)
{
const tinygltf::Mesh& mesh = model.meshes[nn.mesh];
ModelMesh* model_mesh = new ModelMesh;
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 = _vec3_cast(accessor_pos.minValues);
pos_max = _vec3_cast(accessor_pos.maxValues);
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; i < accessor_pos.count; ++i)
{
VertexBone& v = loader_info._vertexBuffer[loader_info._vertexPos];
v._pos = _vec3_cast(&buffer_pos[i * stride_pos]);
if (!buffer_normal)
v._normal = {};
else
v._normal = _vec3_cast(&buffer_normal[i * stride_normal]);
if (!buffer_uv0)
v._uv0 = {};
else
v._uv0 = _vec2_cast(&buffer_uv0[i * stride_uv0]);
if (!buffer_uv1)
v._uv1 = {};
else
v._uv1 = _vec2_cast(&buffer_uv1[i * stride_uv1]);
if (!buffer_color)
v._color = { 1, 1, 1, 1 };
else
v._color = _vec4_cast(&buffer_color[i * 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 j = 0; j < NUM_BONE; ++j)
v._joint0[j] = buf[i * stride_joint + j];
break;
}
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
{
const uint8_t* buf = static_cast<const uint8_t*>(buffer_joint);
for (size_t j = 0; j < NUM_BONE; ++j)
v._joint0[j] = (uint16_t)buf[i * stride_joint + j];
break;
}
default:
assert(0);
break;
}
}
if (!has_skin)
v._weight0 = {};
else
v._weight0 = *(Position4*)(&buffer_weight[i * 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 ModelPrimitive;
model_primitive->firstIndex = index_start;
model_primitive->indexCount = index_count;
model_primitive->vertexCount = vertex_count;
model_primitive->material = primitive.material;// > -1 ?
//materials[primitive.material] : materials.back();
model_primitive->hasIndices = index_count > 0;
model_primitive->bb.min = pos_min;
model_primitive->bb.max = pos_max;
model_primitive->bb.valid = true;
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 = Each::Min(model_mesh->bb.min, p->bb.min);
model_mesh->bb.max = Each::Max(model_mesh->bb.max, p->bb.max);
}
model_node->_mesh = model_mesh;
}
if (model_node_parent) {
model_node_parent->_allChild.push_back(model_node);
}
else {
data->_allNodeChild.push_back(model_node);
}
data->_allNode.push_back(model_node);
}
void ModelLoader::_gltf_load_skin(const tinygltf::Model& gltfModel, ModelData* data)
{
for (const tinygltf::Skin& source : gltfModel.skins) {
ModelSkin* newSkin = new ModelSkin;
newSkin->name = source.name;
// Find skeleton root node
if (source.skeleton > -1) {
newSkin->skeletonRoot = nodeFromIndex(data, source.skeleton);
}
// Find joint nodes
for (int jointIndex : source.joints) {
ModelNode* node = nodeFromIndex(data, jointIndex);
if (node) {
newSkin->_allJoint.push_back(nodeFromIndex(data, 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->_allOffsetMatrix.resize(accessor.count);
memcpy(newSkin->_allOffsetMatrix.data(), &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(Matrix4));
}
data->_allSkin.push_back(newSkin);
}
}
void ModelLoader::_gltf_load_animation(const tinygltf::Model& model, ModelData* data)
{
for (const tinygltf::Animation& anim : model.animations)
{
ModelAnimation animation{};
animation._name = anim.name;
if (anim.name.empty()) {
animation._name = std::to_string(data->_allAnimation.size());
}
// Samplers
for (auto& samp : anim.samplers) {
ModelAnimationSampler sampler{};
if (samp.interpolation == "LINEAR") {
sampler.interpolation = ModelAnimationSampler::InterpolationType::LINEAR;
}
if (samp.interpolation == "STEP") {
sampler.interpolation = ModelAnimationSampler::InterpolationType::STEP;
}
if (samp.interpolation == "CUBICSPLINE") {
sampler.interpolation = ModelAnimationSampler::InterpolationType::CUBICSPLINE;
}
// Read sampler input time values
{
const tinygltf::Accessor& accessor = model.accessors[samp.input];
const tinygltf::BufferView& bufferView = model.bufferViews[accessor.bufferView];
const tinygltf::Buffer& buffer = model.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 = model.accessors[samp.output];
const tinygltf::BufferView& bufferView = model.bufferViews[accessor.bufferView];
const tinygltf::Buffer& buffer = model.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 Position3* buf = (Position3*)dataPtr;
for (size_t index = 0; index < accessor.count; index++) {
sampler.outputsVec4.push_back(toLonger(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 Position4* buf = (Position4*)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._allSampler.push_back(sampler);
}
// Channels
for (auto& source : anim.channels) {
ModelAnimationChannel channel{};
if (source.target_path == "rotation") {
channel.path = ModelAnimationChannel::PathType::ROTATION;
}
if (source.target_path == "translation") {
channel.path = ModelAnimationChannel::PathType::TRANSLATION;
}
if (source.target_path == "scale") {
channel.path = ModelAnimationChannel::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(data, source.target_node);
if (!channel.node) {
continue;
}
animation._allChannel.push_back(channel);
}
data->_allAnimation.push_back(animation);
}
}
dl::ModelNode* ModelLoader::findNode(ModelData* data, ModelNode* parent, uint32_t index)
{
ModelNode* nodeFound = nullptr;
if (parent->_index == index) {
return parent;
}
for (auto& child : parent->_allChild) {
nodeFound = findNode(data, child, index);
if (nodeFound) {
break;
}
}
return nodeFound;
}
dl::ModelNode* ModelLoader::nodeFromIndex(ModelData* data, uint32_t index)
{
ModelNode* nodeFound = nullptr;
for (auto& node : data->_allNode) {
nodeFound = findNode(data, node, index);
if (nodeFound) {
break;
}
}
return nodeFound;
}
dl::Position3 ModelLoader::_vec3_cast(const std::vector<double>& vec3)
{
if (vec3.size() != 3)
{
assert(0);
return {};
}
Position3 ret;
for (size_t i = 0; i < 3; ++i)
{
ret[i] = (Float)vec3[i];
}
return ret;
}
dl::Position4 ModelLoader::_vec4_cast(const std::vector<double>& vec4)
{
if (vec4.size() != 4)
{
assert(0);
return {};
}
Position4 ret;
for (size_t i = 0; i < 4; ++i)
{
ret[i] = (Float)vec4[i];
}
return ret;
}
dl::Position2 ModelLoader::_vec2_cast(const float* p)
{
return { p[0], p[1] };
}
dl::Position3 ModelLoader::_vec3_cast(const float* p)
{
return { p[0], p[1], p[2] };
}
dl::Position4 ModelLoader::_vec4_cast(const float* p)
{
return { p[0], p[1], p[2], p[3] };
}
dl::Matrix4 ModelLoader::_mat4_cast(const std::vector<double>& matrix)
{
if (matrix.size() != 16)
{
assert(0);
return Mat::CreateIdentity();
}
Matrix4 ret;
for (size_t i = 0; i < 16; ++i)
{
ret.At(i) = (Float)matrix[i];
}
return ret;
}
dl::Matrix4 ModelLoader::_mat4_cast(float* p)
{
Matrix4 ret;
for (size_t i = 0; i < 16; ++i)
{
ret.At(i) = (Float)p[i];
}
return ret;
}
}
#endif