我将许多粒子的所有顶点数据合并到一个数组中。我如何以保留其独特翻译的方式批量绘制所有这些粒子?
我很困惑如何做到这一点。我已经在这个问题上创建了两个帖子,但我仍然感到困惑。我目前正在使用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();
有效答案是带有代码示例的答案,该答案清楚地说明了此问题的解决方案。
答案 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新的顶点数据。