Извлечение матрицы масштаба из матрицы вида модели

Как извлечь матрицу масштаба из матрицы вида модели? Прямо сейчас я беру длину каждого столбца, но это не получается, когда масштаб отрицательный. вот мой код:

  float xs =
            matrix[0][0] * matrix[0][1] * matrix[0][2] * matrix[0][3] < 0 ?
                    -1 : 1;
    float ys =
            matrix[1][0] * matrix[1][1] * matrix[1][2] * matrix[1][3] < 0 ?
                    -1 : 1;
    float zs =
            matrix[2][0] * matrix[2][1] * matrix[2][2] * matrix[2][3] < 0 ?
                    -1 : 1;


    glm::vec3 new_scale;
    new_scale.x =  xs* glm::sqrt(
                    matrix[0][0] * matrix[0][0] + matrix[0][1] * matrix[0][1]
                            + matrix[0][2] * matrix[0][2]);
    new_scale.y =  ys* glm::sqrt(
                    matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1]
                            + matrix[1][2] * matrix[1][2]);
    new_scale.z = zs* glm::sqrt(
                    matrix[2][0] * matrix[2][0] + matrix[2][1] * matrix[2][1]
                            + matrix[2][2] * matrix[2][2]);

Например:

float []mat={0.032254f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, -0.0052254f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.4332254f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f};

1 ответ

Решение

См. матрицы однородного преобразования. То, как вы извлекаете весы - это нормально. Так что насчет знака? Ваш текущий подход не будет работать, если ваше преобразование содержит ротации...

Другая проблема состоит в том, что вы не можете знать, какой масштаб отрицается, а какой нет, потому что, если вы отрицаете одну ось, вы можете получить тот же результат, если отрицаете любую другую и поворачиваете, чтобы соответствовать положению. Если вы отмените 2 оси, вы получите исходную матрицу с другим вращением.

Лучшее, что вы можете сделать, это обнаружить, если ваша матрица имеет инвертированную ось 1 или 3:

  1. Создать таблицу знаков для оригинальной неискаженной матрицы

    например, единичная матрица, но если у вас есть другая отправная точка, используйте это

    sz0=dot(cross(X0,Y0),Z0);
    sy0=dot(cross(Z0,X0),Y0);
    sx0=dot(cross(Y0,Z0),X0);
    

    где X0,Y0,Z0 извлекаются векторы осей из вашей начальной точки матрицы

  2. вычислить знаки для вашей текущей матрицы

    sz1=dot(cross(X1,Y1),Z1);
    sy1=dot(cross(Z1,X1),Y1);
    sx1=dot(cross(Y1,Z1),X1);
    

    где X1,Y1,Z1 извлекаются векторы осей из вашей фактической матрицы

  3. сравнить знаки и вывести, какие оси оси шкалы отрицательны

    если (sx0*sx1<0)||(sy0*sy1<0)||(sz0*sz1<0) тогда одна или все 3 оси отменяются, но вы не можете знать, какая... Кроме того, все 3 сравнения знаков должны иметь одинаковый результат.

[править1] разъяснения

  • X=(matrix[0][0],matrix[0][1],matrix[0][2])
  • dot(a,b)=a.x*b.x+a.y*b.y+a.z*b.z скалярное умножение векторов (скалярное произведение)
  • c=cross(a,b) ... c.x=a.y*b.z+a.z*b.y c.y=a.z*b.x+a.x*b.z c.z=a.x*b.y+a.y*b.x является векторным умножением (кросс-произведение)

Поэтому, когда вы вычисляете пересечение двух векторов, вы получаете вектор, перпендикулярный обоим операндам. Поскольку векторы осей матрицы должны быть перпендикулярны умножению на 2 оси, вы получите третий. Точечное произведение просто сравните, если исходная и вычисленная третья оси находятся в одном и том же направлении... Этот способ инвариантен к поворотам

Другие вопросы по тегам