2017-06-27 37 views
0

我开始使用LWJGL观看these创建2d自上而下游戏的教程,我读到VBO应该很快,但为了渲染每帧48 * 48的瓦片,我只得到大约100FPS,这很慢,因为我会添加更多游戏中的东西,而不仅仅是一些静态的,而不是移动或变化的瓷砖。使用LWJGL呈现2D贴图的最快方法?

我该怎么做才能让这个更快?请记住,我刚开始学习lwjgl和opengl,所以我可能不会知道很多事情。

不管怎么说,这里是我的代码的某些部分(我删除也曾经是有点意义的代码中的一些部分,并用一些描述取而代之):

主循环

double targetFPS = 240.0; 
     double targetUPS = 60.0; 

     long initialTime = System.nanoTime(); 
     final double timeU = 1000000000/targetUPS; 
     final double timeF = 1000000000/targetFPS; 
     double deltaU = 0, deltaF = 0; 
     int frames = 0, updates = 0; 
     long timer = System.currentTimeMillis(); 

     while (!window.shouldClose()) { 
      long currentTime = System.nanoTime(); 
      deltaU += (currentTime - initialTime)/timeU; 
      deltaF += (currentTime - initialTime)/timeF; 
      initialTime = currentTime; 

      if (deltaU >= 1) { 
       // --- [ update ] --- 
       --INPUT HANDLING FOR BASIC MOVEMENT, CLOSING THE GAME AND TURNING VSYNC ON AND OFF USING A METHOD FROM THE INPUT HANDLER CLASS-- 

       world.correctCamera(camera, window); 

       window.update(); 

       updates++; 
       deltaU--; 
      } 

      if (deltaF >= 1) { 
       // --- [ render ] --- 
       glClear(GL_COLOR_BUFFER_BIT); 
       world.render(tileRenderer, shader, camera, window); 
       window.swapBuffers(); 

       frames++; 
       deltaF--; 
      } 
      --PRINTING THE FPS AND UPS EVERY SECOND-- 
     }

输入处理程序使用方法:

I have this in my constructor: 
this.keys = new boolean[GLFW_KEY_LAST]; 
for(int i = 0; i < GLFW_KEY_LAST; i++) 
    keys[i] = false; 

And here are the methods: 
public boolean isKeyDown(int key) { 
    return glfwGetKey(window, key) == 1; 
} 
public boolean isKeyPressed(int key) { 
    return (isKeyDown(key) && !keys[key]); 
} 
public void update() { 
    for(int i = 32; i < GLFW_KEY_LAST; i++) 
     keys[i] = isKeyDown(i); 
} 

这是从世界一流的渲染方法:

public void render(TileRenderer renderer, Shader shader, Camera camera, Window window) { 
    int posX = ((int) camera.getPosition().x + (window.getWidth()/2))/(scale * 2); 
    int posY = ((int) camera.getPosition().y - (window.getHeight()/2))/(scale * 2); 
    for (int i = 0; i < view; i++) { 
     for (int j = 0; j < view; j++) { 
      Tile t = getTile(i - posX, j + posY); 
      if (t != null) 
       renderer.renderTile(t, i - posX, -j - posY, shader, world, camera); 
     } 
    } 
} 

这是从TileRenderer的renderTile()方法:

public void renderTile(Tile tile, int x, int y, Shader shader, Matrix4f world, Camera camera) { 
    shader.bind(); 
    if (tileTextures.containsKey(tile.getTexture())) 
     tileTextures.get(tile.getTexture()).bind(0); 

    Matrix4f tilePosition = new Matrix4f().translate(new Vector3f(x * 2, y * 2, 0)); 
    Matrix4f target = new Matrix4f(); 

    camera.getProjection().mul(world, target); 
    target.mul(tilePosition); 

    shader.setUniform("sampler", 0); 
    shader.setUniform("projection", target); 

    model.render(); 
} 

这是构造和从模型类渲染方法:

public Model(float[] vertices, float[] texture_coords, int[] indices) { 
    draw_count = indices.length; 

    v_id = glGenBuffers(); 
    glBindBuffer(GL_ARRAY_BUFFER, v_id); 
    glBufferData(GL_ARRAY_BUFFER, createBuffer(vertices), GL_STATIC_DRAW); 

    t_id = glGenBuffers(); 
    glBindBuffer(GL_ARRAY_BUFFER, t_id); 
    glBufferData(GL_ARRAY_BUFFER, createBuffer(texture_coords), GL_STATIC_DRAW); 

    i_id = glGenBuffers(); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id); 

    IntBuffer buffer = BufferUtils.createIntBuffer(indices.length); 
    buffer.put(indices); 
    buffer.flip(); 

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW); 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
} 

public void render() { 
    glEnableVertexAttribArray(0); 
    glEnableVertexAttribArray(1); 

    glBindBuffer(GL_ARRAY_BUFFER, v_id); 
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); 

    glBindBuffer(GL_ARRAY_BUFFER, t_id); 
    glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0); 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id); 
    glDrawElements(GL_TRIANGLES, draw_count, GL_UNSIGNED_INT, 0); 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    glDisableVertexAttribArray(0); 
    glDisableVertexAttribArray(1); 
} 

我存储顶点,纹理COORDS和指数在瓷砖渲染器:

float[] vertices = new float[]{ 
      -1f, 1f, 0, //top left  0 
      1f, 1f, 0, //top right  1 
      1f, -1f, 0, //bottom right 2 
      -1f, -1f, 0, //bottom left 3 
    }; 

    float[] texture = new float[]{ 
      0, 0, 
      1, 0, 
      1, 1, 
      0, 1, 
    }; 

    int[] indices = new int[]{ 
      0, 1, 2, 
      2, 3, 0 
    }; 

我不知道还有什么要放在这里,但完整的源代码和资源+着色器文件可在github here上找到。

+0

将你所有的静态拼图打包成一个模型,以便在绘制调用('glDrawElements()'&co。)和相关的状态改变时减少waaaaay。也看看纹理地图集和/或数组纹理。 – genpfault

+0

我该怎么做?(捆绑瓷砖) –

+0

您的'vertices' /'texture'/indices'数组中没有单个quad的几何值,您可以获得整个图层的价值。 – genpfault

回答

0

随着你目前的系统,我会建议做的是根据纹理对你的瓷砖进行分组。像这样创造的东西:

Map<Texture, List<Tile>> tiles = new HashMap<Texture, List<Tile>>()

然后,当你去渲染你的图块的地图,你只需要每瓦每组瓷砖一旦设置纹理,而不是一次。这节省了将纹理/纹理ID推送到GPU的PCI-E带宽。你会实现,像这样(伪代码):

for (Texture tex : tile.keySet()) 
{ 
    BIND TEXTURE 
    for (Tile tile : tiles.get(tex)) 
    { 
     SET UNIFORMS 
     RENDER 
    } 
} 

别的东西,我沿着这些线路看是你的投影矩阵分别推到每瓦。在运行着色器程序时,给定的制服的值保持不变,直到您更改它或程序结束为止。将投影矩阵均匀设置一次。

这似乎也是你打电话给每个renderTile(...)。如果值不变,在渲染过程之前计算一次,然后将其作为变量传递给renderTile(...)方法,而不是传入cameraworld

+0

所以我可以摆脱shader.setUniform()行,并在设置投影后开始游戏时只调用它一次?如果我这样做,opengl如何知道在哪里放置tile,因为在第二集中,我通过了包含位置的目标矩阵吗?我想我误解了你。 –