Search Unity

Skinned Mesh Combine code is very slow

Discussion in 'Scripting' started by Manimor, Dec 16, 2015.

  1. Manimor

    Manimor

    Joined:
    Sep 7, 2013
    Posts:
    21
    I'm trying to achieve runtime feasible skinned meshcombining, but it's really slow.
    I do have 431 bones (using rigify), which is probably not good, but can be optimized.
    But why does this really take so long time?
    5254 weight assignments and 431 bindpose assignments, how can this take 3.2 seconds???
    This is just unfeasible for even tens of models being generated at any time.
    Thanks for any feedback, I'm just stumped here ;/


    foreach (SkinnedMeshRenderer smr in SMRs) {

    for(int b2 = 0; b2 < smr.sharedMesh.boneWeights.Length; b2++) {
    weights[bCount[1]] = smr.sharedMesh.boneWeights[b2];
    bCount[1]++;
    }

    for(int b3 = 0; b3 < smr.sharedMesh.bindposes.Length; b3++) {
    bindPoses[bCount[2]] = smr.sharedMesh.bindposes[b3];
    bCount[2]++;
    }
    }


    --------------------------------------------------------------------
    Amount of bones for this model=431
    Amount of weights for this model=5254
    Amount of bindposes for this model=431
    Execution time for this model is -->3.164296
    --------------------------------------------------------------------
    Amount of bones for this model=431
    Amount of weights for this model=507
    Amount of bindposes for this model=431
    Execution time for this model is is -->0.07795525
    --------------------------------------------------------------------
    Amount of bones for this model=431
    Amount of weights for this model=679
    Amount of bindposes for this model=431
    Execution time for this model is is -->0.1062918
    --------------------------------------------------------------------
    Amount of bones for this model=431
    Amount of weights for this model=1074
    Amount of bindposes for this model=431
    Execution time for this model is is -->0.2017202
    --------------------------------------------------------------------

    Thanks
     
  2. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    Try this:

    Code (CSharp):
    1.  
    2.             foreach (SkinnedMeshRenderer smr in SMRs)
    3.             {
    4.                 var mesh = smr.sharedMesh;
    5.  
    6.                 var meshBoneWeights = mesh.boneWeights;
    7.                 for (int b2 = 0; b2 < meshBoneWeights.Length; b2++)
    8.                 {
    9.                     weights[bCount[1]] = meshBoneWeights[b2];
    10.                     bCount[1]++;
    11.                 }
    12.  
    13.                 var meshBindPoses = mesh.bindposes;
    14.                 for (int b3 = 0; b3 < meshBindPoses.Length; b3++)
    15.                 {
    16.                     bindPoses[bCount[2]] = meshBindPoses[b3];
    17.                     bCount[2]++;
    18.                 }
    19.             }
    20.  
     
  3. Manimor

    Manimor

    Joined:
    Sep 7, 2013
    Posts:
    21
    Thanks, I will try your contribution.

    Just wanna add that I was able to reduce it 5 fold by just changing it to
    Code (CSharp):
    1.  
    2. BoneWeight[] currentArray = new BoneWeight[0];
    3.  
    4.         foreach (SkinnedMeshRenderer smr in SMRs) {
    5.  
    6.             currentArray = combine2Array(currentArray, smr.sharedMesh.boneWeights);
    7.  
    8.             for(int b3 = 0; b3 < smr.sharedMesh.bindposes.Length; b3++) {
    9.                 bindPoses[bCount[2]] = smr.sharedMesh.bindposes[b3];    
    10.                 bCount[2]++;
    11.             }
    12.  
    13.         }
    14.         weights = currentArray;
    15.  
    16. public static T[] combine2Array<T>(T[] first,T[]last){
    17.         var z = new T[first.Length + last.Length];
    18.         first.CopyTo(z, 0);
    19.         last.CopyTo(z, first.Length);
    20.         return z;
    21.    
    22.     }
    23.  
    Such is programming! Maybe your code will increase it additionally, hopefully! ;D
    Thanks!

    Edit: Wow, yours was even quicker, thanks ;) Don't really see the epic difference between that one and the first though haha. Appreciate it!
     
    Last edited: Dec 16, 2015
  4. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    smr.sharedMesh is not a field, it's a property. So reading it is like calling a method that does something and then returns the value, and that something may take quite a while.

    skinnedMeshRenderer.boneWeights and .bindposes are also properties, so they may do something time consuming before returning a value. BTW each time you read .boneWeights or .bindposes it returns a new array filled with the exact same data. That means if the weights count is ~5000, then your original code implicitly generates ~10000 identical arrays of bone weights.
     
  5. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    is this one of the instances where a foreach is a poor choice too?
     
  6. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    Actually, something like this

    Code (CSharp):
    1.             foreach (BoneWeight bw in smr.sharedMesh.boneWeights) {
    2.                 weights[bCount[1]] = bw;
    3.                 bCount[1]++;
    4.             }
    5.  
    should work approximately as fast as my previous code using for, because it reads .sharedMesh and .boneWeights properties only once.