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

时间:2016-01-21 05:46:04

标签: c# unity3d 3d

这是question的连续性。

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

但是由于模型的移动记录器,得分计算和着色来自不同的游戏对象附加的类,我需要让它们相互连接以便一起工作。

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

这是我的代码结构,所以这个问题涉及3个不同的类互相调用(都附加到不同的游戏对象)

1)BoneHighlighter.cs

根据上一个问题的脚本对模型进行一些重新着色

//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()函数

的方法
//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进行分数计算

public Comparator comparatorClass = null;
void Update () 
{
    .
    .
    comparatorClass.GetData(frame);
}

2 个答案:

答案 0 :(得分:1)

1)第一个问题是Highlight实现。行"plotOptions": { "column": { pointRange: 365 * 24 * 3600 * 1000, "stacking": "normal" }, }, "xAxis": { tickInterval: 365 * 24 * 3600 * 1000, "type": "datetime", "dateTimeLabelFormats": { "year": "%Y" } } 不应该在里面。这样你就可以多次分配mesh.colors32了,但重要的只是你最后一次分配它,所有其他的都被覆盖了。应该是:

mesh.colors32 = colors;

不需要像这里建议的那样使它成为协程,(实际上会让事情变得更糟)。

2)您的主要问题是您在每个 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 上致电HighlighUpdate不是很轻的功能,因为在设置网格颜色时可能需要访问GPU内存中的对象。每帧都会调用Highlight。您无需在每个帧上执行Update - 一旦突出显示某些内容,它将一直保持突出显示,直到“未突出显示”。您可能只想在实际发生变化的情况下致电Highligh

一种简单的方法是记住前一帧中突出显示的内容,然后仅在更改内容时突出显示。例如,您的荧光笔对象可能如下所示:

Highlight

答案 1 :(得分:0)

1)您是否真的必须在每次更新时调用List<U>?如果是,那么你真的需要在每次更新时调用comparatorClass.GetData(frame);吗?

2)另一个问题在于Highlight()方法。您可能想要移动以下部分:

highlighter.Highlight(highlightedRegion, cost);

进入一个共同的例行程序,并针对特定情况启动该例行程序一次。例如:

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

我希望这会引导你走向正确的方向。