【问题标题】:How can I check if an object(s) are in front of the camera?如何检查物体是否在相机前面?
【发布时间】:2014-12-02 00:16:00
【问题描述】:

我有一些树,它们在游戏中大大滞后,所以我想检查一下这些树是否在镜头前。

我得到了Mathematics forum 的一些帮助,还查看了This link 以帮助我将俯仰/偏航转换为所需的方向矢量。

但是由于某种原因,每当我将相机向左移动时,树木就会变得可见,而每当我将相机向右移动时,它们就会变得不可见(因此,如果相机指向 Z 轴上的 +1,似乎渲染树木,但在 Z 轴上为 -1,它似乎没有渲染它们)。 (请参阅http://i.gyazo.com/cdd05dc3f5dbdc07577c6e41fab3a549 以获得较少跳跃的 .mp4)

我正在使用下面的代码来检查一个物体是否在相机前面:

Ship you = shipsID.get(UID);
int dis = 300;
Vector3f X = new Vector3f(camera.x(), camera.y(), camera.z());
float x = (float) (Math.cos(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
float y = (float) (Math.sin(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
float z = (float) Math.sin(Math.toRadians(camera.pitch()));
Vector3f V = new Vector3f(x, y, z);

for (Tree tree : trees){
    Vector3f Y = new Vector3f(tree.location.x, tree.location.y, tree.location.z);
    Vector3f YMinusX = Y.negate(X);//new Vector3f(Y.x - X.x, Y.y - X.y, Y.z - X.z);
    float dot = Vector3f.dot(YMinusX, V);
    if (dot > 0){
        tree.render();
    }
}

有人能告诉我我在这里做错了什么吗?我不知道是数学..还是代码..还是什么?

相机翻译代码:

 public void applyTranslations() {
    glPushAttrib(GL_TRANSFORM_BIT);
    glMatrixMode(GL_MODELVIEW);
    glRotatef(pitch, 1, 0, 0);
    glRotatef(yaw, 0, 1, 0);
    lastYaw = yaw;
    glRotatef(roll, 0, 0, 1);
    glTranslatef(-x, -y, -z);
    glPopAttrib();
}

更新:

它似乎是相机正在寻找的地方。例如,如果我查看 -Z,什么都不会发生,但如果我查看 +Z,它们都会呈现。 if (dot > 0) code 似乎是 +Z 而不是 +TheCameraRotation。

【问题讨论】:

  • Frustum Culling 是一种更适合移除隐藏几何体的方法。 Check this tutorial.
  • 你能把this checks the distance to the ship*/ if (you.location.x - tree.location.x < dis && you.location.x - tree.location.x > -dis && you.location.z - tree.location.z < dis && you.location.z - tree.location.z > -dis)这行放到可见屏幕上吗?
  • @Coffee 我想我做了你想要的。如果不是,那你能澄清一下吗?
  • 您有两个标准来拒绝树:距离测试和点积测试。您可以通过禁用其中之一轻松找出导致树木消失的原因之一。这将缩小问题的范围。
  • 最可能的问题是你这里计算的相机方向和你渲染时应用的相机变换不一致。在此处未显示的代码中的某处,您必须根据相机参数计算相机(视图)转换。我怀疑它应用相机参数的方式与它们在发布的代码中的使用方式不同。

标签: java opengl math lwjgl


【解决方案1】:

您的相机围绕 Y 旋转偏航,这意味着 Y 是您的向上向量。但是,float z = (float) Math.sin(Math.toRadians(camera.pitch())); 为您的向上向量提供 Z。有不一致之处。我会先在这里交换yz,然后在每一帧打印所有内容,这样你就可以看到旋转相机时会发生什么。也只渲染一棵树并打印dot。例如。您可能会很快注意到只有当您查看树左侧 90 度时,数字才接近 1.0,从而缩小了问题的范围。正如@DWilches 所说,交换 cos/sin 会改变旋转的相位,从而产生这样的效果。

您可以考虑将点积限制在相机的视野范围内。树不只是点仍然存在问题。正如@glampert 建议的那样,更好的方法是针对相机平截头体测试树边界框。

不过,树的几何形状看起来并不那么复杂。优化方面,我会开始尝试更快地绘制它们。你在使用 VBO 吗?也许看看减少绘图调用的方法,例如实例化。甚至可能使用一些模型来制作 LOD 或广告牌。更进一步,广告牌上有多棵树。遮挡剔除方法可用于忽略山后的树木。

[编辑]
由于您的树都大致在一个平面上,您可以将问题限制在相机的偏航上:

float angleToTree = Math.atan2(tree.location.z - camera.z(), tree.location.x - camera.x());
float angleDiff = angleToTree - camera.yaw();
if (angleDiff > Math.PI)
    angleDiff -= 2.0f * Math.PI;
if (angleDiff < -Math.PI)
    angleDiff += 2.0f * Math.PI;
if (abs(angleDiff) < cameraFOV + 0.1f) //bias as trees are not points
    tree.render();

【讨论】:

  • 我现在已经实现了 LOD 的东西。两个月前有人问过这个问题:但是树木(和我即将实施的草!)仍然滞后,这就是为什么我不想渲染我看不到的那些。顺便问一下,我怎么用这样的广告牌?
  • @Joehot200 我会将树渲染为纹理(通过 FBO)并绘制一个带有该纹理的四边形,作为最远的 LOD 模型之一。然后可能会使用不同的旋转渲染一些纹理,因此它们看起来并不相同。
  • 点积在 -10,000 到 +10,000 之间(我认为还有更多)。这正常吗?
  • @Joehot200 哦,对了,这就是到树的距离。希望当您直接注视/远离树时,最小值/最大值与此一致。如果不是,那么问题很可能与您的偏航/俯仰/滚动计算与 OpenGL 旋转不匹配。
  • 点积似乎会受到影响,具体取决于相机的朝向,而不是相机的位置。
【解决方案2】:

你可以这样写吗

    Ship you = shipsID.get(UID);
    int dis = 300;
    Vector3f X = new Vector3f(camera.x(), camera.y(), camera.z());
    float x = (float) (Math.cos(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
    float y = (float) (Math.sin(Math.toRadians(camera.yaw()))*Math.cos(Math.toRadians(camera.pitch())));
    float z = (float) Math.sin(Math.toRadians(camera.pitch()));
    Vector3f V = new Vector3f(x, y, z);

    for (Tree tree : trees){
        Vector3f Y = new Vector3f(tree.location.x, tree.location.y, tree.location.z);
        Vector3f YMinusX = Y.negate(X);//new Vector3f(Y.x - X.x, Y.y - X.y, Y.z - X.z);
        float dot = Vector3f.dot(YMinusX, V);
        if (dot > 0){
            tree.render();
        }
    }

如您所见,每棵树执行的计算要少得多。

【讨论】:

  • 赞成,因为这是一个很好的建议(当时我只是想偷懒并让它工作),但它并没有解决问题。
  • 有点跑题了,但由于主要问题是游戏滞后:您还可以通过存储多个树对象来大大提高渲染速度。就像近距离的物体非常详细,中等范围的一些中等细节的树木,以及远处的树木作为广告牌。当然,您希望它与上面提到的平截头体剔除配对。
【解决方案3】:

对于我看到的here,正确的公式是:

x = Math.sin(pitch) * Math.cos(yaw);
y = Math.sin(pitch) * Math.sin(yaw);
z = Math.cos(pitch);

你能试试吗?

【讨论】:

  • 制作该教程的人在 Spigot 上,所以我会在那里私下给他发消息,看看他是否对它为什么不起作用有任何见解。
  • @Joehot200 这是因为它期望 Z 向上的不同坐标系。我工作,只是不是你的情况。
  • 但是.. Z 不起来。 Y 起来了。
猜你喜欢
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 1970-01-01
  • 2014-09-30
  • 1970-01-01
  • 2020-05-27
相关资源
最近更新 更多