插值皮肤重量

时间:2015-07-31 16:21:27

标签: opengl interpolation skinning

我正在细分网格的三角形,正如你猜测的那样,我需要这些新顶点的权重值。目前我正在使用线性插值(Vnew.weight[i] = (V1.weight[i] + V2.weight[i]) * 0.5),但似乎我无法获得正确的值。

您是否知道使用插值权重的更好解决方案?

编辑:

正确的知道,我正在使用LBS,并通过取中间点将一个三角形分成两个三角形。一旦从文件中读取三角形信息(我使用SMD文件),就会完成此除法。

我认为问题是权重因为,在休息姿势(没有任何皮肤)一切都很好。但是当姿势开始应用并且完成蒙皮时,会出现一些疯狂的三角形和洞。当我仔细观察这些“疯狂三角形”时,它们的顶点随着网格一起移动,但与其他顶点不够快。

这是分割过程的代码,并插入顶点,法线,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 个答案:

答案 0 :(得分:2)

您正在混合可能属于不同骨骼的权重(即,如果骨骼索引不相等)。

相反,从两个顶点收集所有影响骨骼的索引。如果只有一个顶点指向任何骨骼,请使用此重量的一半。如果两个顶点都引用骨骼,请使用插补方法。然后,选择具有最高权重的四个骨骼并重新标准化为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

首先要构建关节权重表:

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

对wrt权重进行排序并挑选四个最大值:

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

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