需要帮助优化 LibGDX、SpriteBatch 上的纹理绘制
Need help to optimize texture drawing on LibGDX, SpriteBatch
我正在使用 LibGDX 将我的游戏 Hold & Drag 从 Swift (SpriteKit) 转换为 Android,我创建了 'SpriteKit' api Xcode.
官方的小克隆
我正在寻找优化纹理渲染的方法,尤其是因为 FPS 下降 (45-60 /60 fps)
当我不绘制纹理时,我得到 60(最大值)。
希望您能尽可能高效地帮助我!
@Override
public void draw() {
if (texture == null)
return;
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
spriteBatch.setTransformMatrix(getTransformMatrix());
spriteBatch.begin();
Color color = spriteBatch.getColor();
color.a = getAlpha();
spriteBatch.setColor(color);
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
spriteBatch.end();
Gdx.gl.glDisable(GL20.GL_BLEND);
}
public List<SKNode> getParents() {
List<SKNode> parents = new ArrayList<>();
if (parent != null) {
parents.add(parent);
parents.addAll(parent.getParents());
}
return parents;
}
public Matrix4 getTransformMatrix() {
List<SKNode> nodes = getParents();
Collections.reverse(nodes);
nodes.add(this);
Matrix4 transformMatrix = new Matrix4();
transformMatrix.idt();
for (SKNode node : nodes) {
transformMatrix.translate(node.position.x + node.origin.x, node.position.y + node.origin.y, 0);
transformMatrix.rotate(0, 0, 1, node.zRotation);
transformMatrix.scale(node.xScale, node.yScale, 0);
transformMatrix.translate(-node.origin.x, -node.origin.y, 0);
}
return transformMatrix;
}
执行导致精灵批次"flush"的事情很慢,这意味着它必须发出许多OpenGL命令并传输顶点数据等。调用[=11时会发生刷新=] 但如果您出现以下情况也会发生:
- 使用与上次绘制的不同的纹理实例绘制一些东西
- 更改投影或变换矩阵
- Enable/disable 混合
所以你想要组织起来,这样你就不会在你绘制的每个对象上触发刷新。通常所做的是开始批处理,然后使用包含所有所需参数的 spriteBatch.draw()
方法之一在其特定位置绘制每个精灵。像这样:
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (GameObject obj : myGameObjects)
obj.draw();
batch.end();
//And in your game object / sprite class
public void draw() {
if (texture == null)
return;
spriteBatch.setColor(1f, 1f, 1f, getAlpha());
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
}
请注意,以上内容假设您在每个对象中引用相同的精灵批处理实例。
现在,为了让它表现得更像 SpriteKit(我假设因为我没有使用过它),你的每个对象都需要一个转换。但是你不想调用 setTransformMatrix
否则你会触发同花顺。相反,您可以使用 Affine2 class 而不是 Matrix4。它的功能同样适用于保存 2D 对象的变换数据。然后你可以使用 spriteBatch.draw(textureRegion, width, height, affine2Transform)
来绘制它而不会触发刷新。
为避免使用不同的纹理实例触发刷新,您应该使用 TextureAtlas 和纹理区域。您可以在其 wiki 上的 LibGDX 文档中阅读相关内容。
顺便说一句,使用 SpriteBatch 时,您无需调用 OpenGL 来启用和禁用混合。这是由 SpriteBatch 内部处理的。改为调用 spriteBatch.enableBlending()
。
我正在使用 LibGDX 将我的游戏 Hold & Drag 从 Swift (SpriteKit) 转换为 Android,我创建了 'SpriteKit' api Xcode.
官方的小克隆我正在寻找优化纹理渲染的方法,尤其是因为 FPS 下降 (45-60 /60 fps) 当我不绘制纹理时,我得到 60(最大值)。
希望您能尽可能高效地帮助我!
@Override
public void draw() {
if (texture == null)
return;
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
spriteBatch.setTransformMatrix(getTransformMatrix());
spriteBatch.begin();
Color color = spriteBatch.getColor();
color.a = getAlpha();
spriteBatch.setColor(color);
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
spriteBatch.end();
Gdx.gl.glDisable(GL20.GL_BLEND);
}
public List<SKNode> getParents() {
List<SKNode> parents = new ArrayList<>();
if (parent != null) {
parents.add(parent);
parents.addAll(parent.getParents());
}
return parents;
}
public Matrix4 getTransformMatrix() {
List<SKNode> nodes = getParents();
Collections.reverse(nodes);
nodes.add(this);
Matrix4 transformMatrix = new Matrix4();
transformMatrix.idt();
for (SKNode node : nodes) {
transformMatrix.translate(node.position.x + node.origin.x, node.position.y + node.origin.y, 0);
transformMatrix.rotate(0, 0, 1, node.zRotation);
transformMatrix.scale(node.xScale, node.yScale, 0);
transformMatrix.translate(-node.origin.x, -node.origin.y, 0);
}
return transformMatrix;
}
执行导致精灵批次"flush"的事情很慢,这意味着它必须发出许多OpenGL命令并传输顶点数据等。调用[=11时会发生刷新=] 但如果您出现以下情况也会发生:
- 使用与上次绘制的不同的纹理实例绘制一些东西
- 更改投影或变换矩阵
- Enable/disable 混合
所以你想要组织起来,这样你就不会在你绘制的每个对象上触发刷新。通常所做的是开始批处理,然后使用包含所有所需参数的 spriteBatch.draw()
方法之一在其特定位置绘制每个精灵。像这样:
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (GameObject obj : myGameObjects)
obj.draw();
batch.end();
//And in your game object / sprite class
public void draw() {
if (texture == null)
return;
spriteBatch.setColor(1f, 1f, 1f, getAlpha());
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
}
请注意,以上内容假设您在每个对象中引用相同的精灵批处理实例。
现在,为了让它表现得更像 SpriteKit(我假设因为我没有使用过它),你的每个对象都需要一个转换。但是你不想调用 setTransformMatrix
否则你会触发同花顺。相反,您可以使用 Affine2 class 而不是 Matrix4。它的功能同样适用于保存 2D 对象的变换数据。然后你可以使用 spriteBatch.draw(textureRegion, width, height, affine2Transform)
来绘制它而不会触发刷新。
为避免使用不同的纹理实例触发刷新,您应该使用 TextureAtlas 和纹理区域。您可以在其 wiki 上的 LibGDX 文档中阅读相关内容。
顺便说一句,使用 SpriteBatch 时,您无需调用 OpenGL 来启用和禁用混合。这是由 SpriteBatch 内部处理的。改为调用 spriteBatch.enableBlending()
。