Unity3d - 如何有效地从属于另一个游戏对象的另一个类调用方法 [英] Unity3d - How to make method calling from another class that belongs to another game object efficiently

查看:23
本文介绍了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:	"+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) 第一个问题是 Highlight 实现.行 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) 你的主要问题是你在每次Update时调用Highligh.Highlight 不是一个非常简单的函数,因为在设置网格颜色时它可能需要访问 GPU 内存中的对象.Update 在每一帧上被调用.你不必在每一帧上都做 Highligh - 一旦某物被高亮,它会一直保持高亮直到unhighlighted".您可能想要调用 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:	"+bones[j].ToString());
        }

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

这篇关于Unity3d - 如何有效地从属于另一个游戏对象的另一个类调用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