2

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

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

这两个帖子是:

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

我目前在我的实现中使用顶点数组对象。我知道我应该使用 VBO 以获得最佳性能。我将实现 VBO,但首先我想实现批处理。成功完成批处理后,我会将 VAO 更改为 VBO。因此,这个问题的重点是如何使用 VAO 来实现这一点。

这是我在批处理之前的代码,我将在模型视图矩阵中推送一个新矩阵,根据当前正在渲染的 Actor 进行平移、旋转、缩放和 alpha,并绘制当前正在渲染的 Actor 的顶点和纹理坐标:

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

现在,鉴于我已将所有粒子 Actor 的顶点和纹理坐标组合到批处理数组中,我想在模型视图矩阵中推送一个新矩阵,并以适当的平移、旋转、比例绘制这些 Actor 的顶点和纹理坐标,阿尔法等。

所以我的猜测是它看起来像:

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

一个有效的答案是一个代码示例,它清楚地说明了这个问题的解决方案。

4

1 回答 1

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。

于 2012-12-30T12:14:48.640 回答