I have problems to understand the field of view of the perspective camera in libGDX (or maybe my calculations are wrong).
I want to draw a box (for example 800px wide, 480px high and 20px deep). The box is placed between x- and y-axis (in other words: the width on x-axis and the height on y-axis). Now I want to stand behind the box on the x-axis (camera position) and look in a direction in such a way that I see the box on my very right screen side. I made some sketches:
On the last sketch, the box is on the right side of the field of view.
Moreover, the height of the box must fit exactly in the screen. In other words: the top edge of the box must be on my screen top and the bottom edge of the box must be on my screen bottom. Here is some code and calculations to achieve this:
public class Box implements ApplicationListener {
public PerspectiveCamera camera;
public float SCREEN_WIDTH;
public float SCREEN_HEIGHT;
@Override
public void create() {
SCREEN_WIDTH = Gdx.graphics.getWidth(); // 800px
SCREEN_HEIGHT = Gdx.graphics.getHeight(); // 480px
// Create camera (90°) and set position
camera = new PerspectiveCamera(90f, SCREEN_WIDTH, SCREEN_HEIGHT);
camera.position.set(SCREEN_WIDTH + SCREEN_HEIGHT/2, SCREEN_HEIGHT/2, 0f);
camera.lookAt(0f, SCREEN_HEIGHT/2, 0f);
camera.near = 1;
camera.far = 2 * SCREEN_WIDTH;
camera.update();
}
@Override
public void render() {
Gdx.gl.glClearColor(Color.WHITE.r, Color.WHITE.g, Color.WHITE.b, Color.WHITE.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// Build the box - width is screenwidth and height is screenheight - one corner in origin
ModelBuilder modelBuilder = new ModelBuilder();
modelBuilder.begin();
MeshPartBuilder mpb = modelBuilder.part("ID", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal,
new Material(ColorAttribute.createDiffuse(Color.GREEN)));
// bottom left corner of the box should be in (0,0,0)
mpb.box(SCREEN_WIDTH/2, SCREEN_HEIGHT/2, -10f, SCREEN_WIDTH, SCREEN_HEIGHT, 20f);
Model model = modelBuilder.end();
ModelInstance instance = new ModelInstance(model);
// Build some light
Environment environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
// Draw the box
ModelBatch modelBatch = new ModelBatch();
modelBatch.begin(camera);
modelBatch.render(instance, environment);
modelBatch.end();
}
}
To fit the box height in the screen I must step back SCREEN_HEIGHT/2, because x = SCREEN_HEIGHT/2 / tan(45°) = SCREEN_HEIGHT/2 / 1 = SCREEN_HEIGHT/2, that's why I added this length to the x-component in the position setting.
The code represents sketch 2 and give me that correct screenshot:
In order to achieve sketch 3, I must rotate my field of view about 45° to the left. But in this connection I must step back a little, because the sides of the field of view are longer than the centerline. I made two hand-drawn sketches:
Where h = SCREEN_HEIGHT. First of all, I have to compute x. x = h/2 / sin(45°) = h/sqrt(2). Now I must step back a length of x and look in a new direction (45° left from box). To calculate the point at which I will looking, I calculate the length y on this sketch:
y = sin(45°) * h/2 = h * sqrt(2)/4. So, the point is for example (SCREEN_WIDTH + (x-y), SCREEN_HEIGHT/2, y). Now I change the position and looking point in my code:
public void create() {
SCREEN_WIDTH = Gdx.graphics.getWidth(); // 800px
SCREEN_HEIGHT = Gdx.graphics.getHeight(); // 480px
// Create camera (90°) and set position
camera = new PerspectiveCamera(90f, SCREEN_WIDTH, SCREEN_HEIGHT);
float x = (float) (SCREEN_HEIGHT / Math.sqrt(2));
float y = (float) (SCREEN_HEIGHT * Math.sqrt(2)/4f);
camera.position.set(SCREEN_WIDTH + x, SCREEN_HEIGHT/2, 0f);
camera.lookAt(SCREEN_WIDTH + x - y, SCREEN_HEIGHT/2, y);
camera.near = 1;
camera.far = 2 * SCREEN_WIDTH;
camera.update();
}
And I get this screen:
But the box isn't on the very right side :(
So now the question: what is wrong? Is my thinking of the field of view wrong or my calculations?
Best regards!