java - LWJGL 加速渲染

标签 java performance opengl rendering lwjgl

我正在使用 LWJGL 创建某种 Minecraft 克隆。

问题是我只能获得大约 20 FPS。 (每个方向约32个街区) 另外,当我更改 block 时, View 会卡住几毫秒。

我正在使用 Slick 加载纹理。为了渲染 block ,我使用 VBO 作为纹理和顶点(没有 VAO、着色器或法线)。每个 block 由 6 个四边形组成,其中由 2 个三角形组成。 block 之间的面不会被渲染。每一帧渲染线程都会检查所有 32 * 32 block 是否已加载到缓冲区中以及是否应该加载(取决于玩家位置)。如果需要,则会创建 vbo 并将句柄保存到列表中。如果 block 太远,缓冲区就会被删除。渲染时,当前在显卡内存中的所有 vbo(句柄保存在列表中)都会被绘制。

如何加快渲染速度?我应该让缓冲区始终处于“加载”状态并只绘制所需的对象吗?法线、VAO 或着色器可以帮助我获得巨大的改进吗?不过,如果我获得更高的帧速率,将会有更多的 block ,而不仅仅是一个盘子,我计划导入 .obj。

Minecraft 在我认为的 DisplayLists 中呈现。这会是一个解决方案吗?为每个 block 或 block 创建一个显示列表,并在 block 或 block 发生更改时重新编译它们?

编辑:我用 VisualVM 测量发现最耗时的方法是 glDrawArrays()。

一些源代码:

渲染:

public static void render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    for(VBO vbo : vbos)
    {
        //disable texture smoothing
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glBindTexture(GL_TEXTURE_2D, vbo.texture);
        glBindBuffer(GL_ARRAY_BUFFER, vbo.vertex_handle);
        glVertexPointer(vbo.vertex_size, GL_FLOAT, 0, 0l);
        glBindBuffer(GL_ARRAY_BUFFER, vbo.texture_handle);
        glTexCoordPointer(vbo.texture_size, GL_FLOAT, 0, 0l);

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glDrawArrays(GL_TRIANGLES, 0, vbo.vertices);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
}

block 加载检测:

int chunkX = (int)(camera.getX() * (-1) / GameData.CHUNK_SIZE);
        int chunkZ = (int)(camera.getZ() * (-1) / GameData.CHUNK_SIZE);

        for(int cx = 0;cx < GameData.NUMBER_OF_CHUNKS;cx++)
        {
            for(int cz = 0;cz < GameData.NUMBER_OF_CHUNKS;cz++)
            {
                boolean shouldBeLoaded = (Math.abs(chunkX - cx) <= 2 && Math.abs(chunkZ - cz) <= 2);

                if(GameData.chunks[cx][cz] != shouldBeLoaded)
                {
                    if(shouldBeLoaded)
                        Util.loadChunk(cx, cz);//loads every block in the chunk
                    else
                        Util.unloadChunk(cx, cz);
                }
            }
        }

block 加载:

public void load()
{
    try{
        if(GameData.map[x][y+1][z] == null || GameData.map[x][y+1][z].id == 2)
            top = Util.createQuad(x, y+1, z, 1, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x][y-1][z] == null || GameData.map[x][y-1][z].id == 2)
            bot = Util.createQuad(x, y, z, 1, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x-1][y][z] == null || GameData.map[x-1][y][z].id == 2)
            left = Util.createQuad(x, y, z, 0, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x+1][y][z] == null || GameData.map[x+1][y][z].id == 2)
            right = Util.createQuad(x+1, y, z, 0, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x][y][z-1] == null || GameData.map[x][y][z-1].id == 2)
            front = Util.createQuad(x, y, z, 2, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x][y][z+1] == null || GameData.map[x][y][z+1].id == 2)
            back = Util.createQuad(x, y, z+1, 2, id);
    }catch(IndexOutOfBoundsException e){};
}

Util.createQuad()

public static VBO createQuad(float x, float y, float z, int axis, int id)
{
    boolean xA = axis == 0;
    boolean yA = axis == 1;//senkrecht
    boolean zA = axis == 2;

    FloatBuffer vertex_data = BufferUtils.createFloatBuffer(6 * 3);
    if(xA)
    {
        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y, z+1, });
        vertex_data.put(new float[] { x, y+1, z+1, });

        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y+1, z, });
        vertex_data.put(new float[] { x, y+1, z+1, });
    }
    if(yA)
    {
        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y, z+1, });
        vertex_data.put(new float[] { x+1, y, z+1, });

        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x+1, y, z, });
        vertex_data.put(new float[] { x+1, y, z+1, });
    }
    if(zA)
    {
        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x+1, y, z, });
        vertex_data.put(new float[] { x+1, y+1, z, });

        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y+1, z, });
        vertex_data.put(new float[] { x+1, y+1, z, });
    }

    FloatBuffer texture_data = BufferUtils.createFloatBuffer(6 * 2);
    texture_data.put(new float[] { 0f, 0f, });
    texture_data.put(new float[] { 1f, 0f, });
    texture_data.put(new float[] { 1f, 1f, });

    texture_data.put(new float[] { 0f, 0f, });
    texture_data.put(new float[] { 0f, 1f, });
    texture_data.put(new float[] { 1f, 1f, });


    vertex_data.flip();
    texture_data.flip();

    int vbo_vertex_handle = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex_handle);
    glBufferData(GL_ARRAY_BUFFER, vertex_data, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    int vbo_texture_handle = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo_texture_handle);
    glBufferData(GL_ARRAY_BUFFER, texture_data, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

    VBO vbo = new VBO(vbo_vertex_handle, vbo_texture_handle, renderEngine.textures.get(id), 6, 3, 2);

    if(id == 2)//transparent
        renderEngine.vbos.add(vbo);
    else
        renderEngine.vbos.add(0, vbo);;

    return vbo;
}

最佳答案

我目前正在使用显示列表,因为我对 lwjgl 还很陌生,并且发现 VBO 非常令人困惑,我所做的只是检查玩家是否移动了 16 个方 block 或更多,或者删除/放置了一个方 block ,这就是我更新我的列表,否则我不会更新列表,您还应该停止渲染您看不到的任何面,因此在检查要绘制哪些面时,您还应该检查它们是否不在您的 View 范围内,这是一个示例我愿意;此示例检查我是否应该渲染某个 block 的顶面: if(PlayerY < BlockY) { then return false; },这样您就不需要渲染您可能看不到的东西。

使用显示列表,在 48*48 的 View 范围内,我可以获得大约 200 - 300 FPS,在 128 时,您将获得大约 20 - 100 FPS。 编辑: 如果您还没有开始使用纹理图集,您也应该开始使用,这会减少 bind() 调用,从而使其速度更快。

祝你好运,希望我能有所帮助:)

关于java - LWJGL 加速渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25435823/

相关文章:

Java Scanner 通过读取带有空格的字符串来忽略接下来的问题

java - 控制Lucene中文档的磁盘位置

java - InputStream 对象在声明后关闭

javascript - Setinterval 口吃生成随机数序列

python - 两个看似相似的 dict 语句的性能差异?

java - 简单 JOGL 程序中的 glTranslate 错误

java - 并发写入 GAE 数据存储实体的不同属性

python - 为什么这个 lambda 函数比 for 循环版本更懒?

OpenGL 恐龙模型错误 : gluTessCallback issue

opengl - 在绘制到屏幕之前,opengl 纹理中的意外像素发生变化