【问题标题】:Performances drops when using particles effects使用粒子效果时性能下降
【发布时间】:2022-01-03 18:04:48
【问题描述】:

一段时间以来,我一直在开发一款使用 libgdx 和 box2d 制作烟花表演的游戏。

游戏由一个编辑器组成,允许放置和调整每个烟花表演。 另一部分是奇观部分,一排排的烟花发射。

每个烟花都由一个以一定速度喷射的物体组成,该物体附有一个粒子效果,允许模拟轨迹(最多 40 个活动粒子)。 在其高峰期,踪迹消失,炸弹的主体被摧毁。 此时另一个效果开始了,以模拟炸弹的爆炸(50 到 100 个活性粒子)。 此外,几个物体(8 到 16 之间)向不同方向喷射,以模拟附有粒子效果的恒星,以模拟它们的轨迹(10 到 50 之间)。 在旅程的最后,每颗恒星都有一个粒子效果(8 到 20 之间),以模拟它们的爆炸。

问题在于,当同时激活 10 个以上的烟花时,Android 上 fps 的数量会大幅下降,下面是截图,以了解渲染:

image1

image2

image3

我显然使用了一个池来避免重新创建粒子效果。此外,我确保在开始游戏时我已经有一些效果在里面。 这个池是位于我的 ParticleManager 类中的一个内部类,它允许启动、更新和渲染效果。

我所有的纹理都包含在一个图集中(包括粒子)。所有粒子都有相同的精灵。

对于我的粒子的渲染,当创建新效果时,我确保每个效果在使用以下指令渲染后避免刷新批次: setEmittersCleanUpBlendFunction (false);

这是我的 ParticleManager 类的渲染方法:

public void render (SpriteBatch sb) {
    if (effects.size == 0) return;

    // Manually change blendFunction.
    sb.setBlendFunction (GL20.GL_SRC_ALPHA, GL20.GL_ONE);

    // Render all effects.
    for (int i = 0; i <effects.size; i ++)
        effects.get(i).draw(sb);

    // Manually reset blendFunction to his initial state.
    sb.setBlendFunction (GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
}

我在我的主要关卡类中使用两台摄像机,一台用于渲染我的场景,一台用于渲染 HUD,所以我调用函数:sb.setProjectionMatrix(); 两次,这导致两次刷新批处理,当效果处于活动状态时会刷新三次是由于位于我的 ParticlesManager 类的渲染方法中的sb.setBlendFunction(); 方法。 所以我来了3个drawCalls。

这是我的 Level 类的渲染方法的代码,没有多余的功能:

public void render (float dt) {
    update(dt);

    Gdx.gl.glClearColor (0, 0, 0, 1);
    Gdx.gl.glClear (GL20.GL_COLOR_BUFFER_BIT);

    // First draw call.
    sb.setProjectionMatrix (camera.combined);
    sb.begin ();
    backgroundManager.render (sb);
    worldManager.render (sb);

    // Second draw call if an effect is active.
    if (run)
        particlesManager.render (sb);

    // Second draw call if no effects, or third otherwise.
    sb.setProjectionMatrix (hud.getCamera (). combined);
    hud.render (sb);
    sb.end ();
}

因此,如果可以进行一些优化,我看不出我最终可以进行哪些优化。 提前感谢您的帮助。

【问题讨论】:

标签: java android libgdx


【解决方案1】:

我想尝试两件事。

  1. 您必须明确地将已完成的效果返回到池中,然后才能重复使用它们,因此您会因为池已用尽并有效地生成新的而不是重复使用而减慢速度。
  2. 您还需要从 effects 中删除,否则您将迭代完成的效果。
    //This is the libGDX array for entry removal speed
    private final Array<PooledEffect> activeEffects = new Array<PooledEffect>(512);

在渲染中

       for (int i = activeEffects.size - 1; i >= 0; i--) {

            final PooledEffect effect = activeEffects.get(i);
            effect.update(Gdx.graphics.getDeltaTime());
            effect.draw(spriteBatch);

            if (effect.isComplete()) {
                effect.reset();
                effect.free();
                activeEffects.removeIndex(i);

            }
        }

【讨论】:

  • 感谢您的回答,但是问题并非来自池,实际上,当效果完成后,我立即将其放回内部,然后将其从我的活动效果数组中删除,如下所示:public void update (float dt) { for (int i = 0; i
  • 感谢您的回复。我唯一可以建议的另一件事是更改您的纹理打包器设置,即 premultiplyAlpha 是(我认为这在 android 上可能更快,但无法再找到参考),强制 POT(2 的幂),将 min 和 mag 过滤器设置为最接近的,并且在设置后台缓冲区配置时也为 MSAA 尝试 0。 config.setBackBufferConfig(8, 8, 8, 8, 16, 0, GC.MSAA);并缩小纹理图集
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-05
  • 2011-11-07
相关资源
最近更新 更多