0

我正在使用 android opengl 1.1 2d 游戏,该游戏具有车辆的顶视图和相对于车辆速度的相机变焦。当速度增加时,相机会缩小,为玩家提供最佳的道路能见度。

我很难找到准确的方法来检测一个精灵是否可见或者不考虑他的位置和当前的相机变焦。

重要的精度,我所有的游戏对象都在同一个 z 坐标上。我使用 3d 只是为了拍摄效果。(这就是我不需要平截头体复杂计算的原因)

这是我的 GLSurfaceView.Renderer 类的示例

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

当我绘制任何相机相关对象时,我使用这种翻译方法:

gl.glTranslatef(position.x - camera.centerPosition.x , position.y -camera.centerPosition.y , - camera.zDecal);

一切都显示得很好,当他检查对象是否可见时,问题来自我的物理线程:

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);


}

不幸的是,这个物体消失得太快并且出现得太晚了,所以我手动在相机上添加了一些缩小以进行测试。

我做了一些手动测试,发现在计算 xDelta 和 yDelta 时,在相机 z 索引上添加大约 260,效果很好。所以现在是:

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));

因为它是一个 hack,并且幻数可能无法在我想了解我错过的所有设备上运行。我猜这个“260”幻数中有一些东西来自 fov 或比率宽度/高度,可以设置为像素完美检测的公式参数。

有什么猜测吗?

4

1 回答 1

0

我的猜测是你应该使用Math.tan(GameRenderer.fov_radians)而不是Math.atan(GameRenderer.fov_radians).

推理:

如果您使用的是 90 度 fov 的相机,那么xDelta并且yDelta应该是无限大的,对吧?因为相机必须查看整个无限平面。

tan(pi/2) 是无限的(负无限)。atan(pi/2) 只是 1.00388...

tan(pi/4) 为 1,而 atan(pi/4) 为 0.66577...

于 2013-01-22T23:54:00.233 回答