2012-04-26 19 views
0

저는 OpenGL과 3D 프로그래밍에 상당히 익숙하지만 http://www.cprogramming.com/tutorial/3d/quaternions.html의 튜토리얼에 기반한 쿼터니언을 사용하여 카메라 회전을 구현하기 시작했습니다. 이것은 모두 JOGL을 사용하여 Java로 작성됩니다.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 메소드는 permenant quaternion에서 생성 된 회전 행렬을 단순히 곱하는 반면 새로운 회전 및 이전 회전에서 새로운 permenant quaternions를 생성합니다.

@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()를 호출하는 디스플레이 (렌더링 가능한 루프 드로잉 가능)를 구현하므로 렌더링 루프를 구현합니다. 모델 측면에서 업데이트 이벤트를 전달한 다음 렌더링 대기열에 저장합니다. 죄송합니다. Camera 클래스에는 이미 눈의 위치와 그 위치가 저장됩니다 (원래 게시물에 코드를 추가합니다). 위쪽 방향을 정의하는 벡터와 관련 있습니다. 카메라가 회전 할 때 변경해야합니까? 위 방향이 바뀌지 않을 cam의 pos를 회전 한 후에 gluLookAt()를 사용하면 가정합니다. – noise

+0

나는 이것이 고정 소수점 주위를 도는 3 인칭 카메라라고 설명해야합니다. 보이는 시점은 회전 할 때만 변하지 만 카메라가 번역되어 있지만 완전히 별개입니다. 카메라의 위치를 ​​회전시키는 것만으로 충분하지 않습니까? 내가 바보라면 미안해. :) – noise

+0

아, 알겠습니다. 회전 코드는 이해하기가 어렵 기 때문에 가장 먼저해야 할 일은 적절한 벡터 수학 라이브러리를 사용하는 것입니다. 카메라 내부의 모든 것을 구현하는 대신 실제 작업을 수행하는 3D 벡터 및 쿼터니언에 대한 클래스가 있어야합니다. 현재 상태에서는 코드가 실제로하는 일과 코드가 올바르게 작동하는지 여부를 말하는 것이 꽤 어렵습니다. –

관련 문제