2016-01-21 27 views
2

这是从这个question的连续性。Unity3d - 如何使另一个类别有效地属于另一个游戏对象的方法有效

我想在这里做的是创建一个程序来计算基于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

脚本-coloring型号

这就是我所说的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

该类用于获得三维模型数据的每个帧,并把它传递给Comparator.cs用于分数计算

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

回答

1

1)第一个问题是高亮执行。行mesh.colors32 = colors;不应该在里面。这种方式可以多次分配mesh.colors32,但重要的只是最后一次分配它,其他所有的都被覆盖。应该是:

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 

制作它,因为它是在这里建议是不需要的,(实际上会使事情变得更糟)协同程序。

2)您的主要问题是你拨打Highligh每个UpdateHighlight不是一个非常轻的函数,因为它可能需要在设置网格颜色时访问GPU内存中的对象。每帧上调用Update。您不必在每一帧上都做Highligh--一旦突出显示某些内容,它会一直保持突出显示,直到“不亮”为止。只有在实际情况发生变化的情况下,您才可以致电Highlight

一个简单的方法是记住上一帧突出显示的内容,然后仅在某些内容发生变化时突出显示。例如,您的荧光笔对象可能是这样的:

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

谢谢您的回答,是的,第一个是我不好,我固定它,它的工作速度快了很多。对于第二个问题,我认为你是对的,但我怀疑通过保存我以前的状态可以解决问题,因为每一帧的比例都会发生很大的变化。我想出了几个想法,例如,在初始化时映射网格,所以我已经存储了哪个网格对应于每个骨骼,并且仅在这些网格之间进行迭代,而不是搜索整个网格。也许我会每5/10帧做一次突出显示,以使其更快 – Richard

0

1)您是否真的必须在每次更新时致电comparatorClass.GetData(frame);?如果是,那么你是否真的需要在每次更新时拨打highlighter.Highlight(highlightedRegion, cost);

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

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

进入一个协调程序,并启动该程序只有一次具体情况。例如:

public void Highlight(int index,double ratio = 1) { 
StopAllCoroutines(); // stop all co routines already running. 
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; 
default: 
    break; 
if(bones != null) 
{  
    startCoroutine(actualHighlight(bones)); 
} 

} 
Ienumrator actualHighlight(Transform[] bones) 
{ 
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; 
      yield return new WaitForEndOfFrame(); 
     } 


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

我希望这可以使您走向正确的方向。

相关问题