glTF animations, loading sampler data from interleaved buffer

Hello everyone,

We are having problems with animations loaded from glTF when animation data is stored in interleaved buffer view (buffer view which has property byteStride set and multiple accessors use that same buffer view).

The problem
The glTF scene is loaded fine, it looks OK until animation is started. When animation starts, whole model gets distorted.

Description
We store animation data (positions, rotations, scale values) in interleaved buffers. Buffer views have properly set byteStride values, but looks like glTF loader does not check that value when loading data into accessor.

I checked animation data in BabylonJS viewer objects when the model is loaded (using Chrome dev tools) and it looks like there are wrong values loaded into animation data.

We have buffer view defined like this:

{
	"buffer": 2,
	"byteLength": 2560,
	"byteStride": 40,
	"byteOffset": 256
}

And then three accessors that use this buffer view look like this:

{
	"bufferView": 9,
	"byteOffset": 0,
	"type": "VEC4",
	"componentType": 5126,
	"count": 64
},
{
	"bufferView": 9,
	"byteOffset": 16,
	"type": "VEC3",
	"componentType": 5126,
	"count": 64
},
{
	"bufferView": 9,
	"byteOffset": 28,
	"type": "VEC3",
	"componentType": 5126,
	"count": 64
}

I checked source code in glTFLoader.ts and it looks like method _loadAccessorAsync(...) calls loadBufferViewAsync(...), but neither of methods take bufferView.byteStride property into consideration and they just load data directly from buffer into accessor._data.

Example
Example for this issue is gltf file on dropbox (sorry, I am new user on forum, so I can only put two URLs):

Other JS glTF libraries
I tried this same animation in vscode using glTF extension and different js libraries:

  • babylon 4.1.0 - objects get distorted as described
  • cesium 1.73 - animation works fine
  • filament 1.8.1 - this animation works, but there are issues with similar gltf scenes
  • three.js r120 - cannot even start the animation

Thank you,
Nikola

pinging @bghgary on this one

Thanks for the bug report @nmalisa! I have fixed it with this PR:

Iā€™m not sure why Blender is outputting animation as interleaved, but I just want to warn that interleaved animation data is slower to load, so be aware of that.

1 Like

It works now, thank you for fast response!

I am not sure if this asset was created by Blender, we use multiple tools to process glTF assets and some are our own implementations, but thanks for the warning.

1 Like

Hi @nmalisa, just following up since there is a discussion happening at the glTF GitHub about this. We are discussing whether interleaved animation data is allowed or not.

Can you tell us what tools are generating interleaved animation data and why it is useful? Thanks.

Hi @bghgary, thank you for bringing this issue to my attention.

This particular gltf file was created by our internal tool.
We will discuss the issue internally and I will get back with our reasons for using interleaved animation data.

hi @bghgary, here is our reason for using interleaved animation data:

We compute animations on CPU and because of that, we want to store all animation data for each frame tightly packed.

To compute Q (rotation, float[4]) and T (translation, float[3]) values for time t (time, float) we need data of two consecutive frames: before and after t. In our case it is t-, Q-, T- and t+, Q+, T+. It is exactly 64 bytes and will fit one cache line of most modern CPUs.
With interleaved data, we need only one access to external memory to obtain all necessary data for animation computing.
On the other hand, if we store animation data in 3 separate buffers, we will access memory 3 times and it will load 192 bytes in cache instead of required 64.
Between calculating two frames for one object, hundreds of megabytes will flow through cache, so all excessive animation data will be overwritten and will not be used for the next frame.

Similarly, if we add scale (float[3]) to translation and rotation, we have 2 memory reads (in case of 64-byte cache) instead of 4.

So we use interleaved animation data to reduce number of times CPU accesses external memory.

1 Like