我正在制作变形目标动画。
我正试图找到加速3D WPF中网格点计算的方法。
所以我有两个网格 - 一个'当前'网格,它保持游戏状态和'变形'网格,我需要计算它们之间的差异。
我正在尝试使用并行for循环,但它不断抛出错误:
类型'System.InvalidOperationException'的第一次机会异常 发生在WindowsBase.dll类型的第一次机会异常 首先在mscorlib.dll中发生'System.InvalidOperationException' 发生了'System.AggregateException'类型的机会异常 mscorlib.dll其他信息:发生了一个或多个错误。
程序'[7444] HelixTrial.vshost.exe'已退出,代码为-1 (0xFFFFFFFF的)。
我的代码非常简单。它创建一个列表,计算当前网格中的位置(等于目标变形网格)。然后它在网格上循环,通过Vector3D找到位置的差异。然后它应该将矢量添加到列表中。
List<Vector3D> listVectors = new List<Vector3D>();
int i = currentMesh.Positions.Count;
Parallel.For(0, i, thisloop =>
{
Point3D mor = morphMesh.Positions[thisloop];
Point3D cur = currentMesh.Positions[thisloop];
Vector3D foo = mor - cur;
listVectors.Add(foo);
});
对我来说看起来没问题,但是不起作用。是否有可能无法在并行循环中使用Point3D?
非常感谢。
修改
这是为了展示'morphMesh'是如何制作的以及它来自何处。
morphMesh取自我的人体模型的变形目标中的一组(导入的.OBJ格式)。我只是动画网格的一部分。所以我通过抓住变形目标模型的孩子来获得我感兴趣的网格组。
var lipsmorph = morph.Children[21];
morphgeometry = (GeometryModel3D)lipsmorph;
morphMesh = (MeshGeometry3D)morphgeometry.Geometry;
所以正在做的是获取变形目标模型的嘴唇组,这被识别为21的子索引中的组。然后它将其变成网格,以便我可以使用它来计算坐标差异并操纵实时“当前”模型中的相应网格。我也使用权重,但我试图将我的示例代码保持在最低限度,以便首先使用网格差异。权重是简单的数学,所以不应该像我在这里问的那样提出问题。
编辑两个
首先使用Scott的代码并冻结模型 - 这将起作用。但对我来说这不值得追求,因为运行此代码需要与非并行解决方案相同的时间用于我的所有计算,例如权重。斯科特在他的一条评论中提到了这一点。我只是没有做足够的数学来发挥作用。
但无论如何,也许对于其他人的参考,我会发布最终停止抛出错误的代码。
i = currentMesh.Positions.Count;
List<Vector3D> listVectors = new List<Vector3D>();
morphMesh.Freeze();
currentMesh.Freeze();
try
{
Parallel.For(0, i,
() => new List<Vector3D>(), //Create a thread local list per thread
(thisloop, loopstate, localList) => //"localList" is the variable we created above or was the list that was returned from a previous loop iteration.
{
Point3D mor = morphMesh.Positions[thisloop];
Point3D cur = currentMesh.Positions[thisloop];
Vector3D foo = mor - cur;
localList.Add(foo);
return localList; //This hands the list off to be the input "localList" variable for the next thread that uses it.
},
localList => //Combine the thread local lists in to the master list in a thread safe way.
{
lock (listVectors)
listVectors.AddRange(localList);
});
}
catch (AggregateException b)
{
data.Text = b.InnerException.ToString();
}
答案 0 :(得分:2)
listVectors
不是线程安全的,因此您无法从多个线程访问它。在处理列表时,您必须使用线程本地对象或线程安全集合。
以下是使用Parallel.For
的{{3}}的线程本地版本。
int i = currentMesh.Positions.Count;
List<Vector3D> listVectors = new List<Vector3D>();
Parallel.For(0, i,
() => new List<Vector3D>(), //Create a thread local list per thread
(thisloop, loopstate, localList) => //"localList" is the variable we created above or was the list that was returned from a previous loop iteration.
{
Point3D mor = morphMesh.Positions[thisloop];
Point3D cur = currentMesh.Positions[thisloop];
Vector3D foo = mor - cur;
localList.Add(foo);
return localList; //This hands the list off to be the input "localList" variable for the next thread that uses it.
},
localList => //Combine the thread local lists in to the master list in a thread safe way.
{
lock(listVectors)
listVectors.AddRange(localList);
});
然而正如我在你的问题中所做的评论所暗示的那样,我认为你可能没有在你的循环中做足够的工作,而且一些管理费用可能会损害潜在的表现。看this overload我推荐并特别注意第28页上的“太精细颗粒,过度粗糙”的反模式示例。
答案 1 :(得分:1)
使用linq的AsParallel:
listVectors.AddRange(Enumerable.Range(0, currentMesh.Positions.Count)
.AsParallel()
.Select(thisloop => morphMesh.Positions[thisloop] - currentMesh.Positions[thisloop]));