Files
dl_old/dl/render/dl_model_loader.cpp
T
2024-08-31 11:25:02 +08:00

707 lines
25 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"
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);
}
}
}