I m woring on an android opengl 1.1 2d game with a top view on a vehicule and a camera zoom relative to the vehicule speed. When the speed increases the camera zoom out to offer the player a best road visibility.
I have litte trouble finding the exact way to detect if a sprite is visible or not regarding his position and the current camera zoom.
Important precision, all of my game’s objects are on the same z coord. I use 3d just for camera effect. (that’s why I do not need frustrum complicated calculations)
here is a sample of my GLSurfaceView.Renderer class
public static float fov_degrees = 45f;
public static float fov_radians = fov_degrees / 180 * (float) Math.PI;
public static float aspect; //1.15572 on my device
public static float camZ; //927 on my device
@Override
public void onSurfaceChanged(GL10 gl, int x, int y) {
aspect = (float) x / (float) y;
camZ = y / 2 / (float) Math.tan(fov_radians / 2);
Camera.MINIDECAL = y / 4; // minimum cam zoom out (192 on my device)
if (x == 0) { // Prevent A Divide By Zero By
x = 1; // Making Height Equal One
}
gl.glViewport(0, 0, x, y); // Reset The Current Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); // Select The Projection Matrix
gl.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(gl, fov_degrees, aspect , camZ / 10, camZ * 10);
GLU.gluLookAt(gl, 0, 0, camZ, 0, 0, 0, 0, 1, 0); // move camera back
gl.glMatrixMode(GL10.GL_MODELVIEW); // Select The Modelview Matrix
gl.glLoadIdentity(); // Reset The Modelview Matrix
when I draw any camera relative object I use this translation method :
gl.glTranslatef(position.x - camera.centerPosition.x , position.y -camera.centerPosition.y , - camera.zDecal);
Eveything is displayed fine, the problem comes from my physic thread when he checks if an object is visible or not:
public static boolean isElementVisible(Element element) {
xDelta = (float) ((camera.zDecal + GameRenderer.camZ) * GameRenderer.aspect * Math.atan(GameRenderer.fov_radians));
yDelta = (float) ((camera.zDecal + GameRenderer.camZ)* Math.atan(GameRenderer.fov_radians));
//(xDelta and yDelta are in reallity updated only ones a frame or when camera zoom change)
Camera camera = ObjectRegistry.INSTANCE.camera;
float xMin = camera.centerPosition.x - xDelta/2;
float xMax = camera.centerPosition.x + xDelta/2;
float yMin = camera.centerPosition.y - yDelta/2;
float yMax = camera.centerPosition.y + yDelta/2;
//xMin and yMin are supposed to be the lower bounds x and y of the visible plan
// same for yMax and xMax
// then i just check that my sprite is visible on this rectangle.
Vector2 phD = element.getDimToTestIfVisibleOnScreen();
int sizeXd2 = (int) phD.x / 2;
int sizeYd2 = (int) phD.y / 2;
return (element.position.x + sizeXd2 > xMin)
&& (element.position.x - sizeXd2 < xMax)
&& (element.position.y - sizeYd2 < yMax)
&& (element.position.y + sizeYd2 > yMin);
}
Unfortunately the object were disapearing too soon and appearing to late so i manuelly added some zoom out on the camera for test purpose.
I did some manual test and found that by adding approx 260 to the camera z index while calculating xDelta and yDelta it, was good.
So the line is now :
xDelta = (float) ((camera.zDecal + GameRenderer.camZ + 260) * GameRenderer.aspect * Math.atan(GameRenderer.fov_radians));
yDelta = (float) ((camera.zDecal + GameRenderer.camZ + 260)* Math.atan(GameRenderer.fov_radians));
Because it’s a hack and the magic number may not work on every device I would like to understand what i missed. I guess there is something in that “260” magic number that comes from the fov or ration width/height and that could be set as a formula parameter for pixel perfect detection.
Any guess ?
My guess is that you should be using
Math.tan(GameRenderer.fov_radians)instead ofMath.atan(GameRenderer.fov_radians).Reasoning:
If you used a camera with 90 degree fov, then
xDeltaandyDeltashould be infinitely large, right? Since the camera would have to view the entire infinite plane.tan(pi/2) is infinite (and negative infinity). atan(pi/2) is merely 1.00388…
tan(pi/4) is 1, compared to atan(pi/4) of 0.66577…