[solved] [ogre 13] prefer local space skinning vs world

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
loath
Platinum Sponsor
Platinum Sponsor
Posts: 290
Joined: Tue Jan 17, 2012 5:18 am
x 67

[solved] [ogre 13] prefer local space skinning vs world

Post by loath »

any idea why ogre uses a world space bone matrix array for hardware skinning? the vertex shader already has to move each vertex to clip space anyway so it's essentially free to compute in the shader vs iterating and concatenating the large bone matrix arrays on the CPU every frame. you also eliminate the extra memory and copying each frame per entity for the Ogre::Entity::mBoneWorldMatrices.

how do you attach a custom (local space) matrix array per renderable? i prototyped adding a new "ACT_LOCAL_MATRIX_ARRAY_3x4" similar to the existing "ACT_WORLD_MATRIX_ARRAY_3x4" and it works great but perhaps there is another approach? i will submit a prototype for "ACT_LOCAL_MATRIX_ARRAY_3x4" on github but figured i'd ask anyway.

thanks!

Last edited by loath on Sun Oct 02, 2022 7:35 pm, edited 1 time in total.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5429
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1337

Re: [ogre 13] prefer local space skinning vs world

Post by dark_sylinc »

Because it's not?

You're omitting a lot of details in the implementation.

When you do:

Code: Select all

finalVertex = viewProj * (worldSkinning[idx] * inputVertex);
somethingElseOut = viewProj * somethingElseIn;

Ogre needs to do: Concatenate N world matrices for M objects and send them. Per pass, it sends the viewProj matrix.

When you do:

Code: Select all

finalVertex = viewProjMatrix * (localSkinning[idx] * inputVertex);
somethingElseOut = viewProj * somethingElseIn;

Ogre needs to do: send N local matrices for M objects, concatenate one extra world matrix against viewProj and send it for M objects. Per pass, it sends the viewProj matrix.

From the GPU side, having one extra matrix consumes more SGPR, which increases register pressure.

CPU side, In theory we send 64 more bytes than in the previous one, but we save lots of matrix concatenations by not having to do world * localSkinning[ i] in the CPU. However in practice the user will need this data anyway (e.g. bone attachments) thus it cannot be avoided.
If the skeletal system is specialized for a particular purpose (e.g. crowds) where you can get away with not doing world * localSkinning[ i] in the CPU, then local space is likely to be a win (unless you're heavily bandwidth bound or heavily limited by SGPR pressure... the latter being extremely rare). Bonus points if you don't need viewProj * somethingElseIn, which means you can skip sending viewProj.

But again that works on specialized cases, and a generic engine often can't assume that.

This discussion also ignores that often the vertex shader may need to know the final position in world space, hence you actually need:

Code: Select all

worldSpaceVertex = worldSkinning[idx] * inputVertex;
// Do something with worldSpaceVertex
finalVertex = viewProj * worldSpaceVertex;
somethingElseOut = viewProj * somethingElseIn;

vs

Code: Select all

worldSpaceVertex = worldMatrix * (localSkinning[idx] * inputVertex);
// Do something with worldSpaceVertex
finalVertex = viewProj * worldSpaceVertex;
somethingElseOut = viewProj * somethingElseIn;

In this case, the vertex shader needs to do one extra matrix multiplication per object, per vertex, which is definitely more expensive.

paroj
OGRE Team Member
OGRE Team Member
Posts: 2093
Joined: Sun Mar 30, 2014 2:51 pm
x 1129

Re: [ogre 13] prefer local space skinning vs world

Post by paroj »

loath wrote: Tue Sep 27, 2022 12:53 pm

any idea why ogre uses a world space bone matrix array for hardware skinning?

That code was written 18 years ago and was a significant improvement over software skinning: https://github.com/OGRECave/ogre-attic/ ... 47570b1904

I guess they just called it a day and did not go for the extra mile to make it fully optimal.

dark_sylinc wrote: Tue Sep 27, 2022 5:33 pm

However in practice the user will need this data anyway (e.g. bone attachments) thus it cannot be avoided.

still, you would only need to transform the bones that have attachments and most bones will not have attachments.

dark_sylinc wrote: Tue Sep 27, 2022 5:33 pm

This discussion also ignores that often the vertex shader may need to know the final position in world space

Looking at the current RTSS implementation, the vertex shader actually needs to know the object space position to allow composition with stages that are unaware of skinning and assume the input is a plain vertex.
Therefore, we are currently sending that extra matrix to get back to local coordinates..

So I would say having local bone matrices would definitely be an improvement. However, I think it makes not much difference performance-wise as Ogre1 is not GPU-bound and 80 extra multiplications is not that bad either - especially considering that we have SIMD code for that. Might have a bigger impact if you use shader based instancing though: https://ogrecave.github.io/ogre/api/lat ... haderBased

Anyway.. as of getting this feature into Ogre, I would rather go with a global flag in the MeshManager, similar to how UBYTE4 weights were added:
https://github.com/OGRECave/ogre/commit ... c482ad65ab

If that flag is set, a SubEntity will simply pass local matrices via getWorldTransforms and shader code will have to deal with that.
I think this will not cause too much trouble as mBoneWorldMatrices is only returned there and only for hw skinning.

loath
Platinum Sponsor
Platinum Sponsor
Posts: 290
Joined: Tue Jan 17, 2012 5:18 am
x 67

Re: [ogre 13] prefer local space skinning vs world

Post by loath »

dark_sylinc wrote: Tue Sep 27, 2022 5:33 pm

Because it's not?

thanks for the detailed reply. helps ensure i'm on the right track.

to be clear, i have my own custom Ogre::Renderable* objects so i'm not using Ogre::Entity*. Ogre doesn't even need to know i'm doing animation. i just need a way to pass a per-renderable matrix3x4 array to my shaders. in my case the array is in local space for reasons similar to what paroj describes. (i.e. i'd need to concat the world transform on the cpu but then remove the world transform in the shaders).

