How to make the camera move in the direction of the roatation?

How can I make the camera move to the direction of which I’m rotating?
I use W,A,S,D to move, UP and DOWN to rotate.
I’m drawing a quad as wall but it just blocks everything when I move around.
You have to click the windows to gain focus.


import javax.media.opengl.*;
import javax.media.opengl.awt.*;
import com.sun.opengl.util.*;
import com.sun.opengl.util.gl2.GLUT;
import javax.media.opengl.glu.*;

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class Rotation2 extends JFrame implements GLEventListener, KeyListener
{
    GLCanvas canvas = null;
    Animator an;
    
    public Rotation2()
    {
        canvas=new GLCanvas();
        an=new Animator(canvas);
        add(canvas);
        canvas.addGLEventListener(this);
        canvas.addKeyListener(this);
        setSize(1280,900);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        an.start();
        requestFocus();
        
    }
    float xPosition = 0;
    float zPosition = 0;
    
    float red = 0;
    float green = 0;
    float blue = 1;
    
    
    public void init(GLAutoDrawable drawable)
    {
        GL2 gl = drawable.getGL().getGL2();
        GLU glu = new GLU();
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        
        double w = drawable.getWidth();
        double h = drawable.getHeight();
        double aspect = w/h;
        glu.gluPerspective(60.0, aspect, 2.0, 200.0);
        
    }
    double zRot = 0;
    double xRot = 0;
    
    public void display(GLAutoDrawable drawable)
    {
        GL2 gl=drawable.getGL().getGL2();
        GLU glu = new GLU();
        GLUT glut = new GLUT();
        
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        gl.glClearColor(0f,0f,0f,0f);
        //xPosition+=0.005;
        //zPosition+=0.005;
        gl.glRotated(zRot, 0, 1, 0);
        gl.glRotated(xRot, 1, 0, 0);
        glu.gluLookAt(xPosition, 0, zPosition,
                xPosition, 0, (zPosition+20),
                0, 1, 0);
        
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
        
        gl.glColor3f(1, 1, 1);
        gl.glBegin(GL2.GL_QUADS);
        gl.glVertex3i(0, 100, -500);
        gl.glVertex3i(0, 100, 0);
        gl.glVertex3i(500, 100, 0);
        gl.glVertex3i(500, 100, -500);
        gl.glEnd();
        
        red = 0.0f;
        green = 0.0f;
        blue = 0.9f;
        gl.glColor3f(red, green, blue);
//transforming the place the next shape
//will be drawn.
        gl.glTranslated(2, 0, 2);
//We use wire here because default
//lighting is not good enough to
//use when rendering the solid version
        glut.glutWireIcosahedron();
//more shapes to navigate through
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.0f;
        green = 0.9f;
        blue = 0.1f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.9f;
        green = 0.0f;
        blue = 0.1f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.9f;
        green = 0.0f;
        blue = 0.9f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutSolidIcosahedron();
        
        gl.glBegin(GL2.GL_QUADS);
        // Right-face
        gl.glColor3f(100.0f, 0.0f, 100.0f); // violet
        gl.glVertex3f(100.0f, 100.0f, -100.0f);
        gl.glVertex3f(100.0f, 100.0f, 100.0f);
        gl.glVertex3f(100.0f, -100.0f, 100.0f);
        gl.glVertex3f(100.0f, -100.0f, -100.0f);
        
        gl.glEnd();
        
        
    }
    
    public void reshape(GLAutoDrawable drawable,int x,int y,int width,int height)
    {}
    public void dispose(GLAutoDrawable drawable)
    {}
    
    
    public static void main(String[] ar)
    {
        
        new Rotation2();
    }
    
    @Override
    public void keyTyped(KeyEvent e) {
        
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
            zPosition++;
        }
        else if (e.getKeyCode() == KeyEvent.VK_S) {
            zPosition--;
        }
        else if(e.getKeyCode() == KeyEvent.VK_A) {
            xPosition++;
        }
        else if (e.getKeyCode() == KeyEvent.VK_D) {
            xPosition--;
        }
        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            zRot+=5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            zRot-=5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_UP) {
            xRot-=5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            xRot+=5;
        }
        canvas.repaint();
    }
    
    @Override
    public void keyReleased(KeyEvent e) {
        
    }
}


OK, so at the beginning of the display call you are setting the modelview to the identity and then performing a rotation for the “camera”


gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        gl.glClearColor(0f,0f,0f,0f);
        //xPosition+=0.005;
        //zPosition+=0.005;
        gl.glRotated(zRot, 0, 1, 0);
        gl.glRotated(xRot, 1, 0, 0);
        glu.gluLookAt(xPosition, 0, zPosition,
                xPosition, 0, (zPosition+20),
                0, 1, 0);

