そのため、四元数を使用して 3D 空間で 2 点のセグメントを作成し、後で同様の四元数を再計算しようとしています (空間を通る同じベクトルを表すもの。それ自体の周りのセグメントの回転は未定義であることを認識しています)。私はそのようにセグメントを作成しています:
sf::Vector3<float> Start(0, 0, 0);
sf::Vector3<float> End = Start;
//Create a vector from the start to the end
sf::Vector3<float> Translation = Orientation.MultVect(sf::Vector3<float>(0, 1, 0));
//Add that vector onto the start position
End.x += Translation.x * Length;
End.y += Translation.y * Length;
End.z += Translation.z * Length;
Orientation::MultVect() は次のようになります。
sf::Vector3<float> Quaternion::MultVect(sf::Vector3<float> Vector)
{
//From http://www.idevgames.com/articles/quaternions
Quaternion VectorQuat = Quaternion();
VectorQuat.x = Vector.x;
VectorQuat.y = Vector.y;
VectorQuat.z = Vector.z;
VectorQuat.w = 0.0;
Quaternion Inverse = (*this);
Inverse.Invert();
Quaternion Result = Inverse * VectorQuat * (*this);
sf::Vector3<float> ResultVector;
ResultVector.x = Result.x;
ResultVector.y = Result.y;
ResultVector.z = Result.z;
return ResultVector;
}
現在、この関数は他のコンテキストではかなりうまく機能しているように見えるので、ここに問題があるとは思いませんが、わかりません。また、フィードするクォータニオン if (オイラー角から構築し、他のクォータニオンとの乗算を使用することもあります) を考えると、ポイントは期待どおりの場所で終了することにも言及する必要があります。
Start
私には、問題はとからクォータニオンを再計算することにあるように見えますEnd
。そのために、この関数を使用します。これは、シーン内のオブジェクトを他のオブジェクトに向ける場合にうまく機能します (問題のオブジェクトがまったく同じ Y 軸に沿っている場合を除きます。この場合、NaN 値のクォータニオンを取得します)。これが私がそれを行う方法です:
Quaternion Quaternion::FromLookVector(sf::Vector3<float> FromPoint, sf::Vector3<float> ToPoint)
{
///Based on this post:
///http://stackoverflow.com/questions/13014973/quaternion-rotate-to
//Get the normalized vector from origin position to ToPoint
sf::Vector3<double> VectorTo(ToPoint.x - FromPoint.x,
ToPoint.y - FromPoint.y,
ToPoint.z - FromPoint.z);
//Get the length of VectorTo
double VectorLength = sqrt(VectorTo.x*VectorTo.x +
VectorTo.y*VectorTo.y +
VectorTo.z*VectorTo.z);
//Normalize VectorTo
VectorTo.x /= -VectorLength;
VectorTo.y /= -VectorLength;
VectorTo.z /= -VectorLength;
//Define a unit up vector
sf::Vector3<double> VectorUp(0, -1, 0);
//The X axis is the cross product of both
//Get the cross product as the axis of rotation
sf::Vector3<double> AxisX(VectorTo.y*VectorUp.z - VectorTo.z*VectorUp.y,
VectorTo.z*VectorUp.x - VectorTo.x*VectorUp.z,
VectorTo.x*VectorUp.y - VectorTo.y*VectorUp.x);
//Normalize the axis
//Get the length of VectorTo
double AxisXLength = sqrt(AxisX.x*AxisX.x +
AxisX.y*AxisX.y +
AxisX.z*AxisX.z);
//Normalize VectorTo
AxisX.x /= AxisXLength;
AxisX.y /= AxisXLength;
AxisX.z /= AxisXLength;
//Get the adjusted Y vector
//Get the cross product of the other two axes
sf::Vector3<double> AxisY(VectorTo.y*AxisX.z - VectorTo.z*AxisX.y,
VectorTo.z*AxisX.x - VectorTo.x*AxisX.z,
VectorTo.x*AxisX.y - VectorTo.y*AxisX.x);
//Normalize the axis
//Get the length of VectorTo
double AxisYLength = sqrt(AxisY.x*AxisY.x +
AxisY.y*AxisY.y +
AxisY.z*AxisY.z);
//Normalize VectorTo
AxisY.x /= AxisYLength;
AxisY.y /= AxisYLength;
AxisY.z /= AxisYLength;
//A matrix representing the Thing's orientation
GLfloat RotationMatrix[16] = {(float)AxisX.x,
(float)AxisX.y,
(float)AxisX.z,
0,
(float)AxisY.x,
(float)AxisY.y,
(float)AxisY.z,
0,
(float)VectorTo.x,
(float)VectorTo.y,
(float)VectorTo.z,
0,
0,
0,
0,
1};
Quaternion LookQuat = Quaternion::FromMatrix(RotationMatrix);
//Reset the quaternion orientation
return LookQuat;
}
したがって、セグメントを計算するときに、再構築された値が次のようになるかどうかも確認します。
sf::Vector3<float> Start(0, 0, 0);
sf::Vector3<float> End = Start;
//Create a vector from the start to the end
sf::Vector3<float> Translation = Orientation.MultVect(sf::Vector3<float>(0, 1, 0));
//Add that vector onto the start position
End.x += Translation.x * Length;
End.y += Translation.y * Length;
End.z += Translation.z * Length;
std::cout << "STATIC END (";
std::cout << End.x << ",";
std::cout << End.y << ",";
std::cout << End.z << ")\n";
///TEST
Quaternion Reconstructed = Quaternion::FromLookVector(Start, End);
Translation = Reconstructed.MultVect(sf::Vector3<float>(0, 1, 0));
sf::Vector3<float> TestEnd = Start;
TestEnd.x += Translation.x * Length;
TestEnd.y += Translation.y * Length;
TestEnd.z += Translation.z * Length;
std::cout << "RECONSTRUCTED END (";
std::cout << TestEnd.x << ",";
std::cout << TestEnd.y << ",";
std::cout << TestEnd.z << ")\n";
そして、両者は一致しません。たとえば、静的エンド ポイントが (0,14.3998,0.0558498) の場合、再計算されたポイントは (0,8.05585,-6.39976) になります。ただし、2つは同一である必要があります。回転の未定義部分は終点の位置を変更するべきではなく、ロール (または Z 回転、または任意の呼び方) のみを変更する必要があります。これはセグメントであるため、問題ではありません。
これを単純なセグメント以外のものに使用する場合、ロールが重要になることに注意してください。そのため、これらのセグメントに沿って配置するオブジェクトの上部が常に可能な限り上向きになるようにアップ ベクトルを使用します (真上または真下に見えるオブジェクトは、必要に応じて個別に決定される特別な任意のロールを持つことができます)。もう 1 つの目標は、複数のセグメントをつなぎ合わせて作成することです。各セグメントは、グローバル スペースに対して回転するのではなく、その前のセグメントの方向に対して回転します。
それで、私はここで何が間違っていますか?最初のクォータニオンと同じ変換を実行する 2 番目のクォータニオンを再計算できないのはなぜですか?