这是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);
}
答案 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
上致电Highligh
。 Update
不是很轻的功能,因为在设置网格颜色时可能需要访问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");
}
我希望这会引导你走向正确的方向。