问题
I'm building an ios drawing app and am having a hard time how to draw paint textures on the screen at different points. Most tutorials online refer to rendering a single texture of a certain size on screen.
However, what I'm looking for is to provide an array of 2d vertices at which to draw the paint texture that is computed based on where the user touches on the screen.
I was using point sprites which didn't require me to specify the texture coordinates and hte primitive object used to draw the texture.
However, I'd like to use texture-coordinates to provide a primitive object (like a quad drawn with triangle strips).
Any ideas on how to do this? Any pointers would be helpful.
Kunal
回答1:
If i understand correct you want to draw many textures (same image) at points that the user touched the screen . For my particle system i use this:
float squarevData[12]={
-1,1,
1,1,
-1,-1,
1,1,
1,-1,
-1,-1,
};
float squarevData2[12]={
-1,1,
1,1,
-1,-1,
1,1,
1,-1,
-1,-1,
};
class BatchRenderer
{
public:
float* partVdata;
float* partCdata;
float* partTdata;
int counter1,counter2,counter3;
int count;
bool isz;
BatchRenderer(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);
}
void Draw(float x,float y,float z,float scalex,float scaley,float angle,float r,float g,float b,float a)
{
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);
squarevData2[c2] = (cos1*x) - ( sin1*y);
squarevData2[c2+1] = (sin1*x) + ( cos1*y);
}
partVdata[counter1++]=x+squarevData2[0];
partVdata[counter1++]=y+squarevData2[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+squarevData2[2];
partVdata[counter1++]=y+squarevData2[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+squarevData2[4];
partVdata[counter1++]=y+squarevData2[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+squarevData2[6];
partVdata[counter1++]=y+squarevData2[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+squarevData2[8];
partVdata[counter1++]=y+squarevData2[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+squarevData2[10];
partVdata[counter1++]=y+squarevData2[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)
{
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
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);
}
};
How to use it?
BatchRenderer* br=new BatchRenderer(500,false)//the max number of textures that can be drawn , and if you want z axis
void Render()
{
br->RenderStart();
for(int c=0;c<POINTS;c++)
{
br->Draw(p[c].x,p[c].y,0,p[c].scalex,p[c].scaly,p[c].angle,p[c].r,p[c].g,p[c].b,p[c].a);
}
br->RenderStop(yourtextureid);
}
You can draw more than 500 textures in 60 fps with a mid device and you can have unique scale,rotation and color for each
回答2:
I finally got this to work. I drew each point where the user touches as a TRIANGLE_STRIP primitive, two of which together result in a square.
GLfloat *tBuffer = malloc(4 * 2 * sizeof(GLfloat));
tBuffer[0] = 0.0;
tBuffer[1] = 1.0;
tBuffer[2] = 1.0;
tBuffer[3] = 1.0;
tBuffer[4] = 0.0;
tBuffer[5] = 0.0;
tBuffer[6] = 1.0;
tBuffer[7] = 0.0;
glTexCoordPointer(2, GL_FLOAT, 0, tBuffer);
CGFloat padding = 16;
vBuffer[0] = xCenter - padding;
vBuffer[1] = yCenter - padding;
vBuffer[2] = xCenter + padding;
vBuffer[3] = yCenter - padding;
vBuffer[4] = xCenter - padding;
vBuffer[5] = yCenter + padding;
vBuffer[6] = xCenter + padding;
vBuffer[7] = yCenter + padding;
CGFloat degrees = atan2(end.y - start.y, end.x - start.x) * 180 / M_PI;
// rotate the texture in the direction of the stroke.
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glTranslatef(0.5, 0.5, 0);
glRotatef(degrees, 0, 0, 1);
glTranslatef(-0.5, -0.5, 0);
glVertexPointer(2, GL_FLOAT, 0, vBuffer);
glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
xCenter, yCenter is where the user touches. Padding determines the size of the primitive.
I also rotate the texture, but translate it to the center before rotating since rotation happens with the pivot at the origin otherwise.
Hope this helps!
UPDATE:
I was able to reduce the number of openGL calls by 1 by running the following set of commands for rotation instead:
Note that I was able to reduce the number of OpenGL calls by 1, by running the following set of commands for the rotation (removing push/pop matrix)
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5, 0.5, 0);
[GLManager rotateBrush:degrees];
glTranslatef(-0.5, -0.5, 0);
[GLManager drawVertexBuffer:vBuffer withVertexNumber:4];
glMatrixMode(GL_MODELVIEW);`
来源:https://stackoverflow.com/questions/11270780/rendering-multiple-textures-at-different-points-on-screen-without-using-point-sp