Промежуточное звено между двумя кватернионамиC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Промежуточное звено между двумя кватернионами

Сообщение Anonymous »

В приведенных ниже фрагментах кода vec4 — это просто псевдоним для std::array, где индекс 0 — это x, 1 — это y, 2 — это z, а 3 — это w.
Я хочу найти промежуточный q3, такой, что q3 = q1 + (q2 - q1)*ratio, где отношение — это произвольное число с плавающей запятой между 0 и 1.
Сначала я по наивности сделал следующее:

Код: Выделить всё

q3 = {
q1[0] + (q2[0] - q1[0])*ratio,
q1[1] + (q2[1] - q1[1])*ratio,
q1[2] + (q2[2] - q1[2])*ratio,
q1[3] + (q2[3] - q1[3])*ratio,
};
Затем я просто применил найденную мной функцию SLERP, чтобы получить «взвешенное среднее значение»:

Код: Выделить всё

// from https://github.com/MartinWeigel/Quaternion/blob/master/Quaternion.c
vec4 quaternionSlerp(vec4 q1, vec4 q2, float t)
{
// Based on http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/index.htm
float cosHalfTheta = q1[3]*q2[3] + q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2];

// if q1=q2 or q1=-q2 then theta = 0 and we can return q1
if (std::fabs(cosHalfTheta) >= 1.0F) {
return q1;
}

float halfTheta = std::acos(cosHalfTheta);
float sinHalfTheta = std::sqrt(1.0F - cosHalfTheta*cosHalfTheta);

// If theta = 180 degrees then result is not fully defined
// We could rotate around any axis normal to q1 or q2
if (std::fabs(sinHalfTheta) < 1e-4F) {
return {
q1[0] * 0.5F + q2[0] * 0.5F,
q1[1] * 0.5F + q2[1] * 0.5F,
q1[2] * 0.5F + q2[2] * 0.5F,
q1[3] * 0.5F + q2[3] * 0.5F
};
}
else {
// Default quaternion calculation
float ratioA = std::sin((1.0F - t) * halfTheta) / sinHalfTheta;
float ratioB = std::sin(t * halfTheta) / sinHalfTheta;

return {
q1[0] * ratioA + q2[0] * ratioB,
q1[1] * ratioA + q2[1] * ratioB,
q1[2] * ratioA + q2[2] * ratioB,
q1[3] * ratioA + q2[3] * ratioB
};
}
}

q3 = quaternionSlerp(q1, q2, ratio);
Покопавшись еще немного, я обнаружил, что, чтобы получить сумму двух кватернионов, вы их умножаете, а для получения разницы между двумя кватернионами вы умножаете один на сопряженное/обратное значение другого, поэтому я попробовал это:

Код: Выделить всё

vec4 multiplyQuaternions(vec4 q1, vec4 q2)
{
float w1 = q1[3], x1 = q1[0], y1 = q1[1], z1 = q1[2];
float w2 = q2[3], x2 = q2[0], y2 = q2[1], z2 = q2[2];

return {
w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2,  // X
w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2,  // Y
w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2,  // Z
w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2   // W
};
}

vec4 intermediateQuaternion(vec4 q1, vec4 q2, float ratio)
{
float cosHalfTheta = q1[3]*q2[3] + q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2];
float halfTheta = std::acos(cosHalfTheta);
float sinHalfTheta = std::sqrt(1.0F - cosHalfTheta*cosHalfTheta);

ratio = std::sin(ratio * halfTheta) / sinHalfTheta;

vec4 qDifference = multiplyQuaternions(q1, { -q2[0], -q2[1], -q2[2], q2[3] });
return multiplyQuaternions(q1, { qDifference[0]*ratio, qDifference[1]*ratio, qDifference[2]*ratio, qDifference[3]*ratio });
}

q3 = intermediateQuaternion(q1, q2, ratio);
Я также попробовал несколько вариантов функции промежуточного кватерниона, но, поскольку я толком не знаю, что делаю, я не добился лучших результатов.
Похоже, ничего из этого не дало желаемого результата. Как правильно рассчитать это «промежуточное» значение?

Подробнее здесь: https://stackoverflow.com/questions/797 ... uaternions
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»