Я программирую в OpenGL и C++. Я знаю 2 точки на 1 линии (диагональная линия) и хочу повернуть объект вокруг этой диагональной линии. Как я могу это сделать? Я знаю, как использовать glrotatef
для поворота вокруг оси x, y или z, но я не уверен в этом.OpenGL Вращение объекта вокруг строки
ответ
гротат вращение вокруг ось. Одним из способов является выполнение преобразований, которые выравнивают ось вращения с одной из координатной оси, выполняют поворот, а затем инвертируют первый шаг. Если вам нужна скорость, вы можете объединить операции в специальную матрицу преобразования и применить их за один шаг. Есть описание here.
Параметры x, y и z до glRotate
могут указывать любую произвольную ось, а не только оси x, y и z. Чтобы найти ось, проходящую через вашу линию, просто вычтите конечные точки линии, чтобы получить вектор оси: если две точки: (x1, y1, z1)
и (x2, y2, z2)
, вам нужна ось (x2-x1, y2-y1, z2-z1)
.
Редактировать: Как отметил @chris_l, это работает только в том случае, если линия проходит через начало координат. Если нет, сначала примените перевод (-x1, -y1, -z1)
, чтобы линия проходила через начало координат, затем применила указанное выше вращение и перевела его обратно на (x1, y1, z1)
.
Эй, как насчет выполнения некоторых кватернионов/векторных математик? =) Я сделал это с помощью небольшой «заплаты» на моем классе Vector:
double NumBounds(double value)
{
if (fabs(value) < (1/1000000.0f))
return 0; else
return value;
}
class Vector
{
private:
double x, y, z;
public:
Vector(const Vector &v)
{
x = NumBounds(v.x); y = NumBounds(v.y); z = NumBounds(v.z);
}
Vector(double _x, double _y, double _z)
{
x = NumBounds(_x); y = NumBounds(_y); z = NumBounds(_z);
}
Vector Normalize()
{
if (Length() != 0)
return Vector(x/Length(), y/Length(), z/Length()); else
return *this;
}
double operator[](unsigned int index) const
{
if (index == 0)
return NumBounds(x); else
if (index == 1)
return NumBounds(y); else
if (index == 2)
return NumBounds(z); else
return 0;
}
void operator=(const Vector &v)
{
x = NumBounds(v.x); y = NumBounds(v.y); z = NumBounds(v.z);
}
Vector operator+(const Vector &v)
{
return Vector(x + v.x, y + v.y, z + v.z);
}
Vector operator-(const Vector &v)
{
return Vector(x - v.x, y - v.y, z - v.z);
}
double operator*(const Vector &v)
{
return NumBounds((x * v.x) + (y * v.y) + (z * v.z));
}
Vector operator*(double s)
{
return Vector(x * s, y * s, z * s);
}
Vector DotProduct(const Vector &v)
{
double k1 = (y * v.z) - (z * v.y);
double k2 = (z * v.x) - (x * v.z);
double k3 = (x * v.y) - (y * v.x);
return Vector(NumBounds(k1), NumBounds(k2), NumBounds(k3));
}
Vector Rotate(Vector &axis, double Angle)
{
Vector v = *this;
return ((v - axis * (axis * v)) * cos(angle)) + (axis.DotProduct(v) * sin(angle)) + (axis * (axis * v));
}
};
Используя этот класс, вы можете легко вращать любой вектор вокруг любого другой:
Vector a(1.0f, 0.0f, 0.0f), b(0.0f, 1.0f, 0.0f), c(0.0f, 0.0f, 0.0f);
c = a.Rotate(b, M_PI/2.0f); // rotate vector a around vector b for 90 degrees (PI/2 radians): should be Vector(0, 0, 1);
Это, конечно, работает только правильно , если ось проходит через начало координат (0, 0, 0). –
@chris_l: Спасибо, обновлено. – casablanca
@chris, это можно зафиксировать, вычитая первую точку из второй, а затем используя результат в качестве вектора оси. Работает, если они не совпадают, но тогда они не будут иметь 2 разных точки на линии –