OpenGL ES 2.0 — Как пакетно рисовать частицы с уникальными перемещениями, поворотами, масштабами и альфа-каналами?

Я объединил все свои данные вершин для многих частиц в один массив. Как мне нарисовать все эти частицы таким образом, чтобы сохранить их уникальные переводы?

Я так запутался, как это сделать. Я уже создал два поста по этому вопросу, но все еще не понимаю. В настоящее время я использую OpenGL ES 1.1, но готов перейти на 2.0, если это означает, что я действительно могу выполнить пакетный рендеринг частиц с уникальными переводами, поворотами и т. д.

Два поста:

Оба объясняют высокоуровневый подход, но мне нужно знать, как визуализировать эту группу частиц, где перенос, вращение и масштаб каждой частицы будут меняться в каждом кадре. Если ваш ответ заключается в вычислении переводов на ЦП, то, пожалуйста, покажите пример этого.

В настоящее время я использую объекты массива вершин в своей реализации. Я понимаю, что я должен использовать VBO для лучшей производительности. Я буду реализовывать VBO, но сначала я хочу реализовать пакетную обработку. Как только я закончу успешное пакетирование, я заменю VAO на VBO. Следовательно, основное внимание в этом вопросе уделяется тому, как добиться этого с помощью VAO.

Вот мой код перед пакетной обработкой, где я помещал новую матрицу в матрицу представления модели, переводил, вращал, масштабировал и альфа-канал в соответствии с текущим визуализируемым Актером и рисовал вершины и textureCoords текущего визуализируемого Актера:

    glPushMatrix();

    glTranslatef(translation.x, translation.y, translation.z);

    // rotation
    glRotatef(rotation.x, 1, 0, 0);
    glRotatef(rotation.y, 0, 1, 0);
    glRotatef(rotation.z, 0, 0, 1);

    // scale
    glScalef(scale.x, scale.y, scale.z);

    // color and alpha
    glColor4f(1.0, 1.0, 1.0, alpha);

    glVertexPointer(2, GL_FLOAT, 0, aSprite.vertices);
    glEnableClientState(GL_VERTEX_ARRAY);


    glTexCoordPointer(2, GL_FLOAT, 0, texturedQuad.textureCoords);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glPopMatrix();

Теперь, учитывая, что я объединил вершины и textureCoords всех Актеров частиц в пакетные массивы, я хотел бы поместить новую матрицу в матрицу представления модели и нарисовать вершины и textureCoords этих Актеров в их соответствующих перемещениях, поворотах, масштабах. , альфы и т.д.

Итак, я предполагаю, что это будет выглядеть примерно так:

    static GLFloat verticesBatched[appropriate_length] = ...; // I have a method to populate this array based on the Actors to render

    static GLFloat textureCoordsBatched[appropriate_length] = ...; // I have a method to populate this array based on the Actors to render

    glPushMatrix();

    // perform CPU matrix manipulation to manually translate, rotate, and scale all vertices         

    glVertexPointer(2, GL_FLOAT, 0, verticesBatched);
    glEnableClientState(GL_VERTEX_ARRAY);


    glTexCoordPointer(2, GL_FLOAT, 0, textureCoordsBatched);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glPopMatrix();

Правильным ответом является тот, который содержит пример кода, который ясно иллюстрирует решение этого вопроса.


person BigSauce    schedule 29.12.2012    source источник


Ответы (1)


Поскольку все частицы имеют одинаковую текстуру, это будет работать:

float squarevData[12]={
    -1,1,
    1,1,
    -1,-1,
    1,1,
    1,-1,
    -1,-1,
};
float squarevDataSteady[12]={
    -1,1,
    1,1,
    -1,-1,
    1,1,
    1,-1,
    -1,-1,
};

class BatchRenderer
{
public:
    float* partVdata;
    float* partCdata;
    float* partTdata;
    bool isanydrawed;
    int counter1,counter2,counter3;
    int count;
    bool isz;
    bool textured;
    void Innit(int maxTextures,bool iszi)
    {
        isz=iszi;
        if(isz)partVdata=(float*)malloc(maxTextures*18*4);
        else partVdata=(float*)malloc(maxTextures*12*4);

        partCdata=(float*)malloc(maxTextures*24*4);
        partTdata=(float*)malloc(maxTextures*12*4);

        isanydrawed=false;
    }
    void Draw(float x,float y,float z,float scalex,float scaley,float angle,float r,float g,float b,float a)
    {
        isanydrawed=true;

        angle*=0.017453f;
        for(int c2=0;c2<12;c2+=2)
        {
            float x=squarevData[c2]*scalex;
            float y=squarevData[c2+1]*scaley;
            float cos1=cos(angle);
            float sin1=sin(angle);
            squarevDataSteady[c2] = (cos1*x) - ( sin1*y);
            squarevDataSteady[c2+1] = (sin1*x) + ( cos1*y);
        }

        partVdata[counter1++]=x+squarevDataSteady[0];
        partVdata[counter1++]=y+squarevDataSteady[1];
        if(isz)partVdata[counter1++]=z;
        partCdata[counter2++]=r;
        partCdata[counter2++]=g;
        partCdata[counter2++]=b;
        partCdata[counter2++]=a;
        partTdata[counter3++]=0;
        partTdata[counter3++]=1;


        partVdata[counter1++]=x+squarevDataSteady[2];
        partVdata[counter1++]=y+squarevDataSteady[3];
        if(isz)partVdata[counter1++]=z;
        partCdata[counter2++]=r;
        partCdata[counter2++]=g;
        partCdata[counter2++]=b;
        partCdata[counter2++]=a;
        partTdata[counter3++]=1;
        partTdata[counter3++]=1;

        partVdata[counter1++]=x+squarevDataSteady[4];
        partVdata[counter1++]=y+squarevDataSteady[5];
        if(isz)partVdata[counter1++]=z;
        partCdata[counter2++]=r;
        partCdata[counter2++]=g;
        partCdata[counter2++]=b;
        partCdata[counter2++]=a;
        partTdata[counter3++]=0;
        partTdata[counter3++]=0;

        partVdata[counter1++]=x+squarevDataSteady[6];
        partVdata[counter1++]=y+squarevDataSteady[7];
        if(isz)partVdata[counter1++]=z;
        partCdata[counter2++]=r;
        partCdata[counter2++]=g;
        partCdata[counter2++]=b;
        partCdata[counter2++]=a;
        partTdata[counter3++]=1;
        partTdata[counter3++]=1;

        partVdata[counter1++]=x+squarevDataSteady[8];
        partVdata[counter1++]=y+squarevDataSteady[9];
        if(isz)partVdata[counter1++]=z;
        partCdata[counter2++]=r;
        partCdata[counter2++]=g;
        partCdata[counter2++]=b;
        partCdata[counter2++]=a;
        partTdata[counter3++]=1;
        partTdata[counter3++]=0;

        partVdata[counter1++]=x+squarevDataSteady[10];
        partVdata[counter1++]=y+squarevDataSteady[11];
        if(isz)partVdata[counter1++]=z;
        partCdata[counter2++]=r;
        partCdata[counter2++]=g;
        partCdata[counter2++]=b;
        partCdata[counter2++]=a;
        partTdata[counter3++]=0;
        partTdata[counter3++]=0;

        count++;

    }
    void RenderStart()
    {
        counter1=counter2=count=counter3=0;
    }
    void RenderStop(int textureid)
    {
        if(!isanydrawed)return;

            glEnable(GL_TEXTURE_2D);
            glEnableClientState(GL_COLOR_ARRAY);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glEnableClientState(GL_VERTEX_ARRAY);
            glBindTexture(GL_TEXTURE_2D, textureid);
            glTexCoordPointer(2, GL_FLOAT, 0, partTdata);
        glColorPointer(4, GL_FLOAT, 0,partCdata );
        if(isz)glVertexPointer(3, GL_FLOAT, 0, partVdata);
        else glVertexPointer(2, GL_FLOAT, 0, partVdata);
        glDrawArrays(GL_TRIANGLES, 0, count*6);
        glDisableClientState(GL_COLOR_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY);

        isanydrawed=false;
    }
};

Ваш код:

BatchRenderer* br=new BatchRenderer(MAX_TEXTURES_NUM,true);//true since you are drawing 3d
void onParticlesRender()
{
      br->RenderStart();
      for(int c=0;c<PARTICLES_SIZE;c++)
      {
            br->Draw(p[c].pos.x,p[c].pos.y,p[c].pos.z,p[c].scale.x,p[c].scale.y,p[c].angle,p[c].r,p[c].g,p[c].b,p[c].a);
      }
      br->RenderStop(yourTextureID);
}

Я не могу проверить код прямо сейчас, поэтому, если он работает без проблем, пожалуйста, дайте мне знать.

VBO бесполезен при пакетном рендеринге, потому что вы загружаете в GPU новые данные вершин в каждом кадре.

person SteveL    schedule 30.12.2012