Лучшая практика движка частиц opengl?

Я разрабатываю простую игру, и в настоящее время я переключаюсь с холста на openGL. Так что мой опыт работы с openGL очень ограничен. В данный момент я пытаюсь создать простой движок частиц, и он отлично работает, НО с моей текущей реализацией мне приходится запускать эту строку при каждом вызове draw() [ vertexBuffer.put(vertices); ] и это очень медленно. Есть ли способ обойти это?

код выглядит так:

public class ParticlesTest {

    private float[] vertices;
    private short[] indices;


    private FloatBuffer vertexBuffer;


    private ShortBuffer indexBuffer;
    private ByteBuffer vbb;

    private int MAX_PARTICLES = 100;

    private ArrayList<Particle> particles;
    public ParticlesTest() {

        particles = new ArrayList<Particle>();

        vertices = new float[MAX_PARTICLES*6*3];
        indices = new short[MAX_PARTICLES*2];


        short cnt = 0;
        for(int i = 0; i < 60; i++){
            createParticle();

            indices[cnt] =  cnt;
            cnt++;
            indices[cnt] =  cnt;
            cnt++;

        }

        vbb = ByteBuffer.allocateDirect(vertices.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        vertexBuffer = vbb.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
        ibb.order(ByteOrder.nativeOrder());
        indexBuffer = ibb.asShortBuffer();
        indexBuffer.put(indices);
        indexBuffer.position(0);



    }

    private void createParticle() {
        Particle particle = new Particle();
        particle.setSpeedX((float)(Math.random() * 20 - 10));
        particle.setSpeedY((float)(Math.random() * 20 - 10));
        particle.setX(100);
        particle.setY(100);

        particles.add(particle);


    }
    private void update(){

        int len = particles.size();

        for(int i = 0; i < len; i++){
            Particle particle = particles.get(i);

            float oldX = particle.getX();
            float oldY = particle.getY();
            float speedX = particle.getSpeedX();
            float speedY = particle.getSpeedY();

            oldX += speedX;
            oldY += speedY;

            particle.setX(oldX);
            particle.setY(oldY);

            if(oldX < 0 || oldX > 400 || oldY < 0 || oldY > 600){
                particles.remove(i);
                len--;
            }
        }

        if(len < MAX_PARTICLES){
            createParticle();
        }
    }


    private void translate(){


        int vcount = 0;
        short icount = 0;

        int clen = vertices.length;

        for(int c = 0; c < clen; c++){
            vertices[c] = 0f;
        }


        int len = particles.size();

        for(int i = 0; i < len; i++){
            Particle particle = particles.get(i);

            float oldX = particle.getX();
            float oldY = particle.getY();

            float speedX = particle.getSpeedX();
            float speedY = particle.getSpeedY();

            vertices[vcount] =oldX;
            vcount++;
            vertices[vcount] = oldY;
            vcount++;
            vertices[vcount] = 0f;
            vcount++;

            vertices[vcount] =oldX + speedX;
            vcount++;
            vertices[vcount] = oldY + speedY;
            vcount++;
            vertices[vcount] = 0f;
            vcount++;

            indices[icount] = icount;
            icount++;
            indices[icount] = icount;
            icount++;

        }
    }


    public void draw(GL10 gl,int w,int h) {

        update();
        translate();

        vertexBuffer.put(vertices);

        vertexBuffer.position(0);

        //GLFPS.VERTS = vertices.length;


        // rendering.
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);      
//      gl.glDrawElements(GL10.GL_LINE_STRIP, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
        gl.glDrawElements(GL10.GL_LINES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);



        // Disable the vertices buffer.
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    }
}

person user465627    schedule 19.04.2011    source источник


Ответы (3)


в качестве рекомендации создание ArrayList из такого большого количества объектов может привести к большим накладным расходам памяти. Кроме того, рассматривали ли вы возможность использования GL ES 2.0 вместо 1? Таким образом, вы можете создать программу шейдера частиц, используя GLSL, это позволит вам освободить память и выполнять вычисления на GPU, а не на CPU. Это должно значительно увеличить производительность.

person Tom    schedule 08.08.2011

Есть ли способ обойти это?

Выделите все свои объекты заранее и продолжайте повторно использовать их во время работы игры.

См. мой другой пост здесь.

person Wroclai    schedule 19.04.2011
comment
это действительно хороший подход для запуска gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_SHORT, mIndexBuffer); на каждой частице? Мне просто интересно, потому что мой тест показывает, что слишком много таких вызовов довольно дороги (скажем, 1000 частиц + все остальное, что нужно нарисовать...) или? - person user465627; 19.04.2011

Хорошо, я нашел действительно хороший способ сделать это сейчас (я думаю). Вместо использования вершинного буфера с плавающей запятой у меня есть вершинный буфер Shorts. Теперь я запускаю 15k частиц на Galaxy S со скоростью 23 кадра в секунду.

person user465627    schedule 22.04.2011