在不使用点精灵的情况下在屏幕上的不同点渲染多个纹理

Posted

技术标签:

【中文标题】在不使用点精灵的情况下在屏幕上的不同点渲染多个纹理【英文标题】:Rendering multiple textures at different points on screen without using point sprites 【发布时间】:2012-06-30 01:36:11 【问题描述】:

我正在构建一个 ios 绘图应用程序,并且很难在屏幕上的不同点绘制油漆纹理。大多数在线教程都是指在屏幕上渲染特定尺寸的单个纹理。

但是,我正在寻找的是提供一个 2d 顶点数组,用于绘制基于用户在屏幕上触摸的位置计算的绘制纹理。

我使用的点精灵不需要我指定纹理坐标和用于绘制纹理的原始对象。

但是,我想使用纹理坐标来提供原始对象(例如用三角形条绘制的四边形)。

关于如何做到这一点的任何想法?任何指针都会有所帮助。

库纳尔

【问题讨论】:

我不太确定您具体遇到了什么问题。只需使用一个纹理绘制任意数量的图元,绑定不同的纹理,绘制更多图元等......直到完成。还是我错过了什么? 我想不通的是如何在用户触摸时为基元提供坐标。我可能想把它们画成 GL_TRIANGLE_STRIPS,对吧?在这种情况下,我必须为每个三角形提供 3 个顶点? 【参考方案1】:

如果我理解正确,您想在用户触摸屏幕的点绘制许多纹理(相同的图像)。对于我的粒子系统,我使用这个:

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

    
;

怎么用?

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


您可以使用中间设备以 60 fps 的速度绘制 500 多个纹理,并且每个纹理都可以具有独特的比例、旋转和颜色

【讨论】:

【参考方案2】:

我终于让它工作了。我将用户触摸的每个点绘制为 TRIANGLE_STRIP 基元,其中两个一起形成一个正方形。

    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 是用户触摸的地方。填充决定了图元的大小。

我也旋转纹理,但在旋转之前将其转换到中心,因为旋转发生在原点处的枢轴。

希望这会有所帮助!

更新

通过运行以下旋转命令集,我能够将 openGL 调用次数减少 1:

请注意,通过运行以下旋转命令集(删除推送/弹出矩阵),我能够将 OpenGL 调用次数减少 1

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

【讨论】:

以上是关于在不使用点精灵的情况下在屏幕上的不同点渲染多个纹理的主要内容,如果未能解决你的问题,请参考以下文章

cocos2dx-精灵如何被渲染and纹理如何被管理产生与销毁

如何在不点击链接的情况下在 javascript 中打开新页面

渲染到屏幕和 FBO 给出不同的结果

如何在不复制的情况下在多个进程中使用大型数据集?

在 2D、z 顺序渲染系统中组合点(粒子)和三角形(精灵)

如何以与 OpenGL 中的点精灵相同的方式渲染屏幕对齐的矩形