but then you never touch that matrix again, which means that everything you draw will be in relation to that rotation (which means static objects will look like they are not moving)

What you should do is reset the modelview matrix back to the identity matrix before each draw call (glBegin()…glEnd()). Although, if you do that you have to understand that you are drawing everything in world coordinates. That is to say you are drawing everything relative to the origin of the “world” (the identity matrix).

You need to compute where the camera is looking at, in world-coordinates:


float forwardZ = -(float)Math.cos(xRot) * (float)Math.cos(yRot);
float forwardX =  (float)Math.sin(yRot) * (float)Math.cos(xRot);
float forwardY = -(float)Math.sin(xRot);

You need to do this computation every time you alter the camera rotation (xRot, yRot).
This will give you the world-space “forward” vector which is always in the direction the camera will be looking along. I also renamed your zRot to yRot, and both angles are now in radians for the purpose of not having to convert to radians for sin/cos.
You now need to add/subtract (forwardX, forwardY, forwardZ) to your (xPosition, yPosition, zPosition) when you want to move forward/backward.

Additionally, you don’t need lookAt. And you also want to swap the order of rotations from YX to XY. Use the following as modelview matrix:


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef((float) Math.toDegrees(xRot), 1, 0, 0);
glRotatef((float) Math.toDegrees(yRot), 0, 1, 0);
glTranslatef(-xPosition, -yPosition, -zPosition);

Everything else can stay as is.

I don’t have much experience with OpenGL but I played around with your code a bit and it looks like I got it to work.
But of course this code is still very crude.
btw. the imports are different because I used the latest version of jogl. Just change them back to match your version.

import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.*;
import com.jogamp.opengl.util.*;
import com.jogamp.opengl.util.gl2.GLUT;
import com.jogamp.opengl.glu.*;
import com.jogamp.opengl.math.Quaternion;


import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class Rotation2 extends JFrame implements GLEventListener, KeyListener
{
    GLCanvas canvas = null;
    Animator an;
    
    public Rotation2()
    {
        canvas=new GLCanvas();
        an=new Animator(canvas);
        add(canvas);
        canvas.addGLEventListener(this);
        canvas.addKeyListener(this);
        setSize(1280,900);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        an.start();
        requestFocus();
        
    }
    float xPosition = 0;
    float yPosition = 0;
    float zPosition = 0;
    
    Quaternion cameraOrientation = new Quaternion();
    
    float red = 0;
    float green = 0;
    float blue = 1;
    
    
    public void init(GLAutoDrawable drawable)
    {   
        GL2 gl = drawable.getGL().getGL2();
        GLU glu = new GLU();
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        
        double w = drawable.getSurfaceWidth();
        double h = drawable.getSurfaceHeight();
        double aspect = w/h;
        glu.gluPerspective(60.0, aspect, 2.0, 200.0);
        
    }
    double yRot = 0;
    double xRot = 0;
    
    public void display(GLAutoDrawable drawable)
    {
        GL2 gl=drawable.getGL().getGL2();
        GLU glu = new GLU();
        GLUT glut = new GLUT();
        
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        gl.glClearColor(0f,0f,0f,0f);
        
        gl.glRotated(xRot, 1, 0, 0);
        gl.glRotated(yRot, 0, 1, 0);
        gl.glTranslated(xPosition, yPosition, zPosition);
        
        
        gl.glTranslated(0, 0, -30);
        
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
        
        gl.glColor3f(1, 1, 1);
        gl.glBegin(GL2.GL_QUADS);
        gl.glVertex3i(0, 100, -500);
        gl.glVertex3i(0, 100, 0);
        gl.glVertex3i(500, 100, 0);
        gl.glVertex3i(500, 100, -500);
        gl.glEnd();
        
        red = 0.0f;
        green = 0.0f;
        blue = 0.9f;
        gl.glColor3f(red, green, blue);
//transforming the place the next shape
//will be drawn.
        gl.glTranslated(2, 0, 2);
//We use wire here because default
//lighting is not good enough to
//use when rendering the solid version
        glut.glutWireIcosahedron();
//more shapes to navigate through
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.0f;
        green = 0.9f;
        blue = 0.1f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.9f;
        green = 0.0f;
        blue = 0.1f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.9f;
        green = 0.0f;
        blue = 0.9f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutSolidIcosahedron();
        
        gl.glBegin(GL2.GL_QUADS);
        // Right-face
        gl.glColor3f(100.0f, 0.0f, 100.0f); // violet
        gl.glVertex3f(100.0f, 100.0f, -100.0f);
        gl.glVertex3f(100.0f, 100.0f, 100.0f);
        gl.glVertex3f(100.0f, -100.0f, 100.0f);
        gl.glVertex3f(100.0f, -100.0f, -100.0f);
        
        gl.glEnd();
        
    }
    
    public void reshape(GLAutoDrawable drawable,int x,int y,int width,int height)
    {}
    public void dispose(GLAutoDrawable drawable)
    {}
    
    
    public static void main(String[] ar)
    {
        
        new Rotation2();
    }
    
    @Override
    public void keyTyped(KeyEvent e) {
        
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
            float[] zAxis = cameraOrientation.copyMatrixColumn(2, new float[3], 0);
            xPosition += zAxis[0];
            yPosition += zAxis[1];
            zPosition += zAxis[2];
        }
        else if (e.getKeyCode() == KeyEvent.VK_S) {
            float[] zAxis = cameraOrientation.copyMatrixColumn(2, new float[3], 0);
            xPosition -= zAxis[0];
            yPosition -= zAxis[1];
            zPosition -= zAxis[2];
        }
        else if(e.getKeyCode() == KeyEvent.VK_A) {
            float[] xAxis = cameraOrientation.copyMatrixColumn(0, new float[3], 0);
            xPosition += xAxis[0];
            yPosition += xAxis[1];
            zPosition += xAxis[2];
        }
        else if (e.getKeyCode() == KeyEvent.VK_D) {
            float[] xAxis = cameraOrientation.copyMatrixColumn(0, new float[3], 0);
            xPosition -= xAxis[0];
            yPosition -= xAxis[1];
            zPosition -= xAxis[2];
        }
        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            yRot+=5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            yRot-=5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_UP) {
            xRot-=5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            xRot+=5;
        }
        cameraOrientation = new Quaternion();
        cameraOrientation.rotateByAngleY((float)Math.toRadians(-yRot));
        cameraOrientation.rotateByAngleX((float)Math.toRadians(-xRot));
        
        canvas.repaint();
    }
    
    @Override
    public void keyReleased(KeyEvent e) {
        
    }
}

The ortho matrix contains the local coordinate frame. 1st row or column (by chosen convention) is local X, Y is second and Z is third. So forward, up, right, etc. can be directly yanked out based on that chosen convention as well.

Why don’t I need glulookAt()? I need to move the screen instead?

Thank you for your help, I tried your code and it does what I want it to do but I have a new problem and that’s how can I now my current position? I want to setup a wall that the player can’t go through, I want set something like a boundary but I don’t know which numbers to work with.

I tried to improve the code some more. I defined a class that represents a virtual camera. To move the player around you just have to move the camera, which means your current position is the position of the camera.
Btw. the camera always looks in the direction of the negative z axis (because that’s the default in opengl). So moving foward means to move towards -z.

import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.*;
import com.jogamp.opengl.util.*;
import com.jogamp.opengl.util.gl2.GLUT;
import com.jogamp.opengl.glu.*;
import com.jogamp.opengl.math.*;

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

class Camera {
  private float[] pos = {0, 0, 0};
  private Quaternion orientation = new Quaternion();
  
  void moveTo(float[] pos) {
    this.pos[0] = pos[0];
    this.pos[1] = pos[1];
    this.pos[2] = pos[2];
  }
  
  void move(float[] dv) {
    this.pos[0] += dv[0];
    this.pos[1] += dv[1];
    this.pos[2] += dv[2];
  }
  
  void setOrientation(Quaternion q) {
    orientation.set(q);
    orientation.normalize();
  }
  
  void rotateAbs(Quaternion q) {
    Quaternion temp = new Quaternion();
    temp.set(orientation);
    orientation.set(q);
    orientation.mult(temp);
  }
  
  void rotateRel(Quaternion q) {
    orientation.mult(q);
  }
  
  void rotateXRel(float radians) {
    Quaternion q = new Quaternion();
    q.rotateByAngleX(radians);
    orientation.mult(q);
  }
  
  void rotateYRel(float radians) {
    Quaternion q = new Quaternion();
    q.rotateByAngleY(radians);
    orientation.mult(q);
  }
  
  void rotateZRel(float radians) {
    Quaternion q = new Quaternion();
    q.rotateByAngleZ(radians);
    orientation.mult(q);
  }
  
  void lookAtPos(float[] target, float[] up) {
    float[] direction = new float[3];
    VectorUtil.subVec3(direction, pos, target);
    orientation.setLookAt(direction, up, new float[3], new float[3], new float[3]);
  }
  
  void moveBack(float x) {
    float[] zAxis = orientation.copyMatrixColumn(2, new float[3], 0);
    pos[0] += zAxis[0] * x;
    pos[1] += zAxis[1] * x;
    pos[2] += zAxis[2] * x;
  }
  
  void moveForward(float x) {
    moveBack(-x);
  }
  
  void moveRight(float x) {
    float[] xAxis = orientation.copyMatrixColumn(0, new float[3], 0);
    pos[0] += xAxis[0] * x;
    pos[1] += xAxis[1] * x;
    pos[2] += xAxis[2] * x;
  }
  
  void moveLeft(float x) {
    moveRight(-x);
  }
  
  void prepareGL(GL2 gl) {
    float[] axis = new float[3];
    float angle = orientation.toAngleAxis(axis);
    gl.glRotated(-Math.toDegrees(angle), axis[0], axis[1], axis[2]);
    gl.glTranslated(-pos[0], -pos[1], -pos[2]);
  }
}

public class Rotation2 extends JFrame implements GLEventListener, KeyListener
{
    GLCanvas canvas = null;
    Animator an;
    
    public Rotation2()
    {
        canvas=new GLCanvas();
        an=new Animator(canvas);
        add(canvas);
        canvas.addGLEventListener(this);
        canvas.addKeyListener(this);
        setSize(1280,900);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        an.start();
        requestFocus();
        
    }
    
    Camera cam = new Camera();
    
    float red = 0;
    float green = 0;
    float blue = 1;
    
    public void init(GLAutoDrawable drawable)
    {   
        GL2 gl = drawable.getGL().getGL2();
        GLU glu = new GLU();
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        
        double w = drawable.getSurfaceWidth();
        double h = drawable.getSurfaceHeight();
        double aspect = w/h;
        glu.gluPerspective(60.0, aspect, 2.0, 200.0);
        cam.moveBack(30);
        
    }
    
    public void display(GLAutoDrawable drawable)
    {
        GL2 gl=drawable.getGL().getGL2();
        GLU glu = new GLU();
        GLUT glut = new GLUT();
        
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        gl.glClearColor(0f,0f,0f,0f);
        
        cam.prepareGL(gl);
        
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
        
        gl.glColor3f(1, 1, 1);
        gl.glBegin(GL2.GL_QUADS);
        gl.glVertex3i(0, 100, -500);
        gl.glVertex3i(0, 100, 0);
        gl.glVertex3i(500, 100, 0);
        gl.glVertex3i(500, 100, -500);
        gl.glEnd();
        
        red = 0.0f;
        green = 0.0f;
        blue = 0.9f;
        gl.glColor3f(red, green, blue);
//transforming the place the next shape
//will be drawn.
        gl.glTranslated(2, 0, 2);
//We use wire here because default
//lighting is not good enough to
//use when rendering the solid version
        glut.glutWireIcosahedron();
//more shapes to navigate through
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.0f;
        green = 0.9f;
        blue = 0.1f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.9f;
        green = 0.0f;
        blue = 0.1f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutWireIcosahedron();
        red = 0.9f;
        green = 0.0f;
        blue = 0.9f;
        gl.glColor3f(red, green, blue);
        gl.glTranslated(4, 0, 4);
        glut.glutWireIcosahedron();
        gl.glTranslated(-4, 0, 0);
        glut.glutSolidIcosahedron();
        
        gl.glBegin(GL2.GL_QUADS);
        // Right-face
        gl.glColor3f(100.0f, 0.0f, 100.0f); // violet
        gl.glVertex3f(100.0f, 100.0f, -100.0f);
        gl.glVertex3f(100.0f, 100.0f, 100.0f);
        gl.glVertex3f(100.0f, -100.0f, 100.0f);
        gl.glVertex3f(100.0f, -100.0f, -100.0f);
        
        gl.glEnd();
        
    }
    
    public void reshape(GLAutoDrawable drawable,int x,int y,int width,int height)
    {}
    public void dispose(GLAutoDrawable drawable)
    {}
    
    
    public static void main(String[] ar)
    {
        new Rotation2();
    }
    
    @Override
    public void keyTyped(KeyEvent e) {
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
          cam.moveForward(1);
        }
        else if (e.getKeyCode() == KeyEvent.VK_S) {
          cam.moveBack(1);
        }
        else if(e.getKeyCode() == KeyEvent.VK_A) {
          cam.moveLeft(1);
        }
        else if (e.getKeyCode() == KeyEvent.VK_D) {
          cam.moveRight(1);
        }
        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
          cam.rotateYRel((float)Math.toRadians(-5));
        }
        else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
          cam.rotateYRel((float)Math.toRadians(5));
        }
        else if (e.getKeyCode() == KeyEvent.VK_UP) {
          cam.rotateXRel((float)Math.toRadians(5));
        }
        else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
          cam.rotateXRel((float)Math.toRadians(-5));
        }
        
        canvas.repaint();
    }
    
    @Override
    public void keyReleased(KeyEvent e) {
        
    }
}