Java 使用LWJGL渲染2D瓷砖的最快方法?
我开始观看使用LWJGL创建2d自上而下游戏的教程,我读到VBO应该很快,但对于每帧渲染48*48个瓷砖,我只能获得大约100FPS的速度,这相当慢,因为我将为游戏添加更多的内容,而不仅仅是一些静态的、不移动或更改的瓷砖 我能做些什么来加快速度?请记住,我刚刚开始学习lwjgl和opengl,所以我可能不会知道很多东西 无论如何,这里是我代码的一些部分(我从代码中删除了一些毫无意义的部分,并用一些描述替换它们): 主回路Java 使用LWJGL渲染2D瓷砖的最快方法?,java,opengl,2d,lwjgl,Java,Opengl,2d,Lwjgl,我开始观看使用LWJGL创建2d自上而下游戏的教程,我读到VBO应该很快,但对于每帧渲染48*48个瓷砖,我只能获得大约100FPS的速度,这相当慢,因为我将为游戏添加更多的内容,而不仅仅是一些静态的、不移动或更改的瓷砖 我能做些什么来加快速度?请记住,我刚刚开始学习lwjgl和opengl,所以我可能不会知道很多东西 无论如何,这里是我代码的一些部分(我从代码中删除了一些毫无意义的部分,并用一些描述替换它们): 主回路 double targetFPS = 240.0; dou
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 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);
}
我将顶点、纹理坐标和索引存储在平铺渲染器中:
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
};
我不知道还有什么可以放在这里,但是完整的源代码和resources+shader文件可以在github上找到。对于您当前的系统,我建议您根据纹理对瓷砖进行分组。创建如下内容:
Map tiles=newhashmap()
然后,当您要渲染瓷砖贴图时,只需为每组瓷砖设置一次纹理,而不是为每个瓷砖设置一次纹理。这为将纹理/纹理ID推送到GPU节省了PCI-E带宽。您可以这样实现(伪代码):
沿着这些线我看到的另一件事是,你将投影矩阵分别推送到每个瓷砖上。运行着色器程序时,给定均匀性的值将保持不变,直到您对其进行更改或程序结束。将投影矩阵均匀设置一次
您似乎每调用一次
renderTile(…)
。如果该值不变,请在渲染过程之前计算一次,然后在renderTile(…)
方法中将其作为变量传入,而不是传入camera
和world
将所有静态分幅捆绑到一个模型中,以便在绘制调用时减少WAAAY(gldrawerelements()
&co.)关联状态更改(&A)。还要查看纹理地图集和/或阵列纹理。我如何才能做到这一点?(捆绑平铺)在顶点
/纹理
/index`数组中没有单个四边形的几何体,而是有整个层的价值。但是,我该怎么做呢?我应该在谷歌搜索答案/教程吗?就像我说的,我是一个彻头彻尾的傻瓜,我不能完全理解我看的教程中的所有内容。那么我可以去掉shader.setUniform()行,在设置投影后开始游戏时只调用它一次吗?如果我这样做了,opengl如何知道将瓷砖放在哪里,因为在第二个集合中,我也传递了包含位置的目标矩阵?我想我误解你了。
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);
}
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
};
for (Texture tex : tile.keySet())
{
BIND TEXTURE
for (Tile tile : tiles.get(tex))
{
SET UNIFORMS
RENDER
}
}