内插蒙皮权重

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

另一种选择是扩展您的结构以使用更多(静态八个或动态)骨骼。但这可能不值得付出努力。