我猜Quaternion.mul()
是乘法?我认为你需要做的不仅仅是一个乘法来进行旋转。这是我用于围绕轴角(四元数)旋转矢量或点的代码:
private double[] vecQuat = new double[4];
private double[] resQuat = new double[4];
private double[] thisQuat = new double[4];
private double[] conj = new double[4];
/**
* Rotates a vector (or point) around this axis-angle
*
* @param vectorX the x component of the vector (or point)
* @param vectorY the y component of the vector (or point)
* @param vectorZ the z component of the vector (or point)
* @param outputArray the array in which the results will be stored
*/
public void RotateVector(double vectorX, double vectorY, double vectorZ, double[] outputArray){
vecQuat[0] = 0.0f;
vecQuat[1] = vectorX;
vecQuat[2] = vectorY;
vecQuat[3] = vectorZ;
thisQuat[0] = w;
thisQuat[1] = x;
thisQuat[2] = y;
thisQuat[3] = z;
getConjugate(conj);
Multiply(vecQuat,conj,resQuat);
Multiply(thisQuat,resQuat,vecQuat);
outputArray[0] = vecQuat[1];
outputArray[1] = vecQuat[2];
outputArray[2] = vecQuat[3];
}
public void getConjugate(double[] outputArray){
outputArray[0] = w;
outputArray[1] = -x;
outputArray[2] = -y;
outputArray[3] = -z;
}
public void Multiply(double[] aq, double[] rq, double[] outputArray){
outputArray[0] = aq[0] * rq[0] - aq[1] * rq[1] - aq[2] * rq[2] - aq[3] * rq[3];
outputArray[1] = aq[0] * rq[1] + aq[1] * rq[0] + aq[2] * rq[3] - aq[3] * rq[2];
outputArray[2] = aq[0] * rq[2] + aq[2] * rq[0] + aq[3] * rq[1] - aq[1] * rq[3];
outputArray[3] = aq[0] * rq[3] + aq[3] * rq[0] + aq[1] * rq[2] - aq[2] * rq[1];
}
我不知道 libgdx,但也许看看它是否有像上面那样的旋转功能。如果没有,您可能可以将其添加到
编辑:
我不知道你想用相机做什么,但这里有一个例子,我使用四元数来设置太空中的 RTS 游戏(想想 homeworld)。宇宙飞船有一个direction vector
(它们行进的方向),用于在每个滴答声中更新它们的运动并将它们旋转到朝向行进方向(在draw()
函数中)。他们还有一个target vector
: 在船的位置和它的当前目的地之间。船只能以turningCircle
弧度转动一秒钟。因此,在每个刻度更新运动后,我将方向/目标向量的叉积作为旋转轴,并turningCircle
作为角度,创建一个四元数。我通过四元数旋转船舶方向矢量以“转动”船舶。
最终的结果是船经过了许多滴答声,以优美的弧线转弯,直到它朝着正确的方向前进。
同样的过程也可以在战斗飞行模拟器中使用,以模拟人工智能飞机的转弯。使用四元数还可以避免“万向节锁定”,这是真正的飞机会遇到的问题!
然而,使用四元数,你的 AI 飞机可能会发现倒挂飞行一半时间更方便,所以你可能不得不让飞机沿着机身轴(即 z 轴)进行一些额外的缓慢旋转,以模拟飞行员将自己定位到“向上”。这实际上很容易做到,只需在正向(方向)向量上添加一个直角的向上和向右向量
这是代码(减去向上矢量位的定向):
/**
* The current position of the spaceship
*/
private Vertex3D currentPosition;
/**
* The target position of the spaceship
*/
private Vertex3D targetPosition;
/**
* The current direction in which the spaceship is travelling
*/
private Vector directionVector;
/**
* The vector towards which the spaceship is turning
*/
private Vector targetVector;
/**
* The right orientation vector
*/
private Vector rightOrientationVector;
/**
* The up orientation vector
*/
private Vector upOrientationVector;
/**
* Angle in radians by which directionVector turns towards TargetVector every tick
*/
private double turningCircle = 0.05f;
public Spaceship(Vertex3D target){
currentPosition = new Vertex3D(0,0,0);
// right hand coordinate system: ship is facing "away" from the camera
directionVector = new Vector(currentPosition, 0,0,-1);
rightOrientationVector = new Vector(currentPosition, 1,0,0);
upOrientationVector = new Vector(currentPosition, 0,1,0);
targetPosition = target;
}
protected void tick(){
incrementPosition();
turn();
draw();
}
protected void incrementPosition(){
// get movement
double velocity = getVelocity();
// move
currentPosition.mX(currentPosition.mX + directionVector.mX * velocity);
currentPosition.mY(currentPosition.mY + directionVector.mY * velocity);
currentPosition.mZ(currentPosition.mZ + directionVector.mZ * velocity);
}
private double[] cross = new double[3];
private double[] newDir = new double[3];
private Quaternion quat;
protected void turn(){
// update target vector relative to new position
setTargetVector();
// turn direction vector towards target vector
MathsExtras.crossProduct(directionVector.mX, directionVector.mY, directionVector.mZ, targetVector.mX, targetVector.mY, targetVector.mZ, cross);
quat = new Quaternion(cross[0], cross[1], cross[2], turningCircle);
quat.RotateVector(directionVector.mX, directionVector.mY, directionVector.mZ, newDir);
directionVector.mX = newDir[0];
directionVector.mY = newDir[1];
directionVector.mZ = newDir[2];
direction.normalise();
// update right orientation
MathsExtras.crossProduct(direction.mX, direction.mY, direction.mZ, upOrientationVector.mX, upOrientationVector.mY, upOrientationVector.mZ, cross);
rightOrientationVector.mX = cross[0];
rightOrientationVector.mY = cross[1];
rightOrientationVector.mZ = cross[2];
rightOrientationVector.normalise();
// update up orientation
MathsExtras.crossProduct(rightOrientationVector.mX, rightOrientationVector.mY, rightOrientationVector.mZ, direction.mX, direction.mY, direction.mZ, cross);
upOrientationVector.mX = cross[0];
upOrientationVector.mY = cross[1];
upOrientationVector.mZ = cross[2];
upOrientationVector.normalise();
}
protected void setTargetVector(){
targetVector.mX = targetPosition.getmX() - currentPosition.getmX();
targetVector.mY = targetPosition.getmY() - currentPosition.getmY();
targetVector.mZ = targetPosition.getmZ() - currentPosition.getmZ();
targetVector.normalise();
}
因此,如果您想使用相同的代码来说明在第一人称射击游戏中转动相机以查看对象,您可以将方向向量设置为玩家正在注视的方向,并将 currentPosition 设置为玩家/相机位置,目标作为目标对象,而 turningCirlce 为角度/您希望相机转动的速度。在draw()
你只会使用lookAt(directionVector.mX + currentPosition.mX, directionVector.mY + currentPosition.mY, directionVector.mZ + currentPosition.mZ)