Unity3d-如何有效地从属于另一个游戏对象的另一个类进行方法调用

Unity3d-如何有效地从属于另一个游戏对象的另一个类进行方法调用

问题描述:

这是此问题的连续性。

我在这里要做的是创建一个程序,根据3D模型的运动来计算一些分数并将其显示为模型颜色的变化。

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.

我想出了如下代码片段所示的解决方案,但是系统变得迟钝和冻结。我是Unity世界的新手,所以我问你们,有什么方法可以更有效地完成这种工作吗?

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?

下面是我的代码结构的详细信息,所以此问题涉及3个不同的类,彼此调用(都附加到不同的游戏对象上)

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

在这里我调用 Highlight()函数,该类将返回浮点数0-1,以确定颜色的强度。这就是我所谓的 Highlight()函数

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

该类用于获取每帧3D模型数据并将其传递给Comparator.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)第一个问题是突出显示实施。 mesh.colors32 = colors; 行不应放在其中。这样,您可以多次分配mesh.colors32,但重要的是,只有最后一次分配它,所有其他对象都将被覆盖。应该为:

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:

 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; // Finally, do it once

按照此处的建议将其制成协程,(

Making it a coroutine as it was suggested here is not needed, (and actually will make things worse).

2)您的主要问题是您呼叫 Highligh $ c每次更新中的$ c>。 Highlight 并不是很轻巧的功能,因为在设置网格颜色时可能需要访问GPU内存中的对象。在每个帧上调用更新。您不必在每个帧上都执行 Highligh -突出显示某项内容后,它将一直突出显示,直到未突出显示为止。您可能要调用 Highlight ,只有在实际发生更改的情况下。

2) Your PRIMARY PROBLEM is that you call Highligh on each Update. 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 do Highligh on every frame - once something was highlighted, it will remain highlighted until "unhighlighted". You might want to call Highlight, 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:

//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);
}

// Remember the index and ratio used last time to highlight.
private int prevIndex = -1;
private int prevRatio = -1;

// Change vertex colors highlighting given bone
public void Highlight(int index,double ratio = 1 ) 
{
    // If nothing changed, no need to highligh again - everything is already
    // highlighted. Break function execution.
    if (index == prevIndex && ratio == prevRatio) return;

    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);
            }

            //Debug.Log("bone index:\t"+bones[j].ToString());
        }

        mesh.colors32 = colors; // Finally, do it once
    } 
    else Debug.Log("smr null");
}