Интерполяция весов скиннинга

Я подразделяю треугольники сетки, и, как вы можете догадаться, мне нужны значения веса для этих новых вершин. В настоящее время я использую линейную интерполяцию (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)

person ciyo    schedule 31.07.2015    source источник
comment
Покажите немного больше контекста. В частности, как узнать, что значения неверны? Кроме того, указанная строка кода не дает достаточно информации, чтобы показать весь процесс подразделения и интерполяции.   -  person lisyarus    schedule 31.07.2015
comment
Что неверно в ваших ценностях? Я не уверен, что вы предоставили достаточно контекста для этого вопроса. Может быть, немного подробнее.   -  person zero298    schedule 31.07.2015
comment
Я добавил еще немного контекста.   -  person ciyo    schedule 31.07.2015


Ответы (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

Вы должны начать с построения таблицы совместных весов:

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

Другим вариантом было бы расширить вашу структуру, чтобы использовать больше (либо статических восьми, либо динамических) костей. Но, наверное, это не стоит усилий.

person Nico Schertler    schedule 01.08.2015
comment
Спасибо за ваш ответ, я думаю, что это может решить мою проблему. Но я не уверен, что полностью понял ваше предложение. Итак, не могли бы вы сделать это немного яснее, предоставив некоторые подробности, пожалуйста? - person ciyo; 02.08.2015