2012-04-26 115 views
0

我對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); 
    } 
} 

我希望我提供足夠的細節:

旋轉軸線和旋轉角是由簡單的按鍵設定如下。任何幫助將非常感激。

回答

1

關於抖動:我沒有看到代碼中的任何渲染循環。呈現方法如何觸發?通過計時器或事件?

當圍繞兩個軸旋轉時,你的旋轉旋轉可能與你需要旋轉第二個旋轉的軸以及第一個軸的總旋轉的事實有關。您不能僅應用關於全局座標系的X或Y軸的旋轉。您必須應用關於相機的上軸和右軸的旋轉。

我建議你創建一個相機類,存儲攝像機的向上,向右和向視方向向量,並將你的旋轉直接應用到這些軸。如果這是一款類似FPS的相機,那麼您將需要水平旋轉相機(向左/向右看)關於絕對Y軸而不是向上向量。這也將導致相機的新右軸。然後,垂直旋轉相機(向上/向下)關於新右軸。但是,當相機直接向上或向下看時,您必須小心,因爲在這種情況下,您不能使用視圖方向和向上矢量的叉積來獲得正確的矢量。

+0

SceneRenderer類實現GLEventListener,它包含調用render()以及render loop的display(GLAutoDrawable drawable)。應用程序的模型端只傳遞更新事件,然後存儲在渲染隊列中。對不起,不清楚。 Camera類已經存儲了眼睛的位置以及它在看什麼(我將把代碼添加到原始文章中)。 至於定義向上方向的向量。這是否需要改變相機旋轉?我假設在旋轉凸輪的位置後,如果使用gluLookAt(),則上方向不會改變。 – noise 2012-04-26 09:06:36

+0

我應該解釋說,這是一個圍繞固定點旋轉的第三人稱相機。所看到的觀點不會在旋轉時改變,只有在相機被翻譯的情況下才是完全獨立的。僅旋轉相機的位置是不夠的?對不起,如果我是愚蠢的。 :) – noise 2012-04-26 09:19:07

+0

啊,我明白了。我認爲你應該做的第一件事就是使用一個合適的矢量數學庫,因爲你的旋轉代碼很難理解。你應該有三維向量和四元數的類來執行實際的工作,而不是實現你的相機內的一切。在目前的狀態下,很難說你的代碼實際上做了什麼以及它是否正確。 – 2012-04-26 09:37:27