i need to do the same to my lit and shadow materials.

paroj wrote: Tue Sep 27, 2022 7:12 pm

still, you would only need to transform the bones that have attachments and most bones will not have attachments.

exactly, this is what i do.

paroj wrote: Tue Sep 27, 2022 7:12 pm

Looking at the current RTSS implementation, the vertex shader actually needs to know the object space position to allow composition with stages that are unaware of skinning and assume the input is a plain vertex. Therefore, we are currently sending that extra matrix to get back to local coordinates.

i'll need to do if there is no way to provide a per-renderable matrix3x4.

here is my prototype that works for my scenario: (not intended for submission)
https://github.com/OGRECave/ogre/pull/2603/files

paroj wrote: Tue Sep 27, 2022 7:12 pm

If that flag is set, a SubEntity will simply pass local matrices via getWorldTransforms and shader code will have to deal with that.

we still need the world matrix, don't we? i.e. to create the world transform (and related transforms like worldViewProjection). i could add an additional single-matrix4 for the world transform or use the 0th index of the array for the world transform and the rest for the local skinning data.

then use the flag to setup the data? this part is fuzzy to me. in my prototype i added a new member function onto Ogre::Renderable*.

i appreciate all the help.

paroj
OGRE Team Member
OGRE Team Member
Posts: 2093
Joined: Sun Mar 30, 2014 2:51 pm
x 1129

Re: [ogre 13] prefer local space skinning vs world

Post by paroj »

loath wrote: Wed Sep 28, 2022 4:34 pm
paroj wrote: Tue Sep 27, 2022 7:12 pm

If that flag is set, a SubEntity will simply pass local matrices via getWorldTransforms and shader code will have to deal with that.

we still need the world matrix, don't we? i.e. to create the world transform (and related transforms like worldViewProjection). i could add an additional single-matrix4 for the world transform or use the 0th index of the array for the world transform and the rest for the local skinning data.

I quickly hacked together a test using the 0th index. Seems to work fine (did not commit the RTSS changes to keep this simple)
https://github.com/paroj/ogre/commit/70 ... 4ac1f3fb78

loath
Platinum Sponsor
Platinum Sponsor
Posts: 290
Joined: Tue Jan 17, 2012 5:18 am
x 67

Re: [ogre 13] prefer local space skinning vs world

Post by loath »

sweet... off to try this. thanks!

loath
Platinum Sponsor
Platinum Sponsor
Posts: 290
Joined: Tue Jan 17, 2012 5:18 am
x 67

Re: [ogre 13] prefer local space skinning vs world

Post by loath »

works very well and i don't need any changes to Ogre. thanks again!

paroj
OGRE Team Member
OGRE Team Member
Posts: 2093
Joined: Sun Mar 30, 2014 2:51 pm
x 1129

Re: [ogre 13] prefer local space skinning vs world

Post by paroj »

paroj wrote: Wed Sep 28, 2022 5:35 pm
loath wrote: Wed Sep 28, 2022 4:34 pm
paroj wrote: Tue Sep 27, 2022 7:12 pm

If that flag is set, a SubEntity will simply pass local matrices via getWorldTransforms and shader code will have to deal with that.

we still need the world matrix, don't we? i.e. to create the world transform (and related transforms like worldViewProjection). i could add an additional single-matrix4 for the world transform or use the 0th index of the array for the world transform and the rest for the local skinning data.

I quickly hacked together a test using the 0th index. Seems to work fine (did not commit the RTSS changes to keep this simple)
https://github.com/paroj/ogre/commit/70 ... 4ac1f3fb78

and the finished version: https://github.com/OGRECave/ogre/pull/2609

loath
Platinum Sponsor
Platinum Sponsor
Posts: 290
Joined: Tue Jan 17, 2012 5:18 am
x 67

Re: [ogre 13] prefer local space skinning vs world

Post by loath »

you're amazing!