在 OpenGL 中,如何使我的天空盒不覆盖我的任何实体?

In OpenGL, how do I make it so that my skybox does not cover any of my entities?

我正在 Java 中使用 LWJGL(ThinMatrix 的教程)开发 OpenGL 游戏,我刚刚添加了我的天空盒。然而,正如您从图片中看到的那样,它正在穿过树木并覆盖某个点后面的所有东西。

这是我的天空盒渲染代码:

public void render(Camera camera, float r, float g, float b) {
    shader.start();
    shader.loadViewMatrix(camera);
    shader.loadFogColor(r, g, b);
    GL30.glBindVertexArray(cube.getVaoID());
    GL20.glEnableVertexAttribArray(0);
    bindTextures();
    GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, cube.getVertexCount());
    GL30.glBindVertexArray(0);
    shader.stop();
}

private void bindTextures() {
    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture);
    GL13.glActiveTexture(GL13.GL_TEXTURE1);
    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, nightTexture);
    shader.loadBlendFactor(getBlendFactor());
}

此外,如果需要,这是我的主渲染器代码:

public void render(List<Light> lights, Camera camera){
    prepare();
    shader.start();
    shader.loadSkyColor(RED, GREEN, BLUE);
    shader.loadLights(lights);
    shader.loadViewMatrix(camera);
    renderer.render(entities);
    shader.stop();
    terrainShader.start();
    terrainShader.loadSkyColor(RED, GREEN, BLUE);
    terrainShader.loadLight(lights);
    terrainShader.loadViewMatrix(camera);
    terrainRenderer.render(terrains);
    terrainShader.stop();
    skyboxRenderer.render(camera, RED, GREEN, BLUE);
    terrains.clear();
    entities.clear();
}

您可能想看看 How can I increase distance (zfar/gluPerspective) where openGL stops drawing objects? 该实例中的问题是天空盒本身太小并且与几何体相交。

我还看到您先渲染地形,然后再渲染天空盒。我会尝试在那里翻转订单;先画天空盒再画地形

首先,您应该移除天空盒并重新渲染场景,以检查是否是天空盒剪裁了树。

如果是天空盒,只需缩放天空盒,使其包含地形中的所有物体。

如果不是,很可能是相机的问题(就像Hanston说的)。您需要至少在天空盒后面设置远裁剪平面。也就是说,它应该比你的天空盒的直径大。

如果要缩放天空盒或任何其他对象,请使用 transformationMatrix。游戏引擎使用一个 4x4 矩阵来控制模型的大小、位置和旋转。您可以在函数 loadModelMatrix 中查看来源 TerrainRenderer.java 中的示例。它创建一个变换矩阵并将其上传到着色器中。你应该做同样的事情,但将比例参数更改为你想要的。

我不熟悉LWJGL,你可以写shader吗?在 plain opengl 中,您不必担心天空盒立方体的大小,如果您愿意,它可以是 {1.0, 1.0, 1.0}。你需要做的是首先将你的相机放在 {0.0, 0.0, 0.0} 并使天空盒在你场景中的所有东西上都无法通过深度测试,你可以通过使标准化设备坐标中天空盒的 z 值为 1.0 来实现.

在顶点着色器中执行此操作

gl_Position = (mvp_mat * vec4(xyz, 1.0)).xyww;

透视除以w后,zw / w1.0

您可以做两件事

如果先绘制天空盒,则可以禁用深度测试 glDisable(GL_DEPTH_TEST) 或深度写入 glDepthMask(false)。这将防止您的天空盒绘制深度值,并且天空盒永远不会位于稍后绘制的任何内容之前。

如果你最后画你的天空盒,你可以通过使用顶点坐标 w-coordinate 为 0 来使它无限大。一个顶点 (x y z 0) 意味着它是一个无限远的顶点向量的方向 (x y z)。为了防止裁剪,你必须启用深度限制 glEnable(GL_DEPTH_CLAMP) 这将防止 OpenGl 裁剪掉你的天空盒面,并且你确定天空盒始终处于最大距离并且永远不会隐藏你之前绘制的任何东西。

第二种方法的优点是在深度测试范围内。因为您已经为场景编写了深度值,所以 OpenGL 管道可以跳过场景中已经覆盖的天空盒像素的计算。但是天空盒的片段着色器通常是非常微不足道的,所以应该不会有太大的不同。