Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Question Skinned mesh vertex position after weights change.

Discussion in 'Editor & General Support' started by rostik1975, Sep 26, 2021.

  1. rostik1975

    rostik1975

    Joined:
    May 14, 2015
    Posts:
    44
    Hello,

    I noticed a strange behavior of skinned mesh vertices after updating mesh weights. The visible position of the vertex is not the same as the one presented in the baked mesh (and displayed in OnDrawGizmos() ).



    Code (CSharp):
    1.  
    2. Mesh resultMesh = Instantiate(bodySkin.sharedMesh);
    3. BoneWeight[] weights = resultMesh.boneWeights;
    4.  
    5. Mesh meshBeforeWeightsUpdate = new Mesh();
    6. bodySkin.BakeMesh(meshBeforeWeightsUpdate);
    7. print(meshBeforeWeightsUpdate.vertices[vertIndex].magnitude);   // 1.301173
    8.                    
    9. weights[vertIndex].weight0 = 0.627f; // set some test weight value
    10. resultMesh.boneWeights = weights;
    11. bodySkin.sharedMesh = resultMesh;
    12.                    
    13. Mesh meshAfterWeightsUpdate = new Mesh();
    14. bodySkin.BakeMesh(meshAfterWeightsUpdate);
    15. print(meshAfterWeightsUpdate.vertices[vertIndex].magnitude);    // 1.313242 - the position is changed, but not as predicted                  
    16. debugVerts.Add(bodySkin.transform.TransformPoint(meshAfterWeightsUpdate.vertices[vertIndex]));
    17.  
    18.  
    How can I get the real position of the given vertex, after the corresponding weights update, for the further calculations and for proper displaying in Gizmos?

    Is this real vertex position calculated in GPU and is not accessible in code?
    I turned off GPU Skinning in Project Settings > Player, but the result is the same.

    Thank you.
     
  2. rostik1975

    rostik1975

    Joined:
    May 14, 2015
    Posts:
    44
    Using Matrix / boneWeights calculations instead of baking the mesh, didn't help.
    The visible vertex is still not the same as the calculated one.

    Code (CSharp):
    1.     using System.Collections;
    2.     using UnityEngine;
    3.    
    4.     public class SkinnedVertices : MonoBehaviour
    5.     {
    6.         public SkinnedMeshRenderer skin;
    7.         private const int vertIndex = 7359;
    8.    
    9.         void Start()
    10.         {
    11.             StartCoroutine(UpdateWeights());
    12.         }
    13.  
    14.         private IEnumerator UpdateWeights()
    15.         {
    16.             Mesh resultMesh = Instantiate(skin.sharedMesh);
    17.             BoneWeight[] weights = resultMesh.boneWeights;
    18.            
    19.             while(true)
    20.             {
    21.                 weights[vertIndex].weight0 = 0.6f + Random.Range(0f, 0.06f);
    22.                 resultMesh.boneWeights = weights;
    23.                 skin.sharedMesh = resultMesh;
    24.                 yield return new WaitForSeconds(1.5f);
    25.             }
    26.         }
    27.        
    28.    
    29.         private void OnDrawGizmos()
    30.         {
    31.             if (Application.isPlaying)
    32.             {
    33.                 Matrix4x4[] boneMatrices = new Matrix4x4[skin.bones.Length];
    34.                 for (int i = 0; i < boneMatrices.Length; i++)
    35.                     boneMatrices[i] = skin.bones[i].localToWorldMatrix * skin.sharedMesh.bindposes[i];
    36.                 BoneWeight weight = skin.sharedMesh.boneWeights[vertIndex];
    37.  
    38.                 Matrix4x4 bm0 = boneMatrices[weight.boneIndex0];
    39.                 Matrix4x4 bm1 = boneMatrices[weight.boneIndex1];
    40.                 Matrix4x4 bm2 = boneMatrices[weight.boneIndex2];
    41.                 Matrix4x4 bm3 = boneMatrices[weight.boneIndex3];
    42.  
    43.                 Matrix4x4 vertexMatrix = new Matrix4x4();
    44.  
    45.                 for (int n = 0; n < 16; n++)
    46.                 {
    47.                     vertexMatrix[n] =
    48.                         bm0[n] * weight.weight0 +
    49.                         bm1[n] * weight.weight1 +
    50.                         bm2[n] * weight.weight2 +
    51.                         bm3[n] * weight.weight3;
    52.                 }
    53.  
    54.                 Vector3 position = vertexMatrix.MultiplyPoint3x4(skin.sharedMesh.vertices[vertIndex]);
    55.                
    56.                 Gizmos.color = Color.red;
    57.                 Gizmos.DrawSphere(position, 0.0005f);
    58.             }
    59.         }
    60.     }
    61.  
     
  3. rostik1975

    rostik1975

    Joined:
    May 14, 2015
    Posts:
    44
    In the following script we generate a new mesh based on the given SkinnedMesh, after some vertex weight is changed.
    BakeMesh() does produce wrong geometry:

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class SkinnedVertices : MonoBehaviour
    5. {
    6.     public SkinnedMeshRenderer skin;
    7.     public MeshFilter testRenderer;
    8.     private Mesh testMesh;
    9.     private const int vertIndex = 7359;
    10.  
    11.     private void Start()
    12.     {
    13.         testMesh = testRenderer.mesh;
    14.         skin.updateWhenOffscreen = true;
    15.        
    16.         Mesh resultMesh = Instantiate(skin.sharedMesh);
    17.         BoneWeight[] weights = resultMesh.boneWeights;
    18.  
    19.         weights[vertIndex].weight0 = 0.62f;
    20.         resultMesh.boneWeights = weights;
    21.         skin.sharedMesh = resultMesh;
    22.        
    23.         skin.BakeMesh(testMesh);
    24.     }
    25. }
    26.