This is the continuity from this question.
What I want to do here is to create a program to calculate some score based on the 3D model's movement and show it as a change of model's color.
But since the model's movement recorder, score calculation, and coloring are from different classes attached on different Game Object, I need to make them connect to each other to work together.
I come up with the solution like below snippet, but the system got laggy and freezing. I am new to Unity world, so I ask you guys, is there any method more efficient to do this kind of job?
Here is my code structure in detail, so this problem is involving 3 different class calling each other (all attached to different game object)
1) BoneHighlighter.cs
to do some re-coloring on the model based on script from previous question
//declare SkinnedMeshRenderer
public SkinnedMeshRenderer smr;
//initialization
//previously put the initialization on Start(), but I try to put it on Awake() to make the initialization a bit sooner
void Awake ()
{
if (smr == null) smr = GetComponent<SkinnedMeshRenderer>();
smr.sharedMesh = (Mesh)Instantiate(smr.sharedMesh);
}
// Change vertex colors highlighting given bone
public void Highlight(int index,double ratio = 1 )
{
Transform[] bones = null;
switch (index)
{
case (int)Skeleton.Head: bones = head; break;
case (int)Skeleton.UpperBody: bones = upperBody; break;
case (int)Skeleton.LowerBody: bones = lowerBody; break;
case (int)Skeleton.RightUpperArm: bones = upperArmRight; break;
case (int)Skeleton.RightLowerArm: bones = lowerArmRight; break;
case (int)Skeleton.RightHand: bones = handRight; break;
case (int)Skeleton.LeftUpperArm: bones = upperArmLeft; break;
case (int)Skeleton.LeftLowerArm: bones = lowerArmLeft; break;
case (int)Skeleton.LeftHand: bones = handLeft; break;
case (int)Skeleton.RightUpperLeg: bones = upperLegRight; break;
case (int)Skeleton.RightLowerLeg: bones = lowerLegRight; break;
case (int)Skeleton.RightFoot: bones = footRight; break;
case (int)Skeleton.LeftUpperLeg: bones = upperLegLeft; break;
case (int)Skeleton.LeftLowerLeg: bones = lowerLegLeft; break;
case (int)Skeleton.LeftFoot: bones = footLeft; break;
default: break;
}
//Debug.Assert(smr != null);
if (smr != null)
{
var mesh = smr.sharedMesh;
var weights = mesh.boneWeights;
var colors = new Color32[weights.Length];
var sums = new float[weights.Length];
for (int j= 0; j<bones.Length; j++)
{
var idx = GetBoneIndex (bones [j]);
for (int i = 0; i < colors.Length; ++i)
{
float sum = 0;
if (weights [i].boneIndex0 == idx && weights [i].weight0 > 0)
sum += weights [i].weight0;
if (weights [i].boneIndex1 == idx && weights [i].weight1 > 0)
sum += weights [i].weight1;
if (weights [i].boneIndex2 == idx && weights [i].weight2 > 0)
sum += weights [i].weight2;
if (weights [i].boneIndex3 == idx && weights [i].weight3 > 0)
sum += weights [i].weight3;
sums [i] += sum;
colors [i] = Color32.Lerp (regularColor, highlightColor, sums [i] * (float)ratio);
mesh.colors32 = colors;
}
//Debug.Log("bone index:\t"+bones[j].ToString());
}
}
else Debug.Log("smr null");
}
2) Comparator.cs
This is where I call Highlight()
function, this class will return float number 0-1 to determine the intensity of the color. This is how I call the Highlight()
function
//declare highlighter class as public variable
//drag & drop GameObject containing BoneHighlighter.cs from property inspector
public BoneHighlighter highlighter = null;
//calculate a score and pass it to highlight() function
private void calculateScore(int data)
{
.
.
highlighter.Highlight(highlightedRegion, cost);
}
//get the data from other game object
public void GetData(Frame frame)
{
calculateScore((int)Skeleton.RightHand);
}
3) Manager.cs
This class is used to get a 3D model data each frame and pass it to Comparator.cs for score calculation
public Comparator comparatorClass = null;
void Update ()
{
.
.
comparatorClass.GetData(frame);
}
1) First problem is with Highlight implementation. The line
mesh.colors32 = colors;
should not be inside for. This way you assign mesh.colors32 multiple times, but what matters is only the last time you assign it, all others are overwritten. Should be:Making it a coroutine as it was suggested here is not needed, (and actually will make things worse).
2) Your PRIMARY PROBLEM is that you call
Highligh
on eachUpdate
.Highlight
is not a very light function since it might need to access objects inside GPU memory when setting mesh colors.Update
is called on each frame. You don't have to doHighligh
on every frame - once something was highlighted, it will remain highlighted until "unhighlighted". You might want to callHighlight
, only if something actually changed.A simple way to do it is to remember what was highlighted on previous frame, and then highlight only if something changed. For example, your highlighter object may look like this:
1) Do you really have to call the
comparatorClass.GetData(frame);
on every update? if yes, then do you really need to callhighlighter.Highlight(highlightedRegion, cost);
on every update?2) The other problem lies in the Highlight() method. You may want to move the following part:
into a co-routine and start that co routine only once for specific case. fo eg:
I hope this steers you into the right direction.