Using many bones X multiple node parts.

Anything libgdx related goes here!

Using many bones X multiple node parts.

Postby Dancovich » Thu Feb 20, 2014 5:21 pm

I'm currently implementing an exporter for Blender to export models directly to G3DJ (instead to FBX -> fbx-conv -> G3D combo).

One thing I noticed is that if I have a model with too many bones (20 or so) the exporter will break my model into multiple parts where each part will have at most 5 or 6 bones.

My exporter doesn't do that, it will try to optimize the use of BLENDWEIGHT attribute to keep it low (so that each vertex will be weighted to at most 4 to 6 bones) but if there is a mesh object with only one material and 20+ bones it will create one node with one part having all 20 bones.

The DefaultShader in LibGDX is defaulted to only accept 12 bones, but you can change that using this code:

Code: Select all
DefaultShader.Config shaderConfig = new DefaultShader.Config();
shaderConfig.numBones = 20; //Read this value from your model
DefaultShaderProvider shaderProvider = new DefaultShaderProvider(shaderConfig);
modelBatch = new ModelBatch(shaderProvider);

The LibGDX documentation says that each node part will generate a render call.

So my question is what is the recommended approach? Splitting bones through multiple parts and have more render calls with less bone transform matrices or having just one render call with more bone transform matrices?

My understanding is that more render calls will lose time because they are expensive and having to many bones consumes more GPU registers, but I don't know if this is the correct way to see things.
Posts: 14
Joined: Tue Feb 18, 2014 1:43 pm

Re: Using many bones X multiple node parts.

Postby xoppa » Thu Feb 20, 2014 10:03 pm

The best way to find the optimum (maximum) number of bones for a specific scenario is to profile/benchmark. There is no single answer for each and every scenario. However, one thing is for sure: you must limit the number of bones to some certain amount. You can't allow an infinite number of bones. Technically this only applies to the shader, not the g3dx file format. In fact, the first versions of fbx-conv had no default limit. Only if you specified a limit it would split the part into multiple parts. This is changed later to comply with the default shader, because users forgot to specify the limit (or didn't know they had to) and therefor experienced problems.

Like you said, the number of bones used by the default shader (and fbx-conv) is configurable. So, if you need, you can specify more (or less) bones to fit your needs. Or you can try different configurations and test which is more performant in your scenario. Ofcourse, if you go profiling, make sure to use the same amount for both fbx-conv and the default shader.

Also like you said, GPU registers (uniforms) are relatively scarce. The default shader is intended to function on any device with any amount of material attributes (not only the one currently implemented in the glsl files) and still allow for enough custom uniforms for the user. Don't forget: each bone is a matrix (16 floats). 12 bones * 16 float = 192 floats, only used for skinning. To put it in perspective: the PowerVR SGX supports up to 512 floats in the vertex shader and 64 floats in the fragment shader (see: ... ternal.pdf). Note that skinning is one of the most "uniform-costly", there aren't much other uses which cost that much uniforms. So, for the default shader in general, it's important to keep the default amount of uniforms used for skinning to a minimum. Otherwise it will not function correctly on older devices and/or more uniforms than only skinning.

The default shader is also intended to render multiple models and avoid switching shader in between as much as possible. Therefor (just like lighting btw) the limit is fixed (unless specified otherwise) for all models. That is: if a model/nodepart uses less than 12 bones, it still uses the shader compiled for 12 bones. This way the shader can be reused for all models (assuming the other material attributes are the same also).

Therefor the (default) maximum number of bones must be enough (but preferable also not more for the above reason) to hold all bones for any possible nodepart. Which is also why the (default) maximum number of bones is exactly 12 and not 8 or 16 for example. This is because the default number of bone weights per vertex is four (note that this is also configurable using the -w option of fbx-conv). The default (and currently only) primitive type is GL_TRIANGLES (three vertices). Thus the theoretical maximum number of bone weights per primitive is 12. (note that fbx-conv will print a warning if you specify a maximum number of bones less than three times the number of bone weights)

For the number of bone weights per vertex also counts that even if the actual number of bones is below it, the final number of bone weight can still be that amount, e.g. to avoid switching mesh (note that fbx-conv currently doesn't expose that command line option (forceMaxVertexBoneCount)). If there are more bone weights per vertex than the specified maximum, fbx-conv will sort them on importance (the weight of bone0 >= the weights of bone1 etc) and remove the bones above the limit.

tl;dr the (default) maximum number of bones is three (the number of vertices within a triangle) times the (default) maximum number of bone weights per vertex.
Posts: 689
Joined: Thu Aug 23, 2012 11:27 pm

Re: Using many bones X multiple node parts.

Postby Dancovich » Fri Feb 21, 2014 4:27 pm

Thank you xoopa, my understanding of this just increased by 10x.

In this case I decided to implement splitting bones between parts in my Blender exporter as well. I might even have a look into fbx-conv source code for some ideas :D

Anyway, thanks for the insightful answer.
Posts: 14
Joined: Tue Feb 18, 2014 1:43 pm

Return to Libgdx

Who is online

Users browsing this forum: Google [Bot], MSN [Bot] and 1 guest