3
\$\begingroup\$

Let me paste some code before I ask the question...

public static void createWindow(int[] args) {

    try {

        Display.setFullscreen(false);
        DisplayMode d[] = Display.getAvailableDisplayModes();
        for (int i = 0; i < d.length; i++) {
            if (d[i].getWidth() == args[0] && d[i].getHeight() == args[1]
                    && d[i].getBitsPerPixel() == 32) {
                displayMode = d[i];
                break;
            }
        }

        Display.setDisplayMode(displayMode);
        Display.create();

    } catch (Exception e) {
        e.printStackTrace();
        System.exit(0);
    }

}

public static void initGL() {
    GL11.glEnable(GL11.GL_TEXTURE_2D);
    GL11.glShadeModel(GL11.GL_SMOOTH);
    GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    GL11.glClearDepth(1.0);
    GL11.glEnable(GL11.GL_DEPTH_TEST);
    GL11.glDepthFunc(GL11.GL_LEQUAL);

    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();

    GLU.gluPerspective(45.0f, (float) displayMode.getWidth()
            / (float) displayMode.getHeight(), 0.1f, 100.0f);

    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
}

So, with the camera and screen setup out of the way, I can now ask the actual question: How do I know what the camera distance is from the image plane? I also would like to know what the angle between the image plane's center normal and a line drawn from the middle of one of the edges to the camera position is.

This will be used to consequently draw a vector from the camera's position through the player's click-coordinates to determine the world coordinates they clicked (or could've clicked).

Also, when I set the camera coordinates, do I set the coordinates of the camera or do I set the coordinates of the image plane?

Thank you for your help.

EDIT: So, I managed to solve how to calculate the distance of the camera... Here's the relevant code...

private static float getScreenFOV(int dim) {
    if (dim == 0) {
        float dist = (float) Math.tan((Math.PI / 2 - Math.toRadians(FOV_Y))/2) * 0.5f;
        float FOV_X = 2 * (float) Math.atan(getScreenRatio() * 0.5f / dist);
        return FOV_X;
    } else if (dim == 1) {
        return FOV_Y;
    }
    return 0;
}

FOV_Y is the Field of View that one defines in gluPerspective (float fovy in javadoc). This seems to be (and would logically be) for the height of the screen. Now I just need to figure out how to calculate that vector.

\$\endgroup\$
1
  • \$\begingroup\$ Tge camera's distance from the image plabe is always the near value of the camera and you alwyys move the camera's position, not the plane. \$\endgroup\$
    – Bálint
    Apr 12, 2016 at 10:00

2 Answers 2

0
\$\begingroup\$

How do I know what the camera distance is from the image plane?

I'm not sure if this is a meaningful question to ask - what is the image plane? A real camera has a plane on which an image is formed, but in OpenGL there is no such thing. If you need this for some physics-based calculation, you could possibly use the near clipping plane distance (third argument to gluPerspective, here it's 0.1 units).

I also would like to know what the angle between the image plane's center normal and a line drawn from the middle of one of the edges to the camera position is.

The angle between the top and bottom edges of the frustum is the "fovy" parameter you passed to Javadoc, so the angle between the top and the normal will be half that.

Since the image isn't square, the horizontal angle will be different from this; you could use some trigonometry to calculate it. If your screen width and height in pixels is sw and sh, your near plane distance is npd, and your vertical FOV is fovy, then:

  • The height of the near plane in view is sh pixels, and npd*tan(fovy/2)*2 OpenGL units.
  • Each pixel must be npd*tan(fovy/2)*2/sh OpenGL units.
  • The width of the near plane in view is sw pixels, at the same scale, so npd*tan(fovy/2)*2*sw/sh OpenGL units.
  • The horizontal FOV is atan(width / npd / 2)*2 or atan(npd*tan(fovy/2)*2*sw/sh/npd/2)*2
  • Simplifying: atan(tan(fovy/2)*sw/sh)*2

That's assuming I didn't make any math mistakes there.

Like before, the angle between the normal and one of the edges will be half the FOV, so remove the *2 at the end to calculate that instead.

Also, when I set the camera coordinates, do I set the coordinates of the camera or do I set the coordinates of the image plane?

OpenGL has no concept of "camera coordinates". If you have a camera in your program, it's a completely made-up concept, and what you're actually doing is moving the entire world the opposite way.

\$\endgroup\$
1
\$\begingroup\$

To answer your question about moving the camera, this is what I do at the start of each frame of my program:

/**
 * Looks through the camera, effectively updating how we view the game.
 *
 * @param updateFrustum recalculates the frustum if true
 */
public void lookThrough(boolean updateFrustum) {
    glRotatef(rx, 1.0f, 0.0f, 0.0f);
    glRotatef(ry, 0.0f, 1.0f, 0.0f);
    glRotatef(rz, 0.0f, 0.0f, 1.0f);
    glTranslatef(position.x, position.y, position.z);
    if (updateFrustum) {
        frustum.calculateFrustum();
        }
    }
}

This is called after I handle the inputs from keyboard and mouse, which probably called the move() method (or pitch() or roll() or yaw(), which are equivalent):

/**
 * Moves the camera a specific amount in a specific direction.
 * 
 * @param amount
 * @param dir
 */
public void move(float amount, Camera.Direction direction) {
    switch (direction) {
    case BACKWARDS_OR_FORWARDS:
        position.z += amount * Math.sin(Math.toRadians(ry + 90));
        position.x += amount * Math.cos(Math.toRadians(ry + 90));
        position.y += amount * Math.sin(Math.toRadians(rx));
        break;
    case SIDEWAYS:
        position.z += amount * Math.sin(Math.toRadians(ry));
        position.x += amount * Math.cos(Math.toRadians(ry));
        break;
    case UP_OR_DOWN:
        // TODO: implement
    default:
        break;
    }
}

I hope the code is self-sufficient to see what I mean but the most important of course are the glRotatef and glTranslatef commands, which moves the point and direction from where I draw my content each frame.

To answer your second question:

When you want to know where your mouse pointer crosses a plane (the terrain for example), you would need to create a line (or vector) from the position of the camera (you have the position and angle of the camera, so you can create a vector out of that) towards the terrain and calculate the point of intersection.

\$\endgroup\$
3
  • \$\begingroup\$ You've completely managed to misunderstand my second question about the movement of the camera. I am not interested in how to move it. I am interested in which part of it I am actually moving. Also, I have understood that I need to draw a vector from the position of the camera, but I don't know how to make it go through the point where the player clicks, nor do I know how to calculate what the vector intersects with. THAT is my actual question. \$\endgroup\$
    – user39208
    Nov 21, 2013 at 14:15
  • \$\begingroup\$ "I am interested in which part of it I am actually moving." The "camera" does not really exist. It represents the point and angle from which you start to draw your scene. When the "camera" moves, you translate and rotate the point of reference from where you draw your 3D elements. \$\endgroup\$ Nov 24, 2013 at 16:05
  • \$\begingroup\$ To elaborate: with enough OpenGL magic you can draw a 3D scene that has no relationship to the scene visible through the "camera" without needing a second "camera" including separating movement and input controls. The camera component is just a helper around this complex OpenGL rendering path that aids the developer in designing the scene. It's much much easier to Tween.add(...) on a gameobject with a camera than to directly manipulate GL.rotate(...) and GL.translate(...) \$\endgroup\$ Jan 11, 2016 at 16:35

You must log in to answer this question.