我對OpenGL和3D編程相當陌生,但是我已經開始使用基於http://www.cprogramming.com/tutorial/3d/quaternions.html教程的四元數實現相機旋轉。這全部用Java編寫,使用JOGL。OpenGL中的3D相機旋轉:如何防止相機抖動?
我意識到這些類型的問題會被問到很多,但我一直在四處搜尋,找不到可行的解決方案,因此我認爲這可能是我的代碼特有的問題。
所以問題是如果我在一個或多個軸上做兩個不同的連續旋轉,會出現抖動和奇數旋轉。沿着一個軸的第一次旋轉,無論是消極的還是積極的,都可以正常工作。但是,如果我沿着一個軸正向旋轉,然後在該軸上進行負向旋轉,那麼旋轉會來回抖動,就好像它在進行正旋轉和負旋轉之間進行交替一樣。
如果我自動旋轉(例如,左旋500次然後右旋500次),那麼它看起來工作正常,這使我認爲這可能與按鍵有關。但是,如果我圍繞x軸旋轉,然後圍繞y軸旋轉,旋轉也是不正確的(因爲缺少更好的單詞)。
無論如何,我有具有以下顯示環中的渲染器類用於繪製`場景節點:在相機類如下進行
private void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(70, Constants.viewWidth/Constants.viewHeight, 0.1, 30000);
gl.glScalef(1.0f, -1.0f, 1.0f); //flip the y axis
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
camera.rotateCamera();
glu.gluLookAt(camera.getCamX(), camera.getCamY(), camera.getCamZ(), camera.getViewX(), camera.getViewY(), camera.getViewZ(), 0, 1, 0);
drawSceneNodes(gl);
}
private void drawSceneNodes(GL2 gl) {
if (currentEvent != null) {
ArrayList<SceneNode> sceneNodes = currentEvent.getSceneNodes();
for (SceneNode sceneNode : sceneNodes) {
sceneNode.update(gl);
}
}
if (renderQueue.size() > 0) {
currentEvent = renderQueue.remove(0);
}
}
旋轉:
public class Camera {
private double width;
private double height;
private double rotation = 0;
private Vector3D cam = new Vector3D(0, 0, 0);
private Vector3D view = new Vector3D(0, 0, 0);
private Vector3D axis = new Vector3D(0, 0, 0);
private Rotation total = new Rotation(0, 0, 0, 1, true);
public Camera(GL2 gl, Vector3D cam, Vector3D view, int width, int height) {
this.cam = cam;
this.view = view;
this.width = width;
this.height = height;
}
public void rotateCamera() {
if (rotation != 0) {
//generate local quaternion from new axis and new rotation
Rotation local = new Rotation(Math.cos(rotation/2), Math.sin(rotation/2 * axis.getX()), Math.sin(rotation/2 * axis.getY()), Math.sin(rotation/2 * axis.getZ()), true);
//multiply local quaternion and total quaternion
total = total.applyTo(local);
//rotate the position of the camera with the new total quaternion
cam = rotatePoint(cam);
//set next rotation to 0
rotation = 0;
}
}
public Vector3D rotatePoint(Vector3D point) {
//set world centre to origin, i.e. (width/2, height/2, 0) to (0, 0, 0)
point = new Vector3D(point.getX() - width/2, point.getY() - height/2, point.getZ());
//rotate point
point = total.applyTo(point);
//set point in world coordinates, i.e. (0, 0, 0) to (width/2, height/2, 0)
return new Vector3D(point.getX() + width/2, point.getY() + height/2, point.getZ());
}
public void setAxis(Vector3D axis) {
this.axis = axis;
}
public void setRotation(double rotation) {
this.rotation = rotation;
}
}
方法rotateCamera從新的旋轉和先前的旋轉生成新的四元數,而rotatePoint方法僅將點與由四元數生成的旋轉矩陣相乘。
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
camera.setAxis(new float[] {1, 0, 0});
camera.setRotation(0.1f);
}
if (e.getKeyCode() == KeyEvent.VK_A) {
camera.setAxis(new float[] {0, 1, 0});
camera.setRotation(0.1f);
}
if (e.getKeyCode() == KeyEvent.VK_S) {
camera.setAxis(new float[] {1, 0, 0});
camera.setRotation(-0.1f);
}
if (e.getKeyCode() == KeyEvent.VK_D) {
camera.setAxis(new float[] {0, 1, 0});
camera.setRotation(-0.1f);
}
}
我希望我提供足夠的細節:
旋轉軸線和旋轉角是由簡單的按鍵設定如下。任何幫助將非常感激。
SceneRenderer類實現GLEventListener,它包含調用render()以及render loop的display(GLAutoDrawable drawable)。應用程序的模型端只傳遞更新事件,然後存儲在渲染隊列中。對不起,不清楚。 Camera類已經存儲了眼睛的位置以及它在看什麼(我將把代碼添加到原始文章中)。 至於定義向上方向的向量。這是否需要改變相機旋轉?我假設在旋轉凸輪的位置後,如果使用gluLookAt(),則上方向不會改變。 – noise 2012-04-26 09:06:36
我應該解釋說,這是一個圍繞固定點旋轉的第三人稱相機。所看到的觀點不會在旋轉時改變,只有在相機被翻譯的情況下才是完全獨立的。僅旋轉相機的位置是不夠的?對不起,如果我是愚蠢的。 :) – noise 2012-04-26 09:19:07
啊,我明白了。我認爲你應該做的第一件事就是使用一個合適的矢量數學庫,因爲你的旋轉代碼很難理解。你應該有三維向量和四元數的類來執行實際的工作,而不是實現你的相機內的一切。在目前的狀態下,很難說你的代碼實際上做了什麼以及它是否正確。 – 2012-04-26 09:37:27