Initial support of animation.

This commit is contained in:
Syoyo Fujita 2016-06-19 18:15:32 +09:00
parent 330f6da818
commit 8c5ab0344f
3 changed files with 272 additions and 53 deletions

View File

@ -34,7 +34,7 @@
## TODOs
* [ ] Support multiple scenes in `.gltf`
* [ ] Parse `animation`, `sampler`
* [ ] Parse `sampler`
* [ ] Compression/decompression(Open3DGC, etc)
* [ ] Support `extensions` and `extras` property
* [ ] HDR image?

View File

@ -2,8 +2,8 @@
#define STB_IMAGE_IMPLEMENTATION
#include "tiny_gltf_loader.h"
#include <fstream>
#include <cstdio>
#include <fstream>
#include <iostream>
static std::string GetFilePathExtension(const std::string &FileName) {
@ -179,7 +179,7 @@ static std::string Indent(int indent) {
return s;
}
static std::string PrintParameterValue(const tinygltf::Parameter& param) {
static std::string PrintParameterValue(const tinygltf::Parameter &param) {
if (!param.number_array.empty()) {
return PrintFloatArray(param.number_array);
} else {
@ -222,16 +222,14 @@ static void DumpStringMap(const std::map<std::string, std::string> &map,
std::map<std::string, std::string>::const_iterator it(map.begin());
std::map<std::string, std::string>::const_iterator itEnd(map.end());
for (; it != itEnd; it++) {
std::cout << Indent(indent) << it->first << ": " << it->second
<< std::endl;
std::cout << Indent(indent) << it->first << ": " << it->second << std::endl;
}
}
static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
std::cout << Indent(indent) << "material : " << primitive.material
<< std::endl;
std::cout << Indent(indent) << "indices : " << primitive.indices
<< std::endl;
std::cout << Indent(indent) << "indices : " << primitive.indices << std::endl;
std::cout << Indent(indent) << "mode : " << PrintMode(primitive.mode)
<< "(" << primitive.mode << ")" << std::endl;
std::cout << Indent(indent)
@ -242,16 +240,13 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
static void DumpTechniqueParameter(const tinygltf::TechniqueParameter &param,
int indent) {
std::cout << Indent(indent) << "count : " << param.count
<< std::endl;
std::cout << Indent(indent) << "node : " << param.node
<< std::endl;
std::cout << Indent(indent) << "semantic : " << param.semantic
<< std::endl;
std::cout << Indent(indent) << "count : " << param.count << std::endl;
std::cout << Indent(indent) << "node : " << param.node << std::endl;
std::cout << Indent(indent) << "semantic : " << param.semantic << std::endl;
std::cout << Indent(indent) << "type : " << PrintParameterType(param.type)
<< std::endl;
std::cout << Indent(indent) << "value : "
<< PrintParameterValue(param.value) << std::endl;
std::cout << Indent(indent)
<< "value : " << PrintParameterValue(param.value) << std::endl;
}
static void Dump(const tinygltf::Scene &scene) {
@ -288,8 +283,10 @@ static void Dump(const tinygltf::Scene &scene) {
}
{
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
std::map<std::string, tinygltf::Mesh>::const_iterator it(
scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
scene.meshes.end());
std::cout << "meshes(item=" << scene.meshes.size() << ")" << std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name : " << it->second.name << std::endl;
@ -304,10 +301,11 @@ static void Dump(const tinygltf::Scene &scene) {
}
{
std::map<std::string, tinygltf::Accessor>::const_iterator it(scene.accessors.begin());
std::map<std::string, tinygltf::Accessor>::const_iterator it(
scene.accessors.begin());
std::map<std::string, tinygltf::Accessor>::const_iterator itEnd(
scene.accessors.end());
std::cout << "accessos(items=" << scene.accessors.size() << ")"
std::cout << "accessors(items=" << scene.accessors.size() << ")"
<< std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name : " << it->first << std::endl;
@ -343,6 +341,64 @@ static void Dump(const tinygltf::Scene &scene) {
}
}
{
std::map<std::string, tinygltf::Animation>::const_iterator it(
scene.animations.begin());
std::map<std::string, tinygltf::Animation>::const_iterator itEnd(
scene.animations.end());
std::cout << "animations(items=" << scene.animations.size() << ")"
<< std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name : " << it->first << std::endl;
std::cout << Indent(1) << "channels : [ " << std::endl;
for (size_t i = 0; i < it->second.channels.size(); i++) {
std::cout << Indent(2)
<< "sampler : " << it->second.channels[i].sampler
<< std::endl;
std::cout << Indent(2)
<< "target.id : " << it->second.channels[i].target_id
<< std::endl;
std::cout << Indent(2)
<< "target.path : " << it->second.channels[i].target_path
<< std::endl;
std::cout << ((i != (it->second.channels.size() - 1)) ? " , " : "");
}
std::cout << " ]" << std::endl;
std::map<std::string, tinygltf::AnimationSampler>::const_iterator
samplerIt(it->second.samplers.begin());
std::map<std::string, tinygltf::AnimationSampler>::const_iterator
samplerItEnd(it->second.samplers.end());
std::cout << Indent(1) << "samplers(items=" << it->second.samplers.size()
<< ")" << std::endl;
for (; samplerIt != samplerItEnd; samplerIt++) {
std::cout << Indent(1) << "name : " << samplerIt->first
<< std::endl;
std::cout << Indent(2) << "input : " << samplerIt->second.input
<< std::endl;
std::cout << Indent(2)
<< "interpolation : " << samplerIt->second.interpolation
<< std::endl;
std::cout << Indent(2) << "output : " << samplerIt->second.output
<< std::endl;
}
{
std::cout << Indent(1)
<< "parameters(items=" << it->second.parameters.size() << ")"
<< std::endl;
tinygltf::ParameterMap::const_iterator p(it->second.parameters.begin());
tinygltf::ParameterMap::const_iterator pEnd(
it->second.parameters.end());
for (; p != pEnd; p++) {
std::cout << Indent(2) << p->first << ": "
<< PrintParameterValue(p->second) << std::endl;
}
}
}
}
{
std::map<std::string, tinygltf::BufferView>::const_iterator it(
scene.bufferViews.begin());
@ -358,14 +414,17 @@ static void Dump(const tinygltf::Scene &scene) {
<< std::endl;
std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset
<< std::endl;
std::cout << Indent(2) << "target : " << PrintTarget(it->second.target)
std::cout << Indent(2)
<< "target : " << PrintTarget(it->second.target)
<< std::endl;
}
}
{
std::map<std::string, tinygltf::Buffer>::const_iterator it(scene.buffers.begin());
std::map<std::string, tinygltf::Buffer>::const_iterator itEnd(scene.buffers.end());
std::map<std::string, tinygltf::Buffer>::const_iterator it(
scene.buffers.begin());
std::map<std::string, tinygltf::Buffer>::const_iterator itEnd(
scene.buffers.end());
std::cout << "buffers(items=" << scene.buffers.size() << ")" << std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name : " << it->first << std::endl;
@ -375,7 +434,8 @@ static void Dump(const tinygltf::Scene &scene) {
}
{
std::map<std::string, tinygltf::Material>::const_iterator it(scene.materials.begin());
std::map<std::string, tinygltf::Material>::const_iterator it(
scene.materials.begin());
std::map<std::string, tinygltf::Material>::const_iterator itEnd(
scene.materials.end());
std::cout << "materials(items=" << scene.materials.size() << ")"
@ -397,8 +457,10 @@ static void Dump(const tinygltf::Scene &scene) {
}
{
std::map<std::string, tinygltf::Node>::const_iterator it(scene.nodes.begin());
std::map<std::string, tinygltf::Node>::const_iterator itEnd(scene.nodes.end());
std::map<std::string, tinygltf::Node>::const_iterator it(
scene.nodes.begin());
std::map<std::string, tinygltf::Node>::const_iterator itEnd(
scene.nodes.end());
std::cout << "nodes(items=" << scene.nodes.size() << ")" << std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name : " << it->first << std::endl;
@ -408,8 +470,10 @@ static void Dump(const tinygltf::Scene &scene) {
}
{
std::map<std::string, tinygltf::Image>::const_iterator it(scene.images.begin());
std::map<std::string, tinygltf::Image>::const_iterator itEnd(scene.images.end());
std::map<std::string, tinygltf::Image>::const_iterator it(
scene.images.begin());
std::map<std::string, tinygltf::Image>::const_iterator itEnd(
scene.images.end());
std::cout << "images(items=" << scene.images.size() << ")" << std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name : " << it->first << std::endl;
@ -424,8 +488,10 @@ static void Dump(const tinygltf::Scene &scene) {
}
{
std::map<std::string, tinygltf::Texture>::const_iterator it(scene.textures.begin());
std::map<std::string, tinygltf::Texture>::const_iterator itEnd(scene.textures.end());
std::map<std::string, tinygltf::Texture>::const_iterator it(
scene.textures.begin());
std::map<std::string, tinygltf::Texture>::const_iterator itEnd(
scene.textures.end());
std::cout << "textures(items=" << scene.textures.size() << ")" << std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name : " << it->first << std::endl;
@ -446,15 +512,16 @@ static void Dump(const tinygltf::Scene &scene) {
{
std::map<std::string, tinygltf::Shader>::const_iterator it(
scene.shaders.begin());
scene.shaders.begin());
std::map<std::string, tinygltf::Shader>::const_iterator itEnd(
scene.shaders.end());
scene.shaders.end());
std::cout << "shaders(items=" << scene.shaders.size() << ")" << std::endl;
for (; it != itEnd; it++) {
std::cout << Indent(1) << "name (id) : " << it->first << std::endl;
std::cout << Indent(2) << "type : "
<< PrintShaderType(it->second.type) << std::endl;
std::cout << Indent(2)
<< "type : " << PrintShaderType(it->second.type)
<< std::endl;
std::cout << Indent(2) << "name (json) : " << it->second.name
<< std::endl;
@ -464,9 +531,9 @@ static void Dump(const tinygltf::Scene &scene) {
shader_source.resize(shader_source.size() + it->second.source.size());
std::vector<unsigned char>::const_iterator sourceIt(
it->second.source.begin());
it->second.source.begin());
std::vector<unsigned char>::const_iterator sourceItEnd(
it->second.source.end());
it->second.source.end());
for (; sourceIt != sourceItEnd; ++sourceIt) {
shader_source += *sourceIt;
@ -474,16 +541,16 @@ static void Dump(const tinygltf::Scene &scene) {
shader_source += Indent(3);
}
}
std::cout << Indent(2) << "source :\n" << shader_source
<< std::endl;
std::cout << Indent(2) << "source :\n"
<< shader_source << std::endl;
}
}
{
std::map<std::string, tinygltf::Program>::const_iterator it(
scene.programs.begin());
scene.programs.begin());
std::map<std::string, tinygltf::Program>::const_iterator itEnd(
scene.programs.end());
scene.programs.end());
std::cout << "programs(items=" << scene.programs.size() << ")" << std::endl;
for (; it != itEnd; it++) {
@ -501,9 +568,9 @@ static void Dump(const tinygltf::Scene &scene) {
{
std::map<std::string, tinygltf::Technique>::const_iterator it(
scene.techniques.begin());
scene.techniques.begin());
std::map<std::string, tinygltf::Technique>::const_iterator itEnd(
scene.techniques.end());
scene.techniques.end());
std::cout << "techniques(items=" << scene.techniques.size() << ")"
<< std::endl;
@ -516,15 +583,16 @@ static void Dump(const tinygltf::Scene &scene) {
std::cout << Indent(2) << "name (json) : " << it->second.name
<< std::endl;
std::cout << Indent(2) << "parameters(items="
<< it->second.parameters.size() << ")" << std::endl;
std::cout << Indent(2)
<< "parameters(items=" << it->second.parameters.size() << ")"
<< std::endl;
std::map<std::string, tinygltf::TechniqueParameter>::const_iterator
paramIt(it->second.parameters.begin());
paramIt(it->second.parameters.begin());
std::map<std::string, tinygltf::TechniqueParameter>::const_iterator
paramItEnd(it->second.parameters.end());
paramItEnd(it->second.parameters.end());
for(; paramIt != paramItEnd; ++paramIt) {
for (; paramIt != paramItEnd; ++paramIt) {
std::cout << Indent(3) << "name : " << paramIt->first << std::endl;
DumpTechniqueParameter(paramIt->second, 4);
}
@ -535,13 +603,11 @@ static void Dump(const tinygltf::Scene &scene) {
DumpStringMap(it->second.attributes, 3);
std::cout << Indent(2)
<< "uniforms(items=" << it->second.uniforms.size() << ")"
<< std::endl;
std::cout << Indent(2) << "uniforms(items=" << it->second.uniforms.size()
<< ")" << std::endl;
DumpStringMap(it->second.uniforms, 3);
}
}
}
int main(int argc, char **argv) {

View File

@ -31,7 +31,8 @@
//
//
// Version:
// - v0.9.4 Support parsing `shader`, `program` and `tecnique` thanks to @lukesanantonio
// - v0.9.4 Support parsing `shader`, `program` and `tecnique` thanks to
// @lukesanantonio
// - v0.9.3 Support binary glTF
// - v0.9.2 Support parsing `texture`
// - v0.9.1 Support loading glTF asset from memory
@ -130,6 +131,25 @@ typedef struct {
typedef std::map<std::string, Parameter> ParameterMap;
typedef struct {
std::string sampler;
std::string target_id;
std::string target_path;
} AnimationChannel;
typedef struct {
std::string input;
std::string interpolation;
std::string output;
} AnimationSampler;
typedef struct {
std::string name;
std::vector<AnimationChannel> channels;
std::map<std::string, AnimationSampler> samplers;
ParameterMap parameters;
} Animation;
typedef struct {
std::string name;
int width;
@ -278,6 +298,7 @@ class Scene {
~Scene() {}
std::map<std::string, Accessor> accessors;
std::map<std::string, Animation> animations;
std::map<std::string, Buffer> buffers;
std::map<std::string, BufferView> bufferViews;
std::map<std::string, Material> materials;
@ -1249,8 +1270,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err,
if (err) {
std::stringstream ss;
ss << "Invalid `byteLength'. Must be equal or less than binary size: "
"`byteLength' = " << byteLength
<< ", binary size = " << bin_size << std::endl;
"`byteLength' = "
<< byteLength << ", binary size = " << bin_size << std::endl;
(*err) += ss.str();
}
return false;
@ -1720,6 +1741,121 @@ static bool ParseTechnique(Technique *technique, std::string *err,
return true;
}
static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
const picojson::object &o) {
if (!ParseStringProperty(&channel->sampler, err, o, "sampler", true)) {
if (err) {
(*err) += "`sampler` field is missing in animation channels\n";
}
return false;
}
picojson::object::const_iterator targetIt = o.find("target");
if ((targetIt != o.end()) && (targetIt->second).is<picojson::object>()) {
const picojson::object &target_object =
(targetIt->second).get<picojson::object>();
if (!ParseStringProperty(&channel->target_id, err, target_object, "id",
true)) {
if (err) {
(*err) += "`id` field is missing in animation.channels.target\n";
}
return false;
}
if (!ParseStringProperty(&channel->target_path, err, target_object, "path",
true)) {
if (err) {
(*err) += "`path` field is missing in animation.channels.target\n";
}
return false;
}
}
return true;
}
static bool ParseAnimation(Animation *animation, std::string *err,
const picojson::object &o) {
{
picojson::object::const_iterator channelsIt = o.find("channels");
if ((channelsIt != o.end()) && (channelsIt->second).is<picojson::array>()) {
const picojson::array &channelArray =
(channelsIt->second).get<picojson::array>();
for (size_t i = 0; i < channelArray.size(); i++) {
AnimationChannel channel;
if (ParseAnimationChannel(&channel, err,
channelArray[i].get<picojson::object>())) {
// Only add the channel if the parsing succeeds.
animation->channels.push_back(channel);
}
}
}
}
{
picojson::object::const_iterator samplerIt = o.find("samplers");
if ((samplerIt != o.end()) && (samplerIt->second).is<picojson::object>()) {
const picojson::object &sampler_object =
(samplerIt->second).get<picojson::object>();
picojson::object::const_iterator it = sampler_object.begin();
picojson::object::const_iterator itEnd = sampler_object.end();
for (; it != itEnd; it++) {
// Skip non-objects
if (!it->second.is<picojson::object>()) continue;
const picojson::object &s = it->second.get<picojson::object>();
AnimationSampler sampler;
if (!ParseStringProperty(&sampler.input, err, s, "input", true)) {
if (err) {
(*err) += "`input` field is missing in animation.sampler\n";
}
return false;
}
if (!ParseStringProperty(&sampler.interpolation, err, s,
"interpolation", true)) {
if (err) {
(*err) += "`interpolation` field is missing in animation.sampler\n";
}
return false;
}
if (!ParseStringProperty(&sampler.output, err, s, "output", true)) {
if (err) {
(*err) += "`output` field is missing in animation.sampler\n";
}
return false;
}
animation->samplers[it->first] = sampler;
}
}
}
picojson::object::const_iterator parametersIt = o.find("parameters");
if ((parametersIt != o.end()) &&
(parametersIt->second).is<picojson::object>()) {
const picojson::object &parameters_object =
(parametersIt->second).get<picojson::object>();
picojson::object::const_iterator it(parameters_object.begin());
picojson::object::const_iterator itEnd(parameters_object.end());
for (; it != itEnd; it++) {
Parameter param;
if (ParseParameterProperty(&param, err, parameters_object, it->first,
false)) {
animation->parameters[it->first] = param;
}
}
}
ParseStringProperty(&animation->name, err, o, "name", false);
return true;
}
bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
const char *str, unsigned int length,
const std::string &base_dir) {
@ -2041,6 +2177,23 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
}
}
// 14. Parse Animation
if (v.contains("animations") && v.get("animations").is<picojson::object>()) {
const picojson::object &root = v.get("animations").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; ++it) {
Animation animation;
if (!ParseAnimation(&animation, err,
(it->second).get<picojson::object>())) {
return false;
}
scene->animations[it->first] = animation;
}
}
return true;
}