If only 2 bones are being used I ll have to make another shader:
Um, no.
The number of bones used per-vertex is a… well, per-vertex quantity. It is not a uniform, nor is it something that you can bake into a shader at compile time. It is either an attribute or an understood constant (as in my example).
If a particular vertex doesn’t actually use all 4 bones that it could, it simply uses a 0 weight for the others (and a valid bone index. Like 0). This is a common technique in vertex program-based skinning, and you should use it.
That’s why 4 is a reasonable number for nIndices. If your artists disagree, smack them.
I don’t know how you rig a character with only 4 bones, but slapping the artists will make me look like a fool that’s is for sure.
since vertex attributes only takes 4 components I guess I ll have to use other attributes to send more bones? damn, my faith in technology starts to fading out…
Originally posted by Golgoth: I don’t know how you rig a character with only 4 bones, but slapping the artists will make me look like a fool that’s is for sure.
This are 4 bones influencing one vertex. Not 4 bones for entire character. Of course you have to split the character into parts by groups of bones and draw each part independently. The indexed method mentioned above will allow you to have reasonably sized parts. Without it you will have use separate draw for each combination of bones and you might be even unable to skin some triangles if number of disjunct bones influencing theirs vertices is higher than number of bones you combine together.
It seems that you are thing about the skinning in following way:
On GPU:
foreach vertex {
foreach bone_in_character {
apply bone
}
}
What you need to do is:
On CPU during mesh load:
[ul][li]For each vertex select four bones with the highest weight & report error if there are more bones with significant weight. It is good to allow the artists to have more bones assigned to the vertex inside the modeling tool if only four of them have significant weight (e.g. >0.01)[*]Construct groups of bones. Maximal size of one group depends on number of matrices you can upload to the uniform variables (e.g. 20 from my post). Assign triangles to the groups. Triangle can be assigned to group which contains all bones selected for triangle vertices. Actually the construction and assignment needs to operate simultaneously so each triangle can be assigned to one group and the groups do not contain bones that are not used by any triangle assigned to them. Of course this means that one bone will very likely end in several groups, this is unavoidable. During the assignment you will generate four bone indices for each vertex. They will represent index of corresponding bone within the group.[/ul][/li]You will then draw the mesh using following:
On CPU:
foreach group {
upload bone matrices for the group to the GPU
draw triangles from the group
}
On GPU:
foreach vertex within the group {
foreach bone_index_assigned_to_vertex (there are 4 of them) {
apply bone with specified index inside the group
}
}
Of course you have to split the character into parts by groups of bones and draw each part independently.
Note: you only need to do that if the total number of bones needed for the mesh exceeds the number of uniforms that you wish to devote to the shader. With quaternion-based bones (rather than matrices), and cards with 256 (or more?) vec4 uniforms, there’s substantially less reason to run into effective limits. 96 bones * 2 is often a good number of uniforms to work with on said hardware; that still gives you 64 uniforms for other needs.
On CPU during mesh load:
For performance-critical applications, this sort of stuff should be done as a preprocessing step and the results stored in a properly formatted file, not something that happens anytime you load a mesh.
Originally posted by Korval: For performance-critical applications, this sort of stuff should be done as a preprocessing step and the results stored in a properly formatted file, not something that happens anytime you load a mesh.
It depends on the nature of the application. If it needs to stream the data on the fly, the preprocessing is a must. If it loads all skinned meshes during level load and the algorithm is sufficiently fast (e.g. something greedy), doing the operation at runtime will allow you to adapt the size to capabilities of current hw without need to have files for several prepared combinations.
If it loads all skinned meshes during level load and the algorithm is sufficiently fast
That means that tri-stripping has to be a load-time thing too. This means that you can’t use the most effective algorithm, which means you’re going to lose runtime performance just from standard rendering calls.
Also, making a performance-critical application run slower at load for no real reason is not a good idea. It’s better to properly format your data as needed, perhaps at install time.
Like I said, for performance-critical applications, it should be a preprocess.
Ok, I think you guys went ahead of what I planned to do!
First, I totally agree with the 4 bones per vertex… it totally make sense and I wont go beyond this limitation. Which btw is due to the max of components per vertex attributes if my understanding is correct.
I m the one pass only type. So I ll avoid multi passes at all cost. I just hate this concept. Once again, if I do get this right, the groups of bones and/or caching into a file technique is one way to find which bone matrices goes with which vertex. My current choice would be to process this when importing the data. Parse all vertices and create the bone indices on the fly.
Then again you guys rock. Thx for sharing your knowledge with me, I greatly appreciate it.