Повишаване на производителността на чертане с шестоъгълна мрежа

Работя върху първата си openGL игра, вдъхновена от играта "Greed Corp" в playstation network. Това е походова стратегическа игра, базирана на шестнадесетична мрежа. Всяка шестоъгълна плочка има собствена височина и текстура.

В момента рисувам шестоъгълник въз основа на някои примери и уроци, които прочетох. Ето моя хексилен клас:

public class HexTile
{
    private float height;

    private int[] textures = new int[1];

    private float vertices[] = {     0.0f,   0.0f, 0.0f,    //center
                                     0.0f,   1.0f, 0.0f,    // top
                                    -1.0f,   0.5f, 0.0f,    // left top
                                    -1.0f,  -0.5f, 0.0f,    // left bottom
                                     0.0f,  -1.0f, 0.0f,    // bottom
                                     1.0f,  -0.5f, 0.0f,    // right bottom
                                     1.0f,  0.5f, 0.0f,     // right top
    };

    private short[] indices = {      0, 1, 2, 3, 4, 5, 6, 1};

    //private float texture[] = { };

    private FloatBuffer vertexBuffer;
    private ShortBuffer indexBuffer;
    //private FloatBuffer textureBuffer;    

    public HexTile()
    {
        ByteBuffer 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);

        /*ByteBuffer tbb = ByteBuffer.allocateDirect(texture.length * 4);
        tbb.order(ByteOrder.nativeOrder());
        textureBuffer = tbb.asFloatBuffer();
        textureBuffer.put(texture);
        textureBuffer.position(0);*/
    }

    public void setHeight(float h)
    {
        height = h;
    }
    public float getHeight()
    {
        return height;
    }

    public void draw(GL10 gl)
    {
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        //gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

        gl.glDrawElements(GL10.GL_TRIANGLE_FAN, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
    }

    public void loadGLTexture(GL10 gl, Context context)
    {
        textures[0] = -1;
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.hex);

        while(textures[0] <= 0)
            gl.glGenTextures(1, textures, 0); 

        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

        bitmap.recycle();
    }
}

Всеки кадър преминавам през всички видими плочки, за да ги нарисувам, това ще бъде 11 * 9 плочки МАКС. Това обаче намалява моята честота на кадрите до 38 и това е без дори да рисувам текстури върху тях, само плоските шестоъгълници.

Сега се опитвам да разбера как да увелича производителността. Реших, че рисуването на цялата мрежа наведнъж може да бъде по-бързо, но нямам идея как да го направя, тъй като всяка плочка може да има различна височина и най-вероятно ще има различна текстура от съседна плочка.

Наистина ще се радвам на малко помощ по този въпрос, защото бих искал да започна с действителната игра ^.^


person Quint Stoffers    schedule 06.06.2011    source източник


Отговори (2)


Ако приемем, че вашата шестнадесетична мрежа е статична, можете просто да завъртите всичките си шестоъгълници веднъж, да генерирате тяхната геометрия и да добавите всичко към един (или повече, ако имате повече от 2^16 върха) голям VBO, който можете да нарисувате наведнъж.

Що се отнася до текстурите, може да можете да използвате атлас на текстури.

person genpfault    schedule 06.06.2011
comment
Хм, страхувам се, че мрежата не е статична и не мисля, че бих могъл да направя правилно това, което предложихте с това, което знам за openGL в момента. Ще трябва да се забърквам с openGL още малко, предполагам. Ще маркирам тази страница за бъдещи справки, благодаря. - person Quint Stoffers; 06.06.2011
comment
@Quipeace: Колко нестатичен е? Всичките ви шестнадесетици движат ли всеки кадър или само малка част? Ако това е само подмножество, можете да варирате актуализации на VBO, точно като текстури. - person genpfault; 07.06.2011

В момента също изучавам OpenGL, създадох едно Android OpenGL приложение, наречено „Cloud Stream“, където открих подобни проблеми с производителността.

Като общ отговор на проблемите с производителността, има няколко неща, които могат да помогнат. Vertex тръбопроводът за графики на хардуерно ниво очевидно е по-ефективен, когато се предават по-големи количества върхове наведнъж. Извикването на glVertexPointer за всяка шестнадесетична плочка не е толкова ефективно, колкото еднократното извикване с върховете на всички плочки.

Това прави нещата по-трудни за кодиране, тъй като по същество рисувате всичките си плочки наведнъж, но изглежда ускорява малко нещата. В моето приложение всички облаци се изчертават в едно извикване.

Други пътища, които да опитате, са да запазите позициите на Vertice във VBO, което намерих за доста трудно, поне беше, когато се опитвах да се погрижа за потребители на 2.1. Тези дни нещата може да са по-лесни, не съм сигурен. С това идеята е да запазите масива Vertice за вашата плочка във видео паметта и да получите обратно указател, както правите с вашите текстури. Както можете да си представите, неизпращането на вашия Vertice Array Buffer до всеки кадър ускорява малко нещата за всяко теглене на плочка. Дори нещата да не са статични, това е добър подход, тъй като се съмнявам, че нещата се променят за всеки кадър.

Друго предложение, на което попаднах онлайн, беше да използвате Short вместо Float за вашите върхове. И след това да промените мащаба на вашето готово изобразяване, за да получите желания размер. Това ще намали размера на вашите върхове и ще ускори малко нещата... не е голяма сума, но все пак си струва да опитате, бих казал.

Едно последно нещо, което бих искал да добавя, ако в крайна сметка използвате прозрачност... имайте предвид, че трябва да рисувате отзад напред, за да работи, което също оказва влияние върху производителността. Ако рисувате отпред назад, машината за изобразяване автоматично знае да не рисува, когато координатите не се виждат... рисуването отзад напред означава, че всичко е начертано. Имайте това предвид и винаги се опитвайте да рисувате отпред назад, когато е възможно.

Успех с играта ти, ще се радвам да знам как се справяш... Тепърва започвам играта си и съм много развълнуван да започна. Ако все още не сте попадали на това... мисля, че си струва да го прочетете. http://www.codeproject.com/KB/graphics/hexagonal_part1.aspx

person CatalystNZ    schedule 29.12.2011