Parse skins & animations in gltf parser
This commit is contained in:
parent
3bb0b53daf
commit
d930ef6d93
3 changed files with 185 additions and 55 deletions
|
|
@ -4,6 +4,7 @@
|
|||
#include <psemek/gfx/color.hpp>
|
||||
#include <psemek/geom/vector.hpp>
|
||||
#include <psemek/geom/quaternion.hpp>
|
||||
#include <psemek/geom/easing.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
|
@ -19,9 +20,11 @@ namespace psemek::gfx
|
|||
struct node
|
||||
{
|
||||
std::string name;
|
||||
std::optional<std::size_t> parent;
|
||||
std::optional<std::size_t> mesh;
|
||||
std::optional<std::size_t> light; // KHR_lights_punctual
|
||||
std::optional<std::size_t> skin;
|
||||
std::vector<std::size_t> children;
|
||||
std::optional<std::size_t> light; // KHR_lights_punctual
|
||||
|
||||
geom::vector<float, 3> translation;
|
||||
geom::quaternion<float> rotation;
|
||||
|
|
@ -57,12 +60,56 @@ namespace psemek::gfx
|
|||
std::string uri;
|
||||
};
|
||||
|
||||
struct skin
|
||||
{
|
||||
std::vector<std::size_t> joints;
|
||||
std::optional<std::size_t> inverse_bind_matrices; // accessor
|
||||
};
|
||||
|
||||
struct animation
|
||||
{
|
||||
struct channel
|
||||
{
|
||||
std::size_t sampler;
|
||||
std::size_t target; // node
|
||||
|
||||
enum path_t
|
||||
{
|
||||
scale,
|
||||
rotation,
|
||||
translation,
|
||||
} path;
|
||||
};
|
||||
|
||||
struct sampler
|
||||
{
|
||||
std::size_t input; // keyframes accessor
|
||||
std::size_t output; // values accessor
|
||||
geom::easing_type interpolation;
|
||||
};
|
||||
|
||||
std::string name;
|
||||
std::vector<channel> channels;
|
||||
std::vector<sampler> samplers;
|
||||
};
|
||||
|
||||
struct accessor
|
||||
{
|
||||
std::size_t buffer_view;
|
||||
std::size_t component_type;
|
||||
std::size_t count;
|
||||
std::size_t type;
|
||||
|
||||
enum type_t
|
||||
{
|
||||
scalar,
|
||||
vec2,
|
||||
vec3,
|
||||
vec4,
|
||||
mat2,
|
||||
mat3,
|
||||
mat4,
|
||||
} type;
|
||||
|
||||
bool normalized;
|
||||
};
|
||||
|
||||
|
|
@ -83,7 +130,7 @@ namespace psemek::gfx
|
|||
// KHR_lights_punctual
|
||||
struct light
|
||||
{
|
||||
enum
|
||||
enum type_t
|
||||
{
|
||||
directional,
|
||||
point,
|
||||
|
|
@ -100,6 +147,8 @@ namespace psemek::gfx
|
|||
std::vector<mesh> meshes;
|
||||
std::vector<material> materials;
|
||||
std::vector<texture> textures;
|
||||
std::vector<skin> skins;
|
||||
std::vector<animation> animations;
|
||||
std::vector<accessor> accessors;
|
||||
std::vector<buffer_view> buffer_views;
|
||||
std::vector<buffer> buffers;
|
||||
|
|
@ -111,4 +160,6 @@ namespace psemek::gfx
|
|||
|
||||
gltf_asset parse_gltf(io::istream && stream);
|
||||
|
||||
std::size_t attribute_size(gltf_asset::accessor::type_t type);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ namespace psemek::gfx
|
|||
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, buffers_[view.buffer].id());
|
||||
gl::EnableVertexAttribArray(attribute.first);
|
||||
gl::VertexAttribPointer(attribute.first, accessor.type, accessor.component_type, accessor.normalized, 0, reinterpret_cast<void const *>(view.offset));
|
||||
gl::VertexAttribPointer(attribute.first, attribute_size(accessor.type), accessor.component_type, accessor.normalized, 0, reinterpret_cast<void const *>(view.offset));
|
||||
}
|
||||
|
||||
target_mesh.push_back({&drawable, primitive.material});
|
||||
|
|
|
|||
|
|
@ -45,16 +45,22 @@ namespace psemek::gfx
|
|||
}
|
||||
}
|
||||
|
||||
std::size_t parse_accessor_type(std::string const & type)
|
||||
auto parse_accessor_type(std::string const & type)
|
||||
{
|
||||
if (type == "SCALAR")
|
||||
return 1;
|
||||
return gltf_asset::accessor::scalar;
|
||||
if (type == "VEC2")
|
||||
return 2;
|
||||
return gltf_asset::accessor::vec2;
|
||||
if (type == "VEC3")
|
||||
return 3;
|
||||
return gltf_asset::accessor::vec3;
|
||||
if (type == "VEC4")
|
||||
return 4;
|
||||
return gltf_asset::accessor::vec4;
|
||||
if (type == "MAT2")
|
||||
return gltf_asset::accessor::mat2;
|
||||
if (type == "MAT3")
|
||||
return gltf_asset::accessor::mat3;
|
||||
if (type == "MAT4")
|
||||
return gltf_asset::accessor::mat4;
|
||||
throw std::runtime_error(util::to_string("Unknown accessor component type: ", type));
|
||||
}
|
||||
|
||||
|
|
@ -82,13 +88,16 @@ namespace psemek::gfx
|
|||
if (!supported_extensions.contains(extension.GetString()))
|
||||
throw std::runtime_error("glTF extension " + std::string(extension.GetString()) + " is not supported");
|
||||
|
||||
for (auto const & node : document["nodes"].GetArray())
|
||||
if (document.HasMember("nodes")) for (auto const & node : document["nodes"].GetArray())
|
||||
{
|
||||
auto & target = result.nodes.emplace_back();
|
||||
target.name = node["name"].GetString();
|
||||
if (node.HasMember("mesh"))
|
||||
target.mesh = node["mesh"].GetUint64();
|
||||
|
||||
if (node.HasMember("skin"))
|
||||
target.skin = node["skin"].GetUint64();
|
||||
|
||||
target.translation = {0.f, 0.f, 0.f};
|
||||
if (node.HasMember("translation"))
|
||||
{
|
||||
|
|
@ -129,7 +138,7 @@ namespace psemek::gfx
|
|||
}
|
||||
}
|
||||
|
||||
for (auto const & mesh : document["meshes"].GetArray())
|
||||
if (document.HasMember("meshes")) for (auto const & mesh : document["meshes"].GetArray())
|
||||
{
|
||||
auto & target = result.meshes.emplace_back();
|
||||
for (auto const & primitive : mesh["primitives"].GetArray())
|
||||
|
|
@ -149,7 +158,7 @@ namespace psemek::gfx
|
|||
}
|
||||
}
|
||||
|
||||
for (auto const & material : document["materials"].GetArray())
|
||||
if (document.HasMember("materials")) for (auto const & material : document["materials"].GetArray())
|
||||
{
|
||||
auto & target = result.materials.emplace_back();
|
||||
|
||||
|
|
@ -189,13 +198,67 @@ namespace psemek::gfx
|
|||
}
|
||||
}
|
||||
|
||||
for (auto const & image : document["images"].GetArray())
|
||||
if (document.HasMember("images")) for (auto const & image : document["images"].GetArray())
|
||||
{
|
||||
auto & target = result.textures.emplace_back();
|
||||
target.uri = image["uri"].GetString();
|
||||
}
|
||||
|
||||
for (auto const & accessor : document["accessors"].GetArray())
|
||||
if (document.HasMember("skins")) for (auto const & skin : document["skins"].GetArray())
|
||||
{
|
||||
auto & target = result.skins.emplace_back();
|
||||
|
||||
for (auto const & joint : skin["joints"].GetArray())
|
||||
target.joints.push_back(joint.GetUint64());
|
||||
|
||||
if (skin.HasMember("inverseBindMatrices"))
|
||||
target.inverse_bind_matrices = skin["inverseBindMatrices"].GetUint64();
|
||||
}
|
||||
|
||||
if (document.HasMember("animations")) for (auto const & animation : document["animations"].GetArray())
|
||||
{
|
||||
auto & target = result.animations.emplace_back();
|
||||
|
||||
if (animation.HasMember("name"))
|
||||
target.name = animation["name"].GetString();
|
||||
|
||||
for (auto const & channel : animation["channels"].GetArray())
|
||||
{
|
||||
auto & channel_target = target.channels.emplace_back();
|
||||
|
||||
channel_target.sampler = channel["sampler"].GetUint64();
|
||||
channel_target.target = channel["target"]["node"].GetUint64();
|
||||
std::string path{channel["target"]["path"].GetString()};
|
||||
if (path == "scale")
|
||||
channel_target.path = gltf_asset::animation::channel::scale;
|
||||
else if (path == "rotation")
|
||||
channel_target.path = gltf_asset::animation::channel::rotation;
|
||||
else if (path == "translation")
|
||||
channel_target.path = gltf_asset::animation::channel::translation;
|
||||
else
|
||||
throw std::runtime_error("Unknown glTF animation target path: " + path);
|
||||
}
|
||||
|
||||
for (auto const & sampler : animation["samplers"].GetArray())
|
||||
{
|
||||
auto & sampler_target = target.samplers.emplace_back();
|
||||
|
||||
sampler_target.input = sampler["input"].GetUint64();
|
||||
sampler_target.output = sampler["output"].GetUint64();
|
||||
|
||||
std::string interpolation{sampler["interpolation"].GetString()};
|
||||
if (interpolation == "STEP")
|
||||
sampler_target.interpolation = geom::easing_type::constant_left;
|
||||
else if (interpolation == "LINEAR")
|
||||
sampler_target.interpolation = geom::easing_type::linear;
|
||||
else if (interpolation == "CUBICSPLINE")
|
||||
sampler_target.interpolation = geom::easing_type::cubic;
|
||||
else
|
||||
throw std::runtime_error("Unknown glTF animation interpolation type: " + interpolation);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.HasMember("accessors")) for (auto const & accessor : document["accessors"].GetArray())
|
||||
{
|
||||
auto & target = result.accessors.emplace_back();
|
||||
|
||||
|
|
@ -210,7 +273,7 @@ namespace psemek::gfx
|
|||
target.normalized = false;
|
||||
}
|
||||
|
||||
for (auto const & buffer_view : document["bufferViews"].GetArray())
|
||||
if (document.HasMember("bufferViews")) for (auto const & buffer_view : document["bufferViews"].GetArray())
|
||||
{
|
||||
auto & target = result.buffer_views.emplace_back();
|
||||
|
||||
|
|
@ -222,7 +285,7 @@ namespace psemek::gfx
|
|||
target.stride = buffer_view["byteStride"].GetUint64();
|
||||
}
|
||||
|
||||
for (auto const & buffer : document["buffers"].GetArray())
|
||||
if (document.HasMember("buffers")) for (auto const & buffer : document["buffers"].GetArray())
|
||||
{
|
||||
auto & target = result.buffers.emplace_back();
|
||||
|
||||
|
|
@ -230,56 +293,59 @@ namespace psemek::gfx
|
|||
target.uri = buffer["uri"].GetString();
|
||||
}
|
||||
|
||||
if (document.HasMember("extensions"))
|
||||
for (auto const & extension : document["extensions"].GetObject())
|
||||
if (document.HasMember("extensions")) for (auto const & extension : document["extensions"].GetObject())
|
||||
{
|
||||
if (extension.name == "KHR_lights_punctual")
|
||||
{
|
||||
if (extension.name == "KHR_lights_punctual")
|
||||
for (auto const & light : extension.value["lights"].GetArray())
|
||||
{
|
||||
for (auto const & light : extension.value["lights"].GetArray())
|
||||
auto & target = result.lights.emplace_back();
|
||||
target.color = {1.f, 1.f, 1.f};
|
||||
target.intensity = 1.f;
|
||||
target.range = std::numeric_limits<float>::infinity();
|
||||
target.cone_angle = {0.f, geom::pi / 4.f};
|
||||
|
||||
std::string type = light["type"].GetString();
|
||||
|
||||
if (type == "directional")
|
||||
target.type = gltf_asset::light::directional;
|
||||
else if (type == "point")
|
||||
target.type = gltf_asset::light::point;
|
||||
else if (type == "spot")
|
||||
target.type = gltf_asset::light::spot;
|
||||
else
|
||||
throw std::runtime_error("unknown light type: " + type);
|
||||
|
||||
if (light.HasMember("color"))
|
||||
{
|
||||
auto & target = result.lights.emplace_back();
|
||||
target.color = {1.f, 1.f, 1.f};
|
||||
target.intensity = 1.f;
|
||||
target.range = std::numeric_limits<float>::infinity();
|
||||
target.cone_angle = {0.f, geom::pi / 4.f};
|
||||
auto const & color = light["color"].GetArray();
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
target.color[i] = color[i].GetFloat();
|
||||
}
|
||||
|
||||
std::string type = light["type"].GetString();
|
||||
if (light.HasMember("intensity"))
|
||||
target.intensity = light["intensity"].GetFloat();
|
||||
|
||||
if (type == "directional")
|
||||
target.type = gltf_asset::light::directional;
|
||||
else if (type == "point")
|
||||
target.type = gltf_asset::light::point;
|
||||
else if (type == "spot")
|
||||
target.type = gltf_asset::light::spot;
|
||||
else
|
||||
throw std::runtime_error("unknown light type: " + type);
|
||||
if (light.HasMember("range"))
|
||||
target.range = light["range"].GetFloat();
|
||||
|
||||
if (light.HasMember("color"))
|
||||
{
|
||||
auto const & color = light["color"].GetArray();
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
target.color[i] = color[i].GetFloat();
|
||||
}
|
||||
if (target.type == gltf_asset::light::spot)
|
||||
{
|
||||
auto const & spot = light["spot"].GetObject();
|
||||
|
||||
if (light.HasMember("intensity"))
|
||||
target.intensity = light["intensity"].GetFloat();
|
||||
if (spot.HasMember("innerConeAngle"))
|
||||
target.cone_angle.min = spot["innerConeAngle"].GetFloat();
|
||||
|
||||
if (light.HasMember("range"))
|
||||
target.range = light["range"].GetFloat();
|
||||
|
||||
if (target.type == gltf_asset::light::spot)
|
||||
{
|
||||
auto const & spot = light["spot"].GetObject();
|
||||
|
||||
if (spot.HasMember("innerConeAngle"))
|
||||
target.cone_angle.min = spot["innerConeAngle"].GetFloat();
|
||||
|
||||
if (spot.HasMember("outerConeAngle"))
|
||||
target.cone_angle.max = spot["outerConeAngle"].GetFloat();
|
||||
}
|
||||
if (spot.HasMember("outerConeAngle"))
|
||||
target.cone_angle.max = spot["outerConeAngle"].GetFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < result.nodes.size(); ++i)
|
||||
for (auto child : result.nodes[i].children)
|
||||
result.nodes[child].parent = i;
|
||||
|
||||
for (std::size_t i = 0; i < result.nodes.size(); ++i)
|
||||
result.node_index[result.nodes[i].name] = i;
|
||||
|
|
@ -290,4 +356,17 @@ namespace psemek::gfx
|
|||
return result;
|
||||
}
|
||||
|
||||
std::size_t attribute_size(gltf_asset::accessor::type_t type)
|
||||
{
|
||||
using type_t = gltf_asset::accessor::type_t;
|
||||
switch (type)
|
||||
{
|
||||
case type_t::scalar: return 1;
|
||||
case type_t::vec2: return 2;
|
||||
case type_t::vec3: return 3;
|
||||
case type_t::vec4: return 4;
|
||||
default: throw std::runtime_error("unsupported attribute type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue