Учитывая нормальную поверхность, найдите вращение для 3D Плоскости

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

Однажды один из этих детей запустит ваш скрипт с $DIRECTORY, установленным на "My M0viez", и ваш скрипт взорвется. Вы этого не хотите. Поэтому используйте это.

if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists, even if it contains spaces
fi
17
задан Adam 19 January 2010 в 20:19
поделиться

2 ответа

Некоторые полезные вещи о вращениях:

  • Любые три ортонормированных вектора, расположенных в виде строк, определяют преобразование в новый базис (вращение в этот базис).
  • Транспонирование любого вращения является его обратным.
  • Итак, любые три ортонормированных вектора, расположенных в виде столбцов, определяют поворот из некоторой основы в вашу «мировую» систему отсчета.

Итак, проблема в том, чтобы найти любой набор из трех ортонормированных векторов и расположить их как

| x1 x2 x3  0 |
| y1 y2 y3  0 |
| z1 z2 z3  0 |
|  0  0  0  1 |

, это именно то, что пытается описать описанный вами метод, если он не работает тогда есть проблема с вашей реализацией.

Очевидно, что мы можем использовать ваш нормаль как (x1, y1, z1), но проблема в том, что система имеет бесконечно много решений для оставшихся двух векторов (хотя знание одного из них дает вам другой, как перекрестное произведение). Следующий код должен дать стабильный вектор, перпендикулярный (x1, y1, z1):

float normal[3] = { ... };

int imin = 0;
for(int i=0; i<3; ++i)
    if(std::abs(normal[i]) < std::abs(normal[imin]))
        imin = i;

float v2[3] = {0,0,0};
float dt    = normal[imin];

v2[imin] = 1;
for(int i=0;i<3;i++)
    v2[i] -= dt*normal[i];

Это в основном использует ортогонализацию Грамма-Шмидта с размерностью, которая уже наиболее ортогональна нормальному вектору. Тогда v3 можно получить, взяв перекрестное произведение normal и v2.

Возможно, вам нужно будет позаботиться о настройке поворота, это касается источника, поэтому вам нужно применить перевод после поворота и для векторов столбцов, а не векторов строк. Если вы используете часы OpenGL, OpenGL принимает массивы в главном порядке столбцов (а не в главном порядке строк в C), поэтому вам может понадобиться транспонировать.

Боюсь, я не проверял вышеизложенное, я просто набрал его из некоторого кода, который я написал некоторое время назад, и адаптировал его к вашей проблеме! Надеюсь, я не забыл ни одной детали.

Редактировать: я кое-что забыл:)

В приведенной выше матрице предполагается, что нормаль к многоугольнику находится вдоль оси x, и у меня есть подозрение, что это не будет, все, что вам нужно сделать помещает «нормальный» вектор в правильный столбец матрицы вращения, а v2 / v3 - в два других столбца. Поэтому, если нормаль к вашему многоугольнику расположена вдоль оси z, то нормаль идет в 3-й столбец, а v2 / v3 - в первые два столбца.

Извините, если это вызывает путаницу.

14
ответ дан 30 November 2019 в 14:12
поделиться

Не уверены, какой метод вы используете для рендеринга, но заимствования из матрицы Openscenegraph :

void Matrix_implementation::makeLookAt(const Vec3d& eye,const Vec3d& center,const Vec3d& up)
{
    Vec3d f(center-eye);
    f.normalize();
    Vec3d s(f^up);
    s.normalize();
    Vec3d u(s^f);
    u.normalize();

    set(
        s[0],     u[0],     -f[0],     0.0,
        s[1],     u[1],     -f[1],     0.0,
        s[2],     u[2],     -f[2],     0.0,
        0.0,     0.0,     0.0,      1.0);

    preMultTranslate(-eye);
}

inline void Matrixd::preMultTranslate( const Vec3d& v )
{
    for (unsigned i = 0; i < 3; ++i)
    {
        double tmp = v[i];
        if (tmp == 0)
            continue;
        _mat[3][0] += tmp*_mat[i][0];
        _mat[3][1] += tmp*_mat[i][1];
        _mat[3][2] += tmp*_mat[i][2];
        _mat[3][3] += tmp*_mat[i][3];
    }
}

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

2
ответ дан 30 November 2019 в 14:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: