fra*_*o13 5 java lwjgl quaternions matrix-multiplication rotational-matrices
我已经花了几个星期来解决这个问题,似乎找不到合适的解决方案,需要一些建议.
我正在使用LWJGL/Java创建一个Camera类,并使用Quaternions来处理轴承(偏航),俯仰和滚转.我希望这款相机可以处理3D空间中的所有6度移动,并且可以滚动.轴承,俯仰和滚动都是四元数.我将它们乘以"变化"四元数,并从中创建一个平移矩阵.我把它放在一个浮动缓冲区中,并将模型视图矩阵乘以包含旋转矩阵的缓冲区.
我可以让轴承和俯仰旋转正常工作,但是当我实施滚动时,我遇到了问题.主要是围绕Z轴旋转(滚动)似乎不起作用.当我"滚动"相机时,它似乎绕全局Z轴而不是本地相机方向轴滚动.我通常可以让3个中的2个工作,这取决于我乘以四元数的顺序,但我不能让它们一起工作.
因为它们都是独立工作的,所以我假设我的方向方法有问题,我将它们组合起来并构建一个旋转矩阵.我在整个课程中遇到了问题,所以这里有与轮换相关的方法和声明:
private final static float DEGTORAD = (float)(Math.PI/180);
//Eye - position of the camera in the 3D world.
private Vector3f eye;
//Camera axis vectors, calculated each time reorient() is called.
//Initialized to global x, y, and z axis initially.
private Vector3f up;
private Vector3f right;
private Vector3f direction;
//Angles of rotation (in degrees)
private float pitchAngle;
private float bearingAngle;
private float rollAngle;
private Quaternion pitch;
private Quaternion bearing;
private Quaternion roll;
private FloatBuffer viewMatrixBuffer = BufferUtils.createFloatBuffer(16);
private Quaternion currentOrientation;
Run Code Online (Sandbox Code Playgroud)
...
/**
* Change the bearing (yaw)
* @param bearing delta in degrees
*/
public void bearing(float bearingDelta){
bearingAngle += bearingDelta;
if(bearingAngle > 360){
bearingAngle -= 360;
}else if(bearingAngle < 0){
bearingAngle += 360;
}
bearing.setFromAxisAngle(new Vector4f(0f, 1f, 0f, bearingAngle * DEGTORAD));
bearing.normalise();
}
/**
* Change the pitch
* @param pitch delta in degrees
*/
public void pitch(float pitchDelta){
pitchAngle += pitchDelta;
if(pitchAngle > 360){
pitchAngle -= 360;
}else if(pitchAngle < 0){
pitchAngle += 360;
}
pitch.setFromAxisAngle(new Vector4f(1f, 0f, 0f, pitchAngle * DEGTORAD));
pitch.normalise();
}
/**
* @param initialRoll
*/
public void roll(float initialRoll) {
rollAngle += initialRoll;
if(rollAngle > 360){
rollAngle -= 360;
}else if(rollAngle < 0){
rollAngle += 360;
}
roll.setFromAxisAngle(new Vector4f(0, 0, 1, rollAngle * DEGTORAD));
roll.normalise();
}
/**
* Change direction to focus on a certain point in the world
* @param eye
*/
public void lookThrough(){
reorient();
GL11.glMultMatrix(viewMatrixBuffer);
}
public void reorient(){
//Multiply in order: bearing, pitch, roll. Non-commutative!
Quaternion change = new Quaternion();
Quaternion.mul(bearing, pitch, change);
Quaternion.mul(roll, change, change);
// orient the camera...
Matrix4f rotationMatrix = getRotationMatrix(change);
//Get the looking direction
direction.x = rotationMatrix.m20;
direction.y = rotationMatrix.m21;
direction.z = rotationMatrix.m22;
//Set the position
rotationMatrix.m30 = eye.x;
rotationMatrix.m31 = eye.y;
rotationMatrix.m32 = eye.z;
rotationMatrix.m33 = 1;
rotationMatrix.invert();
rotationMatrix.store(viewMatrixBuffer);
viewMatrixBuffer.rewind();
Vector3f.cross(new Vector3f(0,1,0), direction, null).normalise(right);
Vector3f.cross(right, direction, null).normalise(up);
}
Run Code Online (Sandbox Code Playgroud)
Vector3f,Quaternion和Matrix4f都是LWJGL类,不是定制的.
所以我的问题是,给定3个四元数表示轴承,俯仰和滚动,如何修改ModelView矩阵以准确表示这些旋转?
编辑:我觉得这非常接近.请参阅RiverC评论中的Gist链接.在旋转了这么多度之后,视图会在滚动之前跳回来,然后再回到正常状态.它的要点在那里,但它仍然略有偏离.
小智 3
您以错误的顺序进行乘法。
对于两个旋转 q1 和 q2,如果 q2 跟随 q1(因为旋转通常是非交换的),则乘以 q2*q1。
在万向节式系统(例如 FPS 的控件)中,优先顺序始终是偏航、俯仰、横滚。这将建议以下数学:
roll * pitch * yaw
Run Code Online (Sandbox Code Playgroud)
作为一个java点,我建议不要为每次更新创建新的四元数,但无论如何
change = Quaternion.mul(Quaternion.mul(roll, pitch, change), yaw, change);
Run Code Online (Sandbox Code Playgroud)
如果您查看代码,第三个四元数将被结果覆盖,因此无需在每个帧/更新时重置或重新创建它。
这种旋转顺序很令人困惑,但如果你查看有关四元数的 Wiki 页面,就会发现这是一般规则。