<p>The accessor (<code>model.accessors[accessor_index]</code>) has its own <code>byteOffset</code> and <code>count</code> values that you need to account for here.</p>
<p>The input and output accessors are allowed to share a bufferView, and your output is showing a dump of the same entire bufferView twice.  The first five values in that dump are the input accessor with the times (in seconds, since the start of the animation) and the remainder of the bufferView is pointed at by the output accessor.  If you account for the additional settings on the accessor itself, it should allow you to pick apart this bufferView correctly.</p>

CC BY-SA 4.0
2020-10-25T18:54:35.897Z
2020-10-25T18:54:35.897Z
emackey
<p>I am using tinyGLTF to parse gltf files and then render them in my program.</p>
<p>I am currently during the third example in <a href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0" rel="nofollow noreferrer">this page</a>.</p>
<p>In particular I am trying to extract the 2 animation buffers:
<a href="https://i.sstatic.net/YIfYs.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/YIfYs.png" alt="enter image description here" /></a></p>
<p>My code:</p>
<pre class="lang-cpp prettyprint-override"><code>MeshMap LoadGltf(const std::string&amp; path)
{
    Model model;
    TinyGLTF loader;
    std::string err;
    std::string warn;

    bool ret = loader.LoadASCIIFromFile(&amp;model, &amp;err, &amp;warn, path);

    if(!warn.empty()) { cout &lt;&lt; warn &lt;&lt; endl; }

    if(!err.empty()) { cout &lt;&lt; err &lt;&lt; endl; }

    if(!ret) { cout &lt;&lt; &quot;Failed to parse glTF&quot; &lt;&lt; endl; }

    MeshMap mesh_map;
    for(auto&amp; mesh: model.meshes)
    {
        if(mesh.name.empty())
            mesh.name = &quot;unnamed mesh &quot; + to_string(global_mesh_index++);
        // TODO(low): implement this functionality as needed
        assert(mesh.primitives.size() == 1);
        GetPrimitiveData(model, mesh, mesh_map);
    }

    if(model.animations.size())
    {
        cout &lt;&lt; &quot;model.animations.size() &quot; &lt;&lt; model.animations.size() &lt;&lt; endl;
        cout &lt;&lt; &quot;model.animations[0].channels.size() &quot; &lt;&lt; model.animations[0].channels.size() &lt;&lt; endl;
        cout &lt;&lt; &quot;model.animations[0].channels[0].sampler &quot; &lt;&lt; model.animations[0].channels[0].sampler &lt;&lt; endl;
        cout &lt;&lt; &quot;model.animations[0].samplers[0].input &quot; &lt;&lt; model.animations[0].samplers[0].input &lt;&lt; endl;
        cout &lt;&lt; &quot;model.animations[0].samplers[0].output &quot; &lt;&lt; model.animations[0].samplers[0].output &lt;&lt; endl;

        const int input = model.animations[0].samplers[0].input;
        const int output = model.animations[0].samplers[0].output;

        vector&lt;float&gt; time = ExtractDataFromAccessor&lt;float&gt;(model, input);
        for(auto f : time) cout &lt;&lt; f &lt;&lt; &quot; &quot;;
        cout &lt;&lt; endl;
        cout &lt;&lt; time.size() &lt;&lt; endl;
        cout &lt;&lt; model.accessors[input].name &lt;&lt; endl;
        vector&lt;float&gt; rot = ExtractDataFromAccessor&lt;float&gt;(model, output);
        for(auto f : rot) cout &lt;&lt; f &lt;&lt; &quot; &quot;;
        cout &lt;&lt; endl;

        cout &lt;&lt; model.animations[0].channels[0].target_node &lt;&lt; endl;
        cout &lt;&lt; model.animations[0].channels[0].target_path &lt;&lt; endl;
    }

    return mesh_map;
}
</code></pre>
<pre class="lang-cpp prettyprint-override"><code>template&lt;typename T&gt;
std::vector&lt;T&gt; ExtractDataFromAccessor(
    Model&amp; model,
    const int accessor_index)
{
    const int buffer_view_index = model.accessors[accessor_index].bufferView;
    const int buffer_index = model.bufferViews[buffer_view_index].buffer;
    const int buffer_length = model.bufferViews[buffer_view_index].byteLength;
    const int buffer_offset = model.bufferViews[buffer_view_index].byteOffset;
    const int buffer_stride = model.bufferViews[buffer_view_index].byteStride;
    const vector&lt;unsigned char&gt; data = model.buffers[buffer_index].data;

    //TODO(low): extend functionality to handle this as needed.
    assert(buffer_stride == 0);

    std::vector&lt;T&gt; holder(buffer_length / sizeof(T));
    memcpy(
        holder.data(),
        data.data() + buffer_offset,
        buffer_length);

    return holder;
}
</code></pre>
<p>Output</p>
<pre><code>model.animations.size() 1
model.animations[0].channels.size() 1
model.animations[0].channels[0].sampler 0
model.animations[0].samplers[0].input 2
model.animations[0].samplers[0].output 3
0 0.25 0.5 0.75 1 0 0 0 1 0 0 0.707 0.707 0 0 1 0 0 0 0.707 -0.707 0 0 0 1 
25

0 0.25 0.5 0.75 1 0 0 0 1 0 0 0.707 0.707 0 0 1 0 0 0 0.707 -0.707 0 0 0 1 
0
rotation
</code></pre>
<p>I am very confused in that <code>in</code> and <code>out</code> seem to be equal, and that they are the concatenation of the 2 animation buffers, rather than what I expected. Which was <code>in</code> to be the time buffer and <code>out</code> to be the rotation buffer.</p>
<p>Where is the data that lets you separate them?</p>

<c++><animation><model><gltf>
Why are these 2 buffers joint while extracting glTF information?
Makogan
# Why are these 2 buffers joint while extracting glTF information?

(Asked by: username_0 on 2020-10-25)

I am using tinyGLTF to parse gltf files and then render them in my program.

I am currently during the third example in [this page](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0).

In particular I am trying to extract the 2 animation buffers:
[![enter image description here](https://i.sstatic.net/YIfYs.png)](https://i.sstatic.net/YIfYs.png)

My code:

```cpp
MeshMap LoadGltf(const std::string& path)
{
    Model model;
    TinyGLTF loader;
    std::string err;
    std::string warn;

    bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, path);

    if(!warn.empty()) { cout << warn << endl; }

    if(!err.empty()) { cout << err << endl; }

    if(!ret) { cout << "Failed to parse glTF" << endl; }

    MeshMap mesh_map;
    for(auto& mesh: model.meshes)
    {
        if(mesh.name.empty())
            mesh.name = "unnamed mesh " + to_string(global_mesh_index++);
        // TODO(low): implement this functionality as needed
        assert(mesh.primitives.size() == 1);
        GetPrimitiveData(model, mesh, mesh_map);
    }

    if(model.animations.size())
    {
        cout << "model.animations.size() " << model.animations.size() << endl;
        cout << "model.animations[0].channels.size() " << model.animations[0].channels.size() << endl;
        cout << "model.animations[0].channels[0].sampler " << model.animations[0].channels[0].sampler << endl;
        cout << "model.animations[0].samplers[0].input " << model.animations[0].samplers[0].input << endl;
        cout << "model.animations[0].samplers[0].output " << model.animations[0].samplers[0].output << endl;

        const int input = model.animations[0].samplers[0].input;
        const int output = model.animations[0].samplers[0].output;

        vector<float> time = ExtractDataFromAccessor<float>(model, input);
        for(auto f : time) cout << f << " ";
        cout << endl;
        cout << time.size() << endl;
        cout << model.accessors[input].name << endl;
        vector<float> rot = ExtractDataFromAccessor<float>(model, output);
        for(auto f : rot) cout << f << " ";
        cout << endl;

        cout << model.animations[0].channels[0].target_node << endl;
        cout << model.animations[0].channels[0].target_path << endl;
    }

    return mesh_map;
}

```

```cpp
template<typename T>
std::vector<T> ExtractDataFromAccessor(
    Model& model,
    const int accessor_index)
{
    const int buffer_view_index = model.accessors[accessor_index].bufferView;
    const int buffer_index = model.bufferViews[buffer_view_index].buffer;
    const int buffer_length = model.bufferViews[buffer_view_index].byteLength;
    const int buffer_offset = model.bufferViews[buffer_view_index].byteOffset;
    const int buffer_stride = model.bufferViews[buffer_view_index].byteStride;
    const vector<unsigned char> data = model.buffers[buffer_index].data;

    //TODO(low): extend functionality to handle this as needed.
    assert(buffer_stride == 0);

    std::vector<T> holder(buffer_length / sizeof(T));
    memcpy(
        holder.data(),
        data.data() + buffer_offset,
        buffer_length);

    return holder;
}

```

Output

```
model.animations.size() 1
model.animations[0].channels.size() 1
model.animations[0].channels[0].sampler 0
model.animations[0].samplers[0].input 2
model.animations[0].samplers[0].output 3
0 0.25 0.5 0.75 1 0 0 0 1 0 0 0.707 0.707 0 0 1 0 0 0 0.707 -0.707 0 0 0 1 
25

0 0.25 0.5 0.75 1 0 0 0 1 0 0 0.707 0.707 0 0 1 0 0 0 0.707 -0.707 0 0 0 1 
0
rotation

```

I am very confused in that `in` and `out` seem to be equal, and that they are the concatenation of the 2 animation buffers, rather than what I expected. Which was `in` to be the time buffer and `out` to be the rotation buffer.

Where is the data that lets you separate them?

**Tags:** c++, animation, model, gltf


---

## 1 answers

### Answer by username_1 on 2020-10-25. Score: 1 | Accepted answer

The accessor (`model.accessors[accessor_index]`) has its own `byteOffset` and `count` values that you need to account for here.

The input and output accessors are allowed to share a bufferView, and your output is showing a dump of the same entire bufferView twice. The first five values in that dump are the input accessor with the times (in seconds, since the start of the animation) and the remainder of the bufferView is pointed at by the output accessor. If you account for the additional settings on the accessor itself, it should allow you to pick apart this bufferView correctly.


---

