Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by SoxwareInteractive · Sep 15, 2016 at 06:29 AM · animationmeshmathmatrix4x4

How to scale Mesh.bindPose correctly

Hello everyone,

I'm stuck with a mathematical problem. I want to set all bones of a model to their bind poses. This works OK for most of the models but there is one where the scale in the bind pose is 40 (I guess it was created using that scale, and after importing in Unity it got scaled down automatically to 1). So I want to scale the whole bindPose[] array down so that every bone transform has a scale of 1 (to match my default scale). But this doesn't work as expected (the whole mesh get's messed up).

 Matrix4x4 bindPose = skinnedMeshRenderer.sharedMesh.bindposes[boneIndex];
 
 // Scale by 1 / 40 so that the end result is 1
 Vector3 scale = new Vector3(1/40, 1/40, 1/40);
 Matrix4x4 normalizeScale = Matrix4x4.Scale(scale);

 // Apply the resulting matrix afterwards
 Matrix4x4 result = transform.localToWorldMatrix * normalizeScale * bindPose.inverse;


So I guess either the order in which I multiply the matrices is not correct, or I'm doing the scale in the wrong space? Thanks in advance.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Sep 15, 2016 at 09:35 PM

Your calculation doesn't make much sense ^^. The bindpose matrix is a matrix that should transform a point from the mesh's local space into the localspace of the bone. Once in that space Unity's animation system would then transform the position from the bones local space into world space using the current localToWorld matrix of the bone.

Next thing is this won't work:

 Vector3 scale = new Vector3(1/40, 1/40, 1/40);

this will give you a (0, 0, 0) vector because 1 and 40 are both integer values.

 Matrix4x4 normalizeScale = Matrix4x4.Scale(Vector3.one / 40f);

Since it's the bones local space which is wrongly scaled you want the scaling to happen after all the other transformations. So you have to put your matrix infront of your original bindpose:

 bindPose = normalizeScale * bindPose;

Next thing is it'S not clear what you do with your "result". Keep in mind that sharedMesh.bindposes is a property, so you can't assign seperate matrices to that array. You have to use a temp array, modify your matrices and finally assign the whole array back to sharedMesh.bindposes.

Final Note: Messing with bindposes of imported models isn't a good idea. It will most likely mess up all animations you have. If there is an issue in the model itself, it should be fixed in the modelling tool.

If you just want to change the scale factor of the model, check out the model inspector of the imported model. You can specify a scale factor there. It will reimport the model and will guarantee that everything will still work (as long as the model doesn't have an error already ^^).

edit
Ahh, thanks to your comment i think we can solve that problem ^^. Your mistake is that you used the Amature transform. You have to use the mesh transform.

Spider

The mesh is actually rendered by the SkinnedMeshRenderer. So the transform of the object with the SkinnedMeshRenderer is the one you have to use when you revert the bindpose.

So the original bindpose matrix converts the local vertex coordinates from the local mesh space into the local space of the bone. When you invert the matrix you convert from bone to local mesh space. So then using the localToWorld matrix of the SkinnedMeshRenderer you would get back the bone matrix.


spider-mesh-scale.png (29.0 kB)
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SoxwareInteractive · Sep 16, 2016 at 02:10 PM 0
Share

Thanks for your answer @Bunny83. Yes you are right 1/40 won't work. In the real code the factor is calculated and not hard coded as in the sample above so this was a mistake when I've written the question. Sorry for that...

$$anonymous$$y goal is to reset a model back to it's initial bind pose position at runtime. So I'm extracting the position, rotation and scale out of the resulting matrix and assign those to the corresponding bone transform. This works great with some models but not with all because of the mentioned scaling problem.

Here is my code that works resetting the bones of most of my models (but has the scaling issue):

 $$anonymous$$atrix4x4 bindPose = skinnedRenderer.shared$$anonymous$$esh.bindposes[boneIndex];
 
 // armatureTransform is the transform named "Armature" which is the parent transform of all bones
 // everytime you drag and drop an imported model into the scene.
 $$anonymous$$atrix4x4 invertBindPose = armatureTransform.localToWorld$$anonymous$$atrix * bindPose.inverse;
 
  boneTransform.position = matrix.GetColumn(3);
  boneTransform.rotation = Quaternion.LookRotation(matrix.GetColumn(2), matrix.GetColumn(1));
  boneTransform.localScale = new Vector3( matrix.GetColumn(0).magnitude,
                                                         matrix.GetColumn(1).magnitude,
                                                         matrix.GetColumn(2).magnitude);

Trying to reset this free spider model from the asset store for example doesn't work with this code as bindPose.inverse has a scale of 40 for this model (I checked the magnitudes of column 0 - 2 with the debugger --> scale = 40) and my other models that work have 1. So I wanted to know how to scale down the bindPose.inverse to also have a scale of 1.

avatar image Bunny83 SoxwareInteractive · Sep 16, 2016 at 04:32 PM 0
Share

Ahh, i got your problem now ^^. I'll edit my answer...

avatar image SoxwareInteractive Bunny83 · Sep 20, 2016 at 07:30 PM 0
Share

@Bunny83: Thanks for the hint with the mesh. The scaling is correct when using the skinned$$anonymous$$eshRenderer.localToWorld$$anonymous$$atrix, but the rotation and the position is wrong. Further investigations showed me that the "armature" transform still plays a roll. So I'm using now:

 $$anonymous$$atrix4x4 invertBindPose = armatureTransform.localToWorld$$anonymous$$atrix * skinned$$anonymous$$eshRenderer.localToWorld$$anonymous$$atrix * bindPose.inverse;

With this formular, the rotation and the scaling seems to be correct but the position is still wrong (all bones get a world space offset). I don't understand how the Skinned$$anonymous$$eshRenderer calculates it's end result based on the different matrices (what is multiplied in which order)...

Also, if you change the transform parameters of the Skinned$$anonymous$$eshRenderer in the inspector nothing happens. So those values don't seem to be used by the "Skinned$$anonymous$$eshRenderer" directly???

avatar image
0

Answer by theANMATOR2b · Sep 15, 2016 at 12:54 PM

This forum post by hippocoder seems to be relevant.

http://forum.unity3d.com/threads/assetpostprocessor-skinned-mesh-renderer-bone-index-reorder-solved.401872/#post-2787571

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Make mesh collider constantly change 1 Answer

problems importing bone based vertex animation 3 Answers

Blender to Unity rig : Distend arm 1 Answer

Why can't my player collide with my animated mesh? 1 Answer

Vestigial Animation component in imported mesh 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges