#include "dl_model_loader.h" #ifndef DL_DISABLE_RENDER #define TINYOBJLOADER_IMPLEMENTATION #include #include #define TINYGLTF3_IMPLEMENTATION //#define TINYGLTF3_ENABLE_FS // enable file I/O //#define TINYGLTF3_ENABLE_STB_IMAGE // enable image decoding #include #include "math/dl_transform.h" namespace dl { ModelLoader* g_modelLoader; std::vector 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 shapes;// 子模型 std::vector 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::ParseFile(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 ret; ModelObject* model_object = new ModelObject; std::vector& mo_vertices = model_object->_allVertex; std::vector& mo_indices = model_object->_allIndex; std::vector& 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); ModelMaterial& material = mo_material[i]; material._materialName = m.name; material._material._baseColorFactor = { m.diffuse[0], m.diffuse[1], m.diffuse[2], 1.0f }; // todo //material._material._metallic = m.metallic; //material._material._roughness = m.roughness; 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> 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& 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 uniqueVertices;//避免重复插入顶点 size_t i = 0; size_t j = 0; ModelNodeRt node; for (std::vector& sub_idx : all_sub) { ModelDrawCall sub; sub._range._offsetIndex = i; sub._range._countTriangle = sub_idx.size() / 3; sub._indexMaterial = j - 1; ++j; // todo node._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._uv0[0] = attrib.texcoords[idx.texcoord_index * 2 + 0]; v._uv0[1] = attrib.texcoords[idx.texcoord_index * 2 + 1]; v._uv0[1] = 1.0f - v._uv0[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; } } model_object->_treeNode.push_back(node); log_msg("解析obj模型完成:v_{},i_{}", mo_vertices.size(), mo_indices.size()); return ret; } ModelObject* ModelLoader::_create_model_object(ModelData& data) { ModelObject* obj = new ModelObject; obj->_allMaterial = data._allMaterial; obj->_allAnimation = data._allAnimation; obj->_allSkin = data._allSkin; obj->_treeNodeParent.resize(data._allNode.GetSize()); obj->_allSub = data._allSub; obj->_allIndex = data._allIndex; if (obj->_allSkin.empty()) obj->_allVertex = data._allVertex; else obj->_allVertexBone = data._allVertexSkin; // index -> vector_index std::unordered_map map_index; data._allNode.ForEach([&](ModelNode* node) { ModelNodeRt node_rt; node_rt._index = node->_index; node_rt._indexSkin = node->_indexSkin; node_rt._trans2Parent = node->_trans2Parent; node_rt._aabb = node->_mesh._aabb; // parent_id 重映射 if (!node->_parent) node_rt._indexParent = -1; else { auto iter = map_index.find(node->_parent->_index); if (iter == map_index.end()) node_rt._indexParent = -1; else node_rt._indexParent = iter->second; } map_index[node_rt._index] = (int)obj->_treeNode.size(); obj->_treeNode.push_back(node_rt); }); return obj; } std::vector 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()); ModelData model_data; _gltf_load_material(model, res_name, model_data._allMaterial); _gltf_load_scene(model, model_data); ModelObject* obj = _create_model_object(model_data); std::vector ret; ret.push_back(obj); return ret; } Position4 _factor_cast(const std::vector& vec) { return { (float)vec[0], (float)vec[1], (float)vec[2], 1.0f }; } void ModelLoader::_gltf_load_material(const tinygltf::Model& model, std::string_view res_name, std::vector& vec_material) { vec_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; ModelMaterial& material = vec_material[i]; material._materialName = m.name; material._material._baseColorFactor = _factor_cast(pbr.baseColorFactor); material._material._emissiveFactor = _factor_cast(m.emissiveFactor); // 纹理导出 // 存在复用的情况 std::unordered_map map_path; auto fn_texture = [&](int index, std::string_view tag) { if (index == -1) return std::string{}; auto iter = map_path.find(index); if (iter != map_path.end()) return iter->second; 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); #if DL_PLATFORM == DL_PLATFORM_WIN32 path_name = CodeCvt::Utf8ToMultiByte(path_name); #endif stbi_write_png(path_name.c_str(), img.width, img.height, 4, img.image.data(), 0); map_path[index] = path_name; return path_name; }; material._pathTexDiffuse = fn_texture(pbr.baseColorTexture.index, ""); material._pathTexPhysical = fn_texture(pbr.metallicRoughnessTexture.index, "_physical"); material._pathTexNormal = fn_texture(m.normalTexture.index, "_normal"); material._pathTexAo = fn_texture(m.occlusionTexture.index, "_ao"); material._pathTexEmissvie = fn_texture(m.emissiveTexture.index, "_emissvie"); material._material._baseColorTextureSet = material._pathTexDiffuse.empty() ? -1 : pbr.baseColorTexture.texCoord; material._material._physicalDescriptorTextureSet = material._pathTexPhysical.empty() ? -1 : pbr.metallicRoughnessTexture.texCoord; material._material._normalTextureSet = material._pathTexNormal.empty() ? -1 : m.normalTexture.texCoord; material._material._occlusionTextureSet = material._pathTexAo.empty() ? -1 : m.occlusionTexture.texCoord; material._material._emissiveTextureSet = material._pathTexEmissvie.empty() ? -1 : m.emissiveTexture.texCoord; material._material._metallicFactor = (float)pbr.metallicFactor; material._material._roughnessFactor = (float)pbr.roughnessFactor; material._material._alphaMask = m.alphaMode == "MASK" ? 1.0f : 0.0f; { auto iter = m.additionalValues.find("alphaCutoff"); if (iter != m.additionalValues.end()) material._material._alphaMaskCutoff = (float)iter->second.Factor(); } material._material._metallicFactor = (float)pbr.metallicFactor; { auto iter = m.additionalValues.find("alphaCutoff"); if (iter != m.additionalValues.end()) material._material._alphaMaskCutoff = (float)iter->second.Factor(); } material._material._emissiveStrength = 1.0f; { auto iter = m.extensions.find("KHR_materials_emissive_strength"); if (iter != m.extensions.end()) { if (iter->second.Has("emissiveStrength")) { auto value = iter->second.Get("emissiveStrength"); material._material._emissiveStrength = (float)value.Get(); } } } memset(material._material._pad, 0, sizeof(material._material._pad)); } } 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) { assert(model.scenes.size() == 1); // 只读一个场景 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); } // data._allIndex.resize(index_count); if (model.skins.empty()) data._allVertex.resize(index_count); else data._allVertexSkin.resize(index_count); // 创建根 ModelNode* node_root = new ModelNode; node_root->_index = 0; node_root->_trans2Parent._mat = Mat::CreateRotation(AXIS_Z, (float)Math::PI(1, 2)) * Mat::CreateRotation(AXIS_X, (float)Math::PI(1, 2)); data._allNode.AddRoot(node_root); // 读取节点 for (size_t i = 0; i < scene.nodes.size(); i++) { _gltf_load_node(model, scene.nodes[i], node_root, data); } // 读取动画 if (model.animations.size() > 0) { _gltf_load_animation(model, data); } // 读取蒙皮 _gltf_load_skin(model, data); // 若是静态模型,则转为世界坐标系 if (data._allSkin.empty()) { for (auto& iter : data._allNode) { ModelNode* node = iter->GetValue(); Matrix4 mat_world = _get_node_mat_world(node); Matrix4 mat_n = Mat::GetInverse(mat_world); mat_n.Transpose(); Matrix3 mat_t = Mat::ToMatrix3(mat_world); for (auto& pri : node->_mesh._primitives) { // 是否多个pri会引用同一个顶点,有待验证 for (size_t i = pri._vertexIndex; i < pri._vertexIndex + pri._vertexCount; ++i) { Vertex& v = data._allVertex[i]; v._pos = Mat::ApplyDot(mat_world, v._pos); v._normal = Mat::ApplyDir(mat_n, v._normal); v._tangent = mat_t * v._tangent; Math::Normalize(v._normal); Math::Normalize(v._tangent); } } } } // pri -> all_sub for (auto& iter : data._allNode) { for (ModelPrimitive& pri : iter->GetValue()->_mesh._primitives) { ModelDrawCall sub; sub._indexMaterial = pri._indexMaterial; sub._range._offsetIndex = pri._indexBeg; sub._range._countTriangle = pri._indexCount / 3; data._allSub.push_back(sub); } } // 子网格合并 if (true) { // 排序 std::map map_pri; for (ModelDrawCall& iter : data._allSub) { map_pri[iter._range._offsetIndex] = &iter; } // 合并网格连续,且材质相同的项 std::vector vec_sub; ModelDrawCall* pre = nullptr; // for (auto& iter : map_pri) { ModelDrawCall* sub = iter.second; 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("子网格合并:{}->{}", map_pri.size(), vec_sub.size()); for (ModelDrawCall& sub : vec_sub) { log_info("合并后网格,起始:{},三角数:{},材质:{}", sub._range._offsetIndex, sub._range._countTriangle, sub._indexMaterial); } std::swap(data._allSub, vec_sub); int pause = 3; } } void ModelLoader::_gltf_load_node(const tinygltf::Model& model, int node, ModelNode* model_node_parent, ModelData& data) { const tinygltf::Node& nn = model.nodes[node]; ModelNode* model_node = new ModelNode; model_node->_parent = model_node_parent; model_node->_index = node + 1; model_node->_indexSkin = nn.skin; // if (nn.translation.size() == 3) { model_node->_trans2Parent._t = _vec3_cast(nn.translation); } if (nn.rotation.size() == 4) { model_node->_trans2Parent._r = _quat_cast(nn.rotation); } if (nn.scale.size() == 3) { model_node->_trans2Parent._s = _vec3_cast(nn.scale); } if (nn.matrix.size() == 16) { model_node->_trans2Parent._mat = _mat4_cast(nn.matrix); } // gltf R(up:+y forward:+z) // dl R(up:+z forward:+x) // 构建树 data._allNode.Add(model_node, model_node_parent); // 子节点加载 for (size_t i = 0; i < nn.children.size(); ++i) { _gltf_load_node(model, nn.children[i], model_node, data); } // 读取mesh if (nn.mesh > -1) { const tinygltf::Mesh& mesh = model.meshes[nn.mesh]; ModelMesh model_mesh; for (size_t j = 0; j < mesh.primitives.size(); j++) { const tinygltf::Primitive& primitive = mesh.primitives[j]; uint32_t vertex_start = (uint32_t)data._vertexPos; uint32_t index_start = (uint32_t)data._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(&(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(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(&(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(&(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(&(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(&(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(&(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) { if (has_skin) { VertexBone& v = data._allVertexSkin[data._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]); switch (joint_comp_type) { case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: { const uint16_t* buf = static_cast(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(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; } v._weight0 = *(Position4*)(&buffer_weight[i * stride_weight]); if (Every::Zero(v._weight0)) { v._weight0[0] = 1.0_f; } } else { Vertex& v = data._allVertex[data._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]); } ++data._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(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(data_ptr); for (size_t index = 0; index < accessor.count; index++) { data._allIndex[data._indexPos] = buf[index] + vertex_start; ++data._indexPos; } break; } case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: { const uint16_t* buf = static_cast(data_ptr); for (size_t index = 0; index < accessor.count; index++) { data._allIndex[data._indexPos] = buf[index] + vertex_start; ++data._indexPos; } break; } case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: { const uint8_t* buf = static_cast(data_ptr); for (size_t index = 0; index < accessor.count; index++) { data._allIndex[data._indexPos] = buf[index] + vertex_start; ++data._indexPos; } break; } default: assert(0); return; } } ModelPrimitive model_primitive; model_primitive._indexBeg = index_start; model_primitive._indexCount = index_count; model_primitive._vertexIndex = vertex_start; model_primitive._vertexCount = vertex_count; model_primitive._indexMaterial = primitive.material; model_primitive._bHasIndices = index_count > 0; model_primitive._aabb = BoundingBox(pos_min, pos_max); model_mesh._primitives.push_back(model_primitive); } // Mesh BB from BBs of primitives for (ModelPrimitive& p : model_mesh._primitives) { model_mesh._aabb.Add(p._aabb); } model_node->_mesh = model_mesh; } } void ModelLoader::_gltf_load_skin(const tinygltf::Model& gltfModel, ModelData& data) { for (const tinygltf::Skin& source : gltfModel.skins) { ModelSkin skin; skin.name = source.name; // Find skeleton root node if (source.skeleton > -1) { skin.skeletonRoot = source.skeleton + 1; } // Find joint nodes for (int jointIndex : source.joints) { ModelNode* node = _find_node(data, jointIndex + 1); if (node) { skin._allJoint.push_back(jointIndex + 1); } } // 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]; skin._allOffsetMatrix.resize(accessor.count); memcpy(skin._allOffsetMatrix.data(), &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(Matrix4)); } data._allSkin.push_back(skin); } } 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(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.indexNode = source.target_node + 1; auto node = _find_node(data, source.target_node + 1); if (!node) { continue; } animation._allChannel.push_back(channel); } // 四元数顺序修正(gltf 为 xyzw) for (const ModelAnimationChannel& channel : animation._allChannel) { ModelAnimationSampler& sampler = animation._allSampler[channel.samplerIndex]; if (channel.path == ModelAnimationChannel::ROTATION) { for (auto& iter : sampler.outputsVec4) { std::swap(iter.x, iter.w); std::swap(iter.y, iter.w); std::swap(iter.z, iter.w); } } } data._allAnimation.push_back(animation); } } dl::ModelNode* ModelLoader::_find_node(ModelData& data, uint32_t index) { for (auto& iter : data._allNode) { if (iter->GetValue()->_index == index) return iter->GetValue(); } return nullptr; } dl::Matrix4 ModelLoader::_get_node_mat_world(const ModelNode* node) { Matrix4 mat = node->_trans2Parent.GetMatrix(); ModelNode* parent = node->_parent; while (parent) { mat = parent->_trans2Parent.GetMatrix() * mat; parent = parent->_parent; } return mat; } dl::Position3 ModelLoader::_vec3_cast(const std::vector& 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& 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::Position4 ModelLoader::_quat_cast(const std::vector& vec4) { if (vec4.size() != 4) { assert(0); return {}; } Position4 ret; ret[0] = (float)vec4[3]; ret[1] = (float)vec4[0]; ret[2] = (float)vec4[1]; ret[3] = (float)vec4[2]; 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& 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