C++ 从四元数计算向量有效,从向量计算四元数无效

C++ 从四元数计算向量有效,从向量计算四元数无效,c++,math,3d,rotation,quaternions,C++,Math,3d,Rotation,Quaternions,所以我用一个四元数在3D空间中创建了一个由两个点组成的线段,并尝试在以后重新计算一个类似的四元数(一个表示空间中的同一向量;我知道线段围绕自身的旋转是未定义的)。我正在创建这样的细分市场: sf::Vector3<float> Start(0, 0, 0); sf::Vector3<float> End = Start; //Create a vector from the start to the end sf::Vector3<float> Transl

所以我用一个四元数在3D空间中创建了一个由两个点组成的线段,并尝试在以后重新计算一个类似的四元数(一个表示空间中的同一向量;我知道线段围绕自身的旋转是未定义的)。我正在创建这样的细分市场:

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;
因此,当我计算线段时,我还检查它们的重构值,如下所示:

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;
}
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";
sf::Vector3开始(0,0,0);
sf::Vector3结束=开始;
//从起点到终点创建一个向量
sf::Vector3 Translation=Orientation.MultVect(sf::Vector3(0,1,0));
//将该向量添加到起始位置
End.x+=平移.x*长度;
End.y+=平移.y*长度;
End.z+=平移.z*长度;

我不完全确定你是如何计算两个向量之间的“旋转”四元数的,但我很确定这很麻烦。至少,如果我理解正确的话,你有指向某个方向的“看”向量,对象从原点(0,0,0)沿该方向“看”,对吗

如果是这样的话,应该不会太难。但有一件事我觉得很奇怪,四元数向量乘法的顺序似乎是相反的。我将四元数*向量定义为:

quat qt = *this * quat(0, vec.x, vec.y, vec.z) * inverse();
return vec3(qt.x, qt.y, qt.z);
其中quat构造函数被定义为quat(w,x,y,z),inverse()方法返回一个副本。逆等于共轭,定义为(w,-x,-y,-z)。但是,要做到这一点,你的四元数必须被规范化,只有这样它们才能真正代表一个方向(只有这样,倒数才会等于共轭数)。然后我有四元数乘法的定义如下:

// This describes A * B (not communative!)
w = A.w * B.w - A.x * B.x - A.y * B.y - A.z * B.z;
x = A.w * B.x + A.x * B.w + A.y * B.z - A.z * B.y;
y = A.w * B.y + A.y * B.w + A.z * B.x - A.x * B.z;
z = A.w * B.z + A.z * B.w + A.x * B.y - A.y * B.x;
有了它,您就可以从“角度轴”构造一个四元数了。这意味着它应该有一个旋转轴和一个围绕该轴旋转的角度(弧度)。我将给你这个算法,因为它在直觉上没有多大意义:

// if axis is already unit length, remove the division
double halfAngle = angle * 0.5f; // In radians
double scale = sin(halfAngle) / axis.magnitude();

w = cos(halfAngle);
x = axis.x * scale;
y = axis.y * scale;
z = axis.z * scale;
现在我们只需要计算一个旋转的轴,以及我们想要旋转多少,以弧度为单位。乍一看,这可能看起来很复杂,但这只是理解正在发生什么的一个例子。你有两个向量,A和B。你要计算一个四元数,它描述了从A到B的旋转。要得到旋转轴,我们只需要一个垂直于两者的轴,显然这可以通过取叉积来完成。如果您使用右手坐标系,它将是:

axis = A × B
如果你使用左手坐标系,我认为你应该颠倒顺序,但不要相信我的话。现在得到两个向量之间的角度。这可以非常简单地通过点积来实现。唯一需要注意的是,必须规范化两个向量,使它们的长度为1,并且不会改变点积的结果。这样,点积将返回角度的余弦,因此要获得实际角度,我们可以执行以下操作:

angle = acos(normalize(A) * normalize(B))
乘法符号当然代表点积。现在我们在我上面给你们的算法中插入轴和角度,我们有一个四元数,描述从看向量a到看向量B的“旋转”。现在如果向量指向完全相同的方向,应用算法是不明智的,因为轴将是(0,0,0)。如果你看一下这个算法,我希望你能看到它要么尝试除以零,要么只是输出全零。所以,每当我应用这个算法时,我首先检查轴是否不是全零

我觉得你现在使用的公式很奇怪,效率也很低。我也不明白你为什么要先计算一个矩阵,从一个矩阵计算一个四元数是一个相当昂贵的计算。事实上,我相信用四元数计算相反的矩阵会更快


不管怎样,祝你好运

四元数乘法不能进行交换。四元数是相对变换(不是绝对变换)。最后,您需要进一步缩小代码的范围:仅仅因为代码可能是自一致的,并不意味着它就是您想要的。事实证明,您的评论帮助我发现我在代码的其他地方犯了错误。我在上面粘贴的Quaternion::FromLookVector()函数是用来获取两点之间的四元数,而不是两个向量,即从单个向量;但当然,由于四元数只是相对变换,我需要假设一个默认的外观向量,以便使四元数像绝对变换一样工作。我一直在假设错误的默认外观向量。我将考虑您的建议来改进性能;之前的调查表明,用预定义的上方向向量从头开始构建四元数最好通过在矩阵表示之间进行转换来完成,尽管我欢迎更快的方法。感谢您抽出时间回复!就我个人而言,我认为上方向的做事方式已经相当过时了。四元数通常用于“动态”旋转,其中没有固定的此类参数,因此不会出现意外错误(例如,沿上方向向量直视是有害的)。此外,您还可以使用纯四元数和叉积等生成相机系统的精确副本,而无需使用任何类型的固定向量。所有您需要的是一个预定义的默认外观向量,即您的起始方向。我建议您在程序中将其定义为const(或类似),祝您好运!对于我正在构建的引擎类型的东西,我实际上实现了一个基于四元数的定向系统。我存储每个节点的比例、位置和方向,然后计算它们的最终节点世界矩阵,因此我只需将该矩阵乘以摄影机矩阵即可进行渲染。你需要更多的内存来存储所有的数据,但是它非常灵活,在某些情况下你甚至可以省去一些计算。如果你想的话,我可以在pastebin或类似的东西上抛出一些算法;)
angle = acos(normalize(A) * normalize(B))