OpenGL ES 2.0 - 如何批量绘制具有独特平移,旋转,比例和alpha的粒子?

时间:2012-12-29 17:48:12

标签: opengl-es opengl-es-2.0 vertex-array

我将许多粒子的所有顶点数据合并到一个数组中。我如何以保留其独特翻译的方式批量绘制所有这些粒子?

我很困惑如何做到这一点。我已经在这个问题上创建了两个帖子,但我仍然感到困惑。我目前正在使用OpenGL ES 1.1但是我愿意升级到2.0,如果这意味着我可以实际完成具有独特翻译,旋转等的粒子的批量渲染。

这两个帖子是:

两者都解释了一个高级方法,但我需要知道如何渲染这批粒子,其中每个粒子的平移,旋转和比例将每帧都改变。如果您的答案是计算CPU上的翻译,那么请举例说明。

我目前正在实施中使用Vertex Array Objects。我认为我应该使用VBO来获得最佳性能。我将实现VBO,但首先我要实现批处理。一旦我完成成功的批处理,我将把VAO改为VBO。因此,这个问题的焦点是如何用VAO实现这一目标。

这是我在批处理之前的代码,我将在模型视图矩阵中推送一个新矩阵,根据当前正在渲染的Actor转换,旋转,缩放和alpha,并绘制当前正在渲染的Actor的顶点和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();

现在,鉴于我已将所有粒子Actors的顶点和textureCoords组合成批处理数组,我想在模型视图矩阵中推送一个新矩阵,并在适当的平移处绘制这些Actors的顶点和textureCoords,旋转,鳞片,alphas等。

所以我猜它看起来像是:

    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();

有效答案是带有代码示例的答案,该答案清楚地说明了此问题的解决方案。

1 个答案:

答案 0 :(得分:0)

由于所有粒子都具有相同的纹理,因此可以完成这项工作:

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新的顶点数据。