- Home /
The question is answered, right answer was accepted
How can I make this code more efficient?
This loops through each vertex in pieceMesh, finds the closest vertex to it in tempPieceMesh and copies its boneweights. I'm using nested for loops to go through each vertex so it takes a second or two to run through. I was hoping to be able to cut that time down as it will have to do this for a few more meshes.
Mesh pieceMesh = piece.GetComponent<SkinnedMeshRenderer>().sharedMesh;
Mesh tempPieceMesh = tempPiece.GetComponent<SkinnedMeshRenderer>().sharedMesh;
BoneWeight[] weights = tempPieceMesh.boneWeights;
// Iterate through piece's vertices, find closest vertice in tempPieceMesh and copy its boneweights
for(int i = 0; i < pieceMesh.vertexCount; i++)
{
// Check vertex distance. If there is a higher one, set verDistance to it
float checkVertDis = 0.0f;
float vertDistance = 10.0f;
for(int j = 0; j < tempPieceMesh.vertexCount; j++)
{
checkVertDis = Vector3.Distance(pieceMesh.vertices[i], tempPieceMesh.vertices[j]);
// If we find a lower distance, set vertdistance to it and copy the boneweights
if(checkVertDis < vertDistance)
{
vertDistance = checkVertDis;
weights[i] = tempPieceMesh.boneWeights[j];
}
}
}
pieceMesh.boneWeights = weights;
Edit: Here's the fixed code using @CHPedersen's advice:
Mesh pieceMesh = piece.GetComponent<SkinnedMeshRenderer>().sharedMesh;
Mesh tempPieceMesh = tempPiece.GetComponent<SkinnedMeshRenderer>().sharedMesh;
BoneWeight[] weights = tempPieceMesh.boneWeights;
BoneWeight[] newWeights = pieceMesh.boneWeights;
// Copy the positions of pieceMesh and tempPieceMesh vertices into new array to use in distance function
Vector3[] pVertices = pieceMesh.vertices;
Vector3[] tPVertices = tempPieceMesh.vertices;
// Iterate through piece's vertices, find closest vertice in tempPieceMesh and copy its boneweights
for(int i = 0; i < pieceMesh.vertexCount; i++)
{
// Check vertex distance. If there is a higher one, set verDistance to it
float checkVertDis = 0.0f;
float vertDistance = 10.0f;
for(int j = 0; j < tempPieceMesh.vertexCount; j++)
{
checkVertDis = Vector3.Distance(pVertices[i], tPVertices[j]);
// If we find a lower distance, set vertdistance to it
if(checkVertDis < vertDistance)
{
vertDistance = checkVertDis;
newWeights[i] = weights[j];
}
}
}
pieceMesh.boneWeights = newWeights;
This looks like a pure modelling thing. I mean, $$anonymous$$ax and blender do this for auto-set bone weights, probably based on a standard algorithm. I'd imagine that technical modelling forums would have more info.
@Owen Reynolds
I'm creating a system that lets you sag the character's pants at runtime using a slider and blendshapes. Here's an image showing what I was trying to achieve.
http://i.imgur.com/t2OTas9.jpg
piece is the image on the left and tempPiece is the image on the right.
The problem was that the vertices no longer deformed correctly. The vertices that were supposed to bend at the knees bent at the shins ins$$anonymous$$d. The code fixes the deformation by copying the weights of the closest vertex in tempPiece to piece but it takes a little while to go through the loops. I'm looking for ways to make it more efficient.
Answer by CHPedersen · Mar 14, 2015 at 06:02 PM
By far the worst performance drawback of that code snippet is that you're accessing Mesh.vertices inside the for-loop. That property looks innocent, but Unity is in fact instantiating and returning a deep copy every time you access it, which adds an incredibly unnecessary overhead on each access of pieceMesh.vertices[i] and tempPieceMesh.vertices[j], especially if that mesh has a lot of vertices.
Copy out the vertex arrays ONCE outside the for loop, then index into that copy to do your distance calculations.
Thank you! I edited the code in the OP with your advice.
It now takes 17 ms ins$$anonymous$$d of 3832 ms
Follow this Question
Related Questions
Increase value through frames, or in a while? 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
C# Code efficiency. 1 Answer