Modify camera to display a specific part of the scene

Hi, for a strategy game, I have to set up the camera so that a specific part of the scene is visible.

Input:

  • The coordinate system is x to the right, y in front and z as an up-vector (strategy map, x,y,height)

  • A fixed camera rotation, set in the following way (camera looks at the origin):

     Vector3f DEFAULT_LOCATION = new Vector3f(0, -5, 7);
     position.set(DEFAULT_LOCATION); //Vector3f, send to camera.setLocation()
     rotation.lookAt(DEFAULT_LOCATION.negate(), Vector3f.UNIT_Z); //Quaternion, send to camera.setRotation()
    
  • A rectangular area of the 3d scene, x,y,width,height, on the ground (z=0) in world coordinates

  • a rectangular area in the gui (in pixel coordinates) in which the selected 3d scene should be displayed. The rest of the scene is covered by GUI: guiX, guiY, guiWidth, guiHeight

Goal:
I now want to move the camera (modify the position-vector) so that the selected part of the ground (in 3d) is visible in the available rect in the GUI.
How can I calculate this vector?
Thank you

What is the position and what is the rotation ?
Will you apply it to the same camera Node ?
If so, you should notice that looking at the same position where you object are not allays will turn the “head” to it, I have an post talking about it here in the forum, you may look on that.
Anyway, bether to set your camera position and set an imaginary point, then look at it, so you should dont need to “send to camera.setlocation”…

This will be one of the easier vector math problems you’ll have to solve during game development, I suggest tying to wrap your head around this yourself. Hint: a^2 + b^2 = c^2

Hi normen. This is a late response but this is what I have so far:

And here is the code for setting the camera properties:

float alpha = 45 * FastMath.DEG_TO_RAD; //fov
float beta = alpha * screenHeight / screenWidth;

float defaultLocationY = -5;
float defaultLocationZ = 7;
float theta = FastMath.atan(defaultLocationZ / (-defaultLocationY));
Quaternion rot = new Quaternion();
rot.lookAt(new Vector3f(0, -defaultLocationY, -defaultLocationZ), Vector3f.UNIT_Z); //still the easiest way for me

Vector3f min = playfield.getMin(null); //x0=min.x; y0=min.y; z0=min.z
Vector3f max = playfield.getMax(null); //x1=max.x; y1=max.y; z1=maz.z

//calculate y and z
int c = freeGuiArea.getY1();
int b = freeGuiArea.getHeight();
float tau1 = FastMath.HALF_PI - theta - beta/2 + beta*c/screenWidth;
float tau2 = FastMath.HALF_PI - theta - beta/2 + beta*(b+c)/screenWidth;
float y1 = (FastMath.tan(tau1)*min.y + max.z + FastMath.tan(tau2)*max.y) / (FastMath.tan(tau1) - FastMath.tan(tau2));
float z1 = FastMath.tan(tau1) * (-y1 - min.y);

//calculate x and z
int e = freeGuiArea.getX1();
int f = freeGuiArea.getWidth();
int g = screenWidth - freeGuiArea.getX2();
float mu1 = (f/2.0f) * (alpha / 2.0f) / (e + f/2.0f);
float mu2 = (f/2.0f) * (alpha / 2.0f) / (g + f/2.0f);
float z2 = (max.z*FastMath.tan(mu1) + max.z*FastMath.tan(mu2) + min.x + max.x) / (FastMath.tan(mu1) + FastMath.tan(mu2));
float x2 = (FastMath.tan(mu1) * (z2 - max.z)) - min.x;

Vector3f position = new Vector3f(x2, y1, Math.max(z1, z2));
camera.setFrustumPerspective(beta * FastMath.RAD_TO_DEG, (float) screenWidth / screenHeight, 0.1f, 1000);
camera.setLocation(position);
camera.setRotation(rot);

Sadly, it does not work. The camera is placed to far on the right and not high enough. Does someone find the error/errors? Thanks

Is your camera at a fixed rotation or do you rotate it to fit also? That part wasn’t really clear to me.

…and if it’s supposed to also rotate then how do you decide to rotate versus move?

If it doesn’t rotate then the answer is pretty easy. I did similar to zoom my cameras in on the trees for SimArboreal to fit them to the camera for an atlas texture.

I want the camera to be at a fixed rotation, at ~55° from the horizontal plane. This looks best for my board strategy game.
It is done by the Quaternion.lookAt()-code.

For getting where to look, you can possibly just project the bounding box corners into 2D space and find the center, then project that back into 3D space, move until that’s in the center of your viewport. Else, if you don’t require perfect accuracy vertically, it’s way easier to just find the center of the bounding box and place the camera along its reverse view vector by some distance.

camPos = bbCenter.add(cam.getDirection().mult(-distance));

As far as distance goes, there is a matrix value that will be very helpful. If you want, you can look at the sim-arboreal code I use to calculate camera distance to fit a BB in view:

Starts here:

In my case, I’m straight on but you should be able to still use it for the distance in the equation above.