【问题标题】:OpenGL (LWJGL 3) culling terrain vertices/triangles that are not in the view frustumOpenGL (LWJGL 3) 剔除不在视锥体中的地形顶点/三角形
【发布时间】:2021-08-29 16:18:15
【问题描述】:

我目前正在尝试在我的 3D 游戏中实现截锥体剔除,它与实体有效地工作,因为它们有一个边界框 (AABB),并且更容易检查截锥体的框。说到这里,我将如何剔除地形? (它在物理上不能有 AABB 或球体)

截锥体类(我使用内置的 JOML 类):

import org.joml.FrustumIntersection;
import org.joml.Matrix4f;

import engine.Terrians.Terrain;
import engine.maths.Matrices;
import engine.maths.Vector3f;
import engine.objects.Camera;
import engine.physics.AABB;

public class FrustumG {

    private final Matrix4f projectionViewMatrix;

    private FrustumIntersection frustumInt;

    public FrustumG() {
        projectionViewMatrix = new Matrix4f().identity();
        frustumInt = new FrustumIntersection();
    }
    
    public void update(Matrix4f projectionMatrix, Matrix4f viewMatrix) {
        projectionViewMatrix.set(projectionMatrix);
        projectionViewMatrix.mul(viewMatrix);
        
        frustumInt.set(projectionViewMatrix);
    }
    
    public boolean intersectsAABB(AABB aabb) {
        return frustumInt.testAab(aabb.getWorldMinX(), aabb.getWorldMinY(), aabb.getWorldMinZ(), 
                                  aabb.getWorldMaxX(), aabb.getWorldMaxY(), aabb.getWorldMaxZ());
    }
    
    public boolean intersectsPoint(Vector3f point) {
        return frustumInt.testPoint(point.getX(), point.getY(), point.getZ());
    }
    
}

我的网格类存储地形的顶点信息。我不想每帧都编辑和更新顶点 VBO,因为我用谷歌搜索它会影响游戏的性能(而且我还必须编辑索引列表,并在每帧循环遍历两个列表)。我看到一些网站说用GL_DYNAMIC_DRAW而不是GL_STATIC_DRAW,但我没看懂。

这是网格类:

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil;

public class Mesh {
    private float[] verticesData;
    private int[] indicesData;
    private float[] textureData;
    private float[] normalsData;
    private int vao, pbo, ibo, cbo, tbo, nbo;
    private Texture texture;
    
    public Mesh(float[] verticesArray, int[] indices, float[] normalsArray, float[] texturesArray) {
        this.verticesData = verticesArray;
        this.indicesData = indices;
        this.textureData = texturesArray;
        this.normalsData = normalsArray;
    }
    
    public Mesh(float[] positions, int dimensions) {
        this.verticesData = positions;
        vao = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(vao);
         
        FloatBuffer positionBuffer = MemoryUtil.memAllocFloat(positions.length);
        positionBuffer.put(positions).flip();
        
        pbo = storeData(positionBuffer, 0, dimensions);
    }
    
    public void createTextures(String filepath) {
        Texture texture = new Texture(filepath);
        texture.create();
        this.texture = texture;
    }
    
    public int loadCubeMap(String[] textureFiles, String textureMainSystemPath) {
        int texID = GL11.glGenTextures();
        GL30.glActiveTexture(GL30.GL_TEXTURE0);
        GL30.glBindTexture(GL30.GL_TEXTURE_CUBE_MAP, texID);
        
        for(int i = 0; i < textureFiles.length; i++) {
            Texture.createSkybox(textureMainSystemPath + textureFiles[i] + ".png", i);
        }
        
        GL30.glTexParameteri(GL30.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_MAG_FILTER, GL30.GL_LINEAR);
        GL30.glTexParameteri(GL30.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_MIN_FILTER, GL30.GL_LINEAR);
        
        return texID;
    }
    
    public void createMeshes() {    
        vao = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(vao);
        
        FloatBuffer positionBuffer = MemoryUtil.memAllocFloat(verticesData.length);
        positionBuffer.put(verticesData).flip();
        
        pbo = storeData(positionBuffer, 0, 3);
        
        /**FloatBuffer colorBuffer = MemoryUtil.memAllocFloat(vertices.length * 3);
        float[] colorData = new float[vertices.length * 3];
        for (int i = 0; i < vertices.length; i++) {
            colorData[i * 3] = vertices[i].getColor().getX();
            colorData[i * 3 + 1] = vertices[i].getColor().getY();
            colorData[i * 3 + 2] = vertices[i].getColor().getZ();
        }
        colorBuffer.put(colorData).flip();
        
        cbo = storeData(colorBuffer, 1, 3);**/
        
        FloatBuffer textureBuffer = MemoryUtil.memAllocFloat(verticesData.length);
        textureBuffer.put(textureData).flip();
        tbo = storeData(textureBuffer, 1, 2);
        
        FloatBuffer normalBuffer = MemoryUtil.memAllocFloat(verticesData.length);
        normalBuffer.put(normalsData).flip();
        nbo = storeData(normalBuffer, 2, 3);
        
        IntBuffer indicesBuffer = MemoryUtil.memAllocInt(indicesData.length);
        indicesBuffer.put(indicesData).flip();
        
        ibo = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ibo);
        GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL15.GL_STATIC_DRAW);
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
    }
    
    private int storeData(FloatBuffer buffer, int index, int size) {
        int bufferID = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferID);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
        GL20.glVertexAttribPointer(index, size, GL11.GL_FLOAT, false, 0, 0);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
        return bufferID;
    }
    
    public void destroyBuffers() {
        GL15.glDeleteBuffers(pbo);
        GL15.glDeleteBuffers(cbo);
        GL15.glDeleteBuffers(ibo);
        GL15.glDeleteBuffers(tbo);
        GL15.glDeleteBuffers(nbo);
        
        GL30.glDeleteVertexArrays(vao);
    }

    public float[] getVertices() {
        return verticesData;
    }
    
    public float[] getPositions2D() {
        return verticesData;
    }

    public int[] getIndices() {
        return indicesData;
    }

    public int getVAO() {
        return vao;
    }

    public int getPBO() {
        return pbo;
    }
    
    public int getCBO() {
        return cbo;
    }

    public int getIBO() {
        return ibo;
    }
    
    public int getTBO() {
        return tbo;
    }
    
    public int getNBO() {
        return nbo;
    }

    public Texture getTexture() {
        return texture;
    }
}

有没有更有效的方法来截断地形的顶点/三角形?

【问题讨论】:

    标签: java opengl optimization lwjgl frustum


    【解决方案1】:

    确定应剔除地形的哪一部分的一种方法是使用四叉树(对于高度图)或八叉树(对于体素图)。基本上,您将地形分成小块,然后相应地进一步划分。然后,您可以测试这些块是否在您的视锥中,并在必要时剔除它们。这种技术已经被详细讨论过:

    我看到一些网站说使用GL_DYNAMIC_DRAW而不是GL_STATIC_DRAW,但我没看懂。

    这些是 OpenGL 关于如何访问数据的使用提示,因此实现能够对如何存储/使用数据进行某些优化。

    usage 是 GL 实现关于如何访问缓冲区对象的数据存储的提示。这使 GL 实现能够做出更智能的决策,这些决策可能会显着影响缓冲区对象的性能。 (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml)

    请注意,这些只是指示,没有限制:

    但是,它不限制数据存储的实际使用。

    因为您可能会不断更新您的 VBO 和 IBO(请参阅剔除)并且只想绘制它们 GL_DYNAMIC_DRAW 将是一个不错的选择:

    数据存储内容将被反复修改(因为剔除)并多次使用。数据存储内容由应用程序修改并用作 GL 绘图和图像规范命令的源。

    我在谷歌上搜索过它会影响游戏的性能

    好吧,剔除地形会消耗一些性能,但最终,它可能会提高性能,因为可以丢弃许多顶点(三角形)。这种性能提升可能会随着更大的地形而增长。

    【讨论】:

    • 谢谢!这个解释和网站帮助很大!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    相关资源
    最近更新 更多