内插蒙皮权重
Interpolating Skinning Weights
我正在细分网格的三角形,您可以猜到,我需要这些新顶点的权重值。目前我正在使用线性插值 (Vnew.weight[i] = (V1.weight[i] + V2.weight[i]) * 0.5
) 但是,我似乎无法获得正确的值。
您知道使用插值权重的更好解决方案吗?
编辑:
对了,我用的是LBS,用中点把一个三角形分成两个三角形。一旦从文件中读取三角形信息(我正在使用 SMD
个文件),就会完成此除法。
我认为问题出在权重上,因为在静止姿势(没有任何蒙皮)中一切都很好。但是当开始应用姿势并完成蒙皮时,会出现一些疯狂的三角形和孔洞。当我仔细观察这些 "crazy triangles" 时,它们的顶点随网格移动,但与其他顶点移动的速度不够快。
这里是分割过程的代码,以及插值顶点、法线、UV和权重
int pi=0;
while (1)
{
// Some control, and decleration
for (int w = 0; w < 3; w++)
{
// Some declerations
Vert v;
// Values are read from file into Cert v
// Using boneIndex2[] and boneWeight2[] because GLSL 1.30 does
// not support shader storage buffer object, and I need just
// 8 indices most for now.
v.boneIndex2[0] = 0;
v.boneIndex2[1] = 0;
v.boneIndex2[2] = 0;
v.boneIndex2[3] = 0;
v.boneWeight2[0] = 0;
v.boneWeight2[1] = 0;
v.boneWeight2[2] = 0;
v.boneWeight2[3] = 0;
m.vert.push_back(v);
pi++;
}
// Dividing the triangle
Vert a = m.vert[pi - 2];
Vert b = m.vert[pi - 1];
Vert v;
// Interpolate position
v.pos[0] = (a.pos[0] + b.pos[0]) / 2;
v.pos[1] = (a.pos[1] + b.pos[1]) / 2;
v.pos[2] = (a.pos[2] + b.pos[2]) / 2;
// Interpolate normal
v.norm[0] = (a.norm[0] + b.norm[0]) / 2;
v.norm[1] = (a.norm[1] + b.norm[1]) / 2;
v.norm[2] = (a.norm[2] + b.norm[2]) / 2;
// Interpolate UV
v.uv[0] = (a.uv[0] + b.uv[0]) / 2;
v.uv[1] = (a.uv[1] + b.uv[1]) / 2;
// Assign bone indices
// The new vertex should be treated by each bone of Vert a, and b
v.boneIndex[0] = a.boneIndex[0];
v.boneIndex[1] = a.boneIndex[1];
v.boneIndex[2] = a.boneIndex[2];
v.boneIndex[3] = a.boneIndex[3];
v.boneIndex2[0] = b.boneIndex[0];
v.boneIndex2[1] = b.boneIndex[1];
v.boneIndex2[2] = b.boneIndex[2];
v.boneIndex2[3] = b.boneIndex[3];
// Interpolate weights
float we[4];
we[0] = (a.boneWeight[0] + b.boneWeight[0]) / 2;
we[1] = (a.boneWeight[1] + b.boneWeight[1]) / 2;
we[2] = (a.boneWeight[2] + b.boneWeight[2]) / 2;
we[3] = (a.boneWeight[3] + b.boneWeight[3]) / 2;
// Assign weights
v.boneWeight[0] = we[0];
v.boneWeight[1] = we[1];
v.boneWeight[2] = we[2];
v.boneWeight[3] = we[3];
v.boneWeight2[0] = we[0];
v.boneWeight2[1] = we[1];
v.boneWeight2[2] = we[2];
v.boneWeight2[3] = we[3];
// Push new vertex
m.vert.push_back(v);
pi++;
// Push new faces
m.face.push_back(Face(pi - 4, pi - 1, pi - 2));
m.face.push_back(Face(pi - 4, pi - 3, pi - 1));
} // End of while(1)
您正在混合可能属于不同骨骼的权重(即如果骨骼索引不相等)。
相反,从两个顶点收集所有影响骨骼的索引。如果只有一个顶点引用任何骨骼,则使用该权重的一半。如果两个顶点都引用骨骼,请像您已经做的那样使用插值。然后,挑出权重最高的四块骨骼,重新归一化为总和为1。
这是一个例子。假设您有两个具有这些骨骼索引和权重的顶点:
v1 v2
index | weight index | weight
------+-------- ------+--------
0 | 0.2 2 | 0.1
1 | 0.5 3 | 0.6
2 | 0.1 4 | 0.2
3 | 0.2 5 | 0.1
您将从构建 table 关节权重开始:
index | weight
------+--------
0 | 0.2 / 2 = 0.1
1 | 0.5 / 2 = 0.25
2 | (0.1 + 0.1) / 2 = 0.1
3 | (0.2 + 0.6) / 2 = 0.4
4 | 0.2 / 2 = 0.1
5 | 0.1 / 2 = 0.05
按重量排序并选出四个最大的:
index | weight
------+--------
3 | 0.4 *
1 | 0.25 *
0 | 0.1 *
2 | 0.1 *
4 | 0.1
5 | 0.05
这些权重总和为 0.85。所以将权重除以 0.85 得到最终的权重和指数:
index | weight
------+--------
3 | 0.47
1 | 0.29
0 | 0.12
2 | 0.12
另一种选择是扩展您的结构以使用更多(静态八个或动态)骨骼。但这可能不值得付出努力。
我正在细分网格的三角形,您可以猜到,我需要这些新顶点的权重值。目前我正在使用线性插值 (Vnew.weight[i] = (V1.weight[i] + V2.weight[i]) * 0.5
) 但是,我似乎无法获得正确的值。
您知道使用插值权重的更好解决方案吗?
编辑:
对了,我用的是LBS,用中点把一个三角形分成两个三角形。一旦从文件中读取三角形信息(我正在使用 SMD
个文件),就会完成此除法。
我认为问题出在权重上,因为在静止姿势(没有任何蒙皮)中一切都很好。但是当开始应用姿势并完成蒙皮时,会出现一些疯狂的三角形和孔洞。当我仔细观察这些 "crazy triangles" 时,它们的顶点随网格移动,但与其他顶点移动的速度不够快。
这里是分割过程的代码,以及插值顶点、法线、UV和权重
int pi=0;
while (1)
{
// Some control, and decleration
for (int w = 0; w < 3; w++)
{
// Some declerations
Vert v;
// Values are read from file into Cert v
// Using boneIndex2[] and boneWeight2[] because GLSL 1.30 does
// not support shader storage buffer object, and I need just
// 8 indices most for now.
v.boneIndex2[0] = 0;
v.boneIndex2[1] = 0;
v.boneIndex2[2] = 0;
v.boneIndex2[3] = 0;
v.boneWeight2[0] = 0;
v.boneWeight2[1] = 0;
v.boneWeight2[2] = 0;
v.boneWeight2[3] = 0;
m.vert.push_back(v);
pi++;
}
// Dividing the triangle
Vert a = m.vert[pi - 2];
Vert b = m.vert[pi - 1];
Vert v;
// Interpolate position
v.pos[0] = (a.pos[0] + b.pos[0]) / 2;
v.pos[1] = (a.pos[1] + b.pos[1]) / 2;
v.pos[2] = (a.pos[2] + b.pos[2]) / 2;
// Interpolate normal
v.norm[0] = (a.norm[0] + b.norm[0]) / 2;
v.norm[1] = (a.norm[1] + b.norm[1]) / 2;
v.norm[2] = (a.norm[2] + b.norm[2]) / 2;
// Interpolate UV
v.uv[0] = (a.uv[0] + b.uv[0]) / 2;
v.uv[1] = (a.uv[1] + b.uv[1]) / 2;
// Assign bone indices
// The new vertex should be treated by each bone of Vert a, and b
v.boneIndex[0] = a.boneIndex[0];
v.boneIndex[1] = a.boneIndex[1];
v.boneIndex[2] = a.boneIndex[2];
v.boneIndex[3] = a.boneIndex[3];
v.boneIndex2[0] = b.boneIndex[0];
v.boneIndex2[1] = b.boneIndex[1];
v.boneIndex2[2] = b.boneIndex[2];
v.boneIndex2[3] = b.boneIndex[3];
// Interpolate weights
float we[4];
we[0] = (a.boneWeight[0] + b.boneWeight[0]) / 2;
we[1] = (a.boneWeight[1] + b.boneWeight[1]) / 2;
we[2] = (a.boneWeight[2] + b.boneWeight[2]) / 2;
we[3] = (a.boneWeight[3] + b.boneWeight[3]) / 2;
// Assign weights
v.boneWeight[0] = we[0];
v.boneWeight[1] = we[1];
v.boneWeight[2] = we[2];
v.boneWeight[3] = we[3];
v.boneWeight2[0] = we[0];
v.boneWeight2[1] = we[1];
v.boneWeight2[2] = we[2];
v.boneWeight2[3] = we[3];
// Push new vertex
m.vert.push_back(v);
pi++;
// Push new faces
m.face.push_back(Face(pi - 4, pi - 1, pi - 2));
m.face.push_back(Face(pi - 4, pi - 3, pi - 1));
} // End of while(1)
您正在混合可能属于不同骨骼的权重(即如果骨骼索引不相等)。
相反,从两个顶点收集所有影响骨骼的索引。如果只有一个顶点引用任何骨骼,则使用该权重的一半。如果两个顶点都引用骨骼,请像您已经做的那样使用插值。然后,挑出权重最高的四块骨骼,重新归一化为总和为1。
这是一个例子。假设您有两个具有这些骨骼索引和权重的顶点:
v1 v2
index | weight index | weight
------+-------- ------+--------
0 | 0.2 2 | 0.1
1 | 0.5 3 | 0.6
2 | 0.1 4 | 0.2
3 | 0.2 5 | 0.1
您将从构建 table 关节权重开始:
index | weight
------+--------
0 | 0.2 / 2 = 0.1
1 | 0.5 / 2 = 0.25
2 | (0.1 + 0.1) / 2 = 0.1
3 | (0.2 + 0.6) / 2 = 0.4
4 | 0.2 / 2 = 0.1
5 | 0.1 / 2 = 0.05
按重量排序并选出四个最大的:
index | weight
------+--------
3 | 0.4 *
1 | 0.25 *
0 | 0.1 *
2 | 0.1 *
4 | 0.1
5 | 0.05
这些权重总和为 0.85。所以将权重除以 0.85 得到最终的权重和指数:
index | weight
------+--------
3 | 0.47
1 | 0.29
0 | 0.12
2 | 0.12
另一种选择是扩展您的结构以使用更多(静态八个或动态)骨骼。但这可能不值得付出努力。