Rotate the camera to a point

I am making a game that uses the entire planet for its map. I used close technology using this technique , and now I am adding camera controls.

The sphere has sizes from 1 to -1, so each point on the sphere is also a normalized vector. At any time, one of the hexagonal tiles that make up the sphere is the “selected” tile. The player can then move the selection to adjacent tiles using the d-pad. They can also independently rotate the camera around using the analog joystick.

I need to do two things regarding the selected tile and camera. First, I need to be able to switch the selection to the tile closest to the camera. Secondly, I need to focus the camera on a dedicated plate

The sphere is at the origin, and the camera is at the point (0,0,1). The graphics engine allows me to rotate the camera around the X and Y axes, so to solve the first problem, I use quaternions to rotate the point (0,0,1) around the x axis and then the y axis to find the point in 3D space. where the camera is located:

private Quaternion quat = new Quaternion(0,0,0,0); private double[] output = new double[4]; private double[] cam = new double[3]; private double camX = 0; private double camY = 0; private double camZ = 1; private double[] getCamPosition(){ quat.setAxisAngle(1, 0, 0, Math.toRadians(-graphicsEngine.getRotationX())); quat.RotateVector(camX, camY, camZ, output); cam[0] = output[0]; cam[1] = output[1]; cam[2] = output[2]; quat.setAxisAngle(0, 1, 0, Math.toRadians(-graphicsEngine.getRotationY())); quat.RotateVector(cam[0], cam[1], cam[2], output); cam[0] = output[0]; cam[1] = output[1]; cam[2] = output[2]; return cam; } 

Then I compare the distances between the centroid of each tile and the camera position and select the tile that is closest to the selected tile.

However, to solve the second problem, I want to do the opposite. I want to take a centroid (which is already in the form of a normalized vector) and find out the rotation around X and the rotation around Y, necessary for the camera to be focused on it.

At the moment, I rotate the camera back (0,0,1), then getting the angle along the X axis and Y axis between (0,0,1) and the centroid and using this to rotate the camera a second time:

 private double[] outputArray = new double[2]; /** * Cam is always (0,0,1) */ public void centreOnSelected(double camX, double camY, double camZ){ selectedTile.getCentroidAngles(outputArray); outputArray[0] -= Math.atan2(camZ, camY); outputArray[1] -= Math.atan2(camX, camZ); // this determines if the centroid is pointing away from the camera // Ie is on the far side of the sphere to the camera point (0,0,1) if(!selected.getCentroidDirectionY(camX, camZ)){ outputArray[0] = -Math.PI - outputArray[0]; } graphicsEngine.rotateCam(Math.toDegrees(outputArray[0]), Math.toDegrees(outputArray[1])); } 

and in selected (tile class)

 void getCentroidAngles(double[] outputArray){ outputArray[0] = Math.atan2(centroidZ, centroidY); outputArray[1] = Math.atan2(centroidX, centroidZ); } 

The problem is that this will not work (the x axis always seems missing), and I am sure that this is due to the mathematics of obtaining angles and performing rotating

Note: the graphics engine rotates first around the X axis, then around Y:

  gl.glRotatef(mRotateX, 1, 0, 0); gl.glRotatef(mRotateY, 0, 1, 0); 

The centroids are in the right place, and the camera definitely rotates by the right amount, so I'm sure the problem is not in the graphics engine. This is also not re-positioning the camera (0,0,1), since I checked this by running the program

I also made a video to illustrate the problem:

http://www.youtube.com/watch?v=Uvka7ifZMlE

This listened to me for several days, so any help in getting this fix would be greatly appreciated!

Thanks james

+6
source share
1 answer

Unfortunately, I do not quite understand what is happening here, and cannot offer a complete solution, but it can at least point out some problems that need to be looked at.

I never used glRotatef, but I'm a little confused about the order and signs of the transforms here - for example, do you really rotate x first, given the order of the calls to glRotatef?

In any case, at least part of the problem here comes from these equations

 outputArray[0] = Math.atan2(centroidZ, centroidY); outputArray[1] = Math.atan2(centroidX, centroidZ); 

First, did you mean (centroidY, centroidZ) in the first? More seriously, the angles you get here cannot be used to create a turn transporting (0,0,1) to your center or vice versa. For example, suppose you want to rotate the centroid vector at (0,0,1) . Each of your two turns can individually be used to rotate around one axis, setting one component to zero. For example, rotating outputArray[0] around the x-axis of the corresponding sign would set the y-component to zero (provided that the arguments to atan2 were replaced). Alternatively, turning the right sign on outputArray[1] relative to the y axis could set the x-component to 0. But after we first make the x-turn (say) to set the y-component to 0, the centroid vector changes - now the rotation around y, which sets the x-component to 0, is no longer described by outputArray[1] .

Proper formulas for these things always have atan2 for one corner and acos or asin for another. For example, if you want the angles for active rotation to transfer the vector (1,0,0) to (x,y,z) , you would use

 first_angle_around_x = -asin(y) second_angle_around_y = atan2(x, z) 

To carry (x,y,z) to (1,0,0) you should use

 first_angle_around_x = atan2(y, z) second_angle_around_y = -asin(x) 

(These angles describe the rotation around the x, y axes, which are counterclockwise when the axis "pushes you into the eyes.")

Another problem here

 outputArray[0] -= Math.atan2(camZ, camY); outputArray[1] -= Math.atan2(camX, camZ); 

Subtraction of such angles is only for rotation around one axis. After you create compound transformations from rotations around different axes, the relationships become much more complex - that’s why matrices and quaternions are suitable. I think this code does not matter if the inputs of camX-Z are redundant, as suggested by the comment preceding the method (although at the moment with the components Z and Y, the path around them here will give a non-zero result, which can compensate that they were the “wrong” ways in the first equations that I mentioned, I'm not sure if this is intentional).

There is also a fundamental problem with the way you move the camera to the selected tile, although it is a bit subjective if this is really a problem. Since you only rotate around the x and y axes, you have a unique camera orientation for every point on your planet. The problem is that it is not possible to constantly choose this orientation - to see this, imagine a vector field on the planet where the vector at each point is a unit vector directed along the direction of the screen x when the camera is above this point. This field cannot be continuous using the Theory of the Hairball . In practice, this means that there will be a moment on the planet when creating something that looks like a small adjustment of the camera’s position will make the planet rotate 180 degrees around the screen. If you want to avoid this, you can choose an orientation instead of the current camera position to minimize the amount of rotation. This means, for example, that the planet may “curl up” on the screen if the camera moves in a closed loop, which may not be desirable in your game. It also requires that your engine can rotate on all three axes.

+2
source

All Articles