在openGL ES 2.0 Quad Batch

时间:2015-07-03 15:30:15

标签: opengl-es-2.0 sprite opacity particles quad

概述

在我的应用程序(这是一个游戏)中,我使用项目的批处理来减少绘制调用的次数。因此,我将创建一个名为平台的Java对象,该对象用于所有游戏中的平台。所有的敌人都被收集在一起,就像所有收藏物品一样....

这非常有效。目前,我可以相互独立地批量和定位各个项目,但是,我已经到了我真正需要改变个人项目的不透明度的地步。目前,我只能更改整批产品的不透明度。

配料

我正在上传批次中要显示的所有项目的顶点(如果我不希望它们被绘制,我可以关闭单个项目),然后一旦完成,我只需绘制它们在一个电话中。

以下是我正在做的事情的想法 - 我意识到这可能无法编译,只是为了提出问题的目的。

public void draw(){

    //Upload vertices
    for (count = 0;count<numOfSpritesInBatch;count+=1){

        vertices[x] = xLeft;        
        vertices[(x+1)] = yPTop;    
        vertices[(x+2)] = 0;    
        vertices[(x+3)] = textureLeft; 
        vertices[(x+4)] = 0;
        vertices[(x+5)] = xPRight;
        vertices[(x+6)] = yTop;
        vertices[(x+7)] = 0;
        vertices[(x+8)] = textureRight;
        vertices[x+9] = 0; 
        vertices[x+10] = xLeft; 
        vertices[x+11] = yBottom;
        vertices[x+12] = 0; 
        vertices[x+13] = textureLeft;
        vertices[x+14] = 1;
        vertices[x+15] = xRight;
        vertices[x+16] = yTop;
        vertices[x+17] = 0;
        vertices[x+18] = textureRight;
        vertices[x+19] = 0; 
        vertices[x+20] = xLeft;
        vertices[x+21] = yBottom;
        vertices[x+22] = 0;
        vertices[x+23] = textureLeft;
        vertices[x+24] = 1; 
        vertices[x+25] = xRight;
        vertices[x+26] = yBottom;
        vertices[x+27] = 0;
        vertices[x+28] = textureRight;
        vertices[x+29] = 1;

        x+=30;
    }

    vertexBuf.rewind();
    vertexBuf.put(vertices).position(0);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID);

    GLES20.glUseProgram(iProgId);

    Matrix.multiplyMM(mvpMatrix2, 0, mvpMatrix, 0,  mRotationMatrix, 0);

    mMVPMatrixHandle = GLES20.glGetUniformLocation(iProgId, "uMVPMatrix");

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix2, 0);

    vertexBuf.position(0);
    GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf);
    GLES20.glEnableVertexAttribArray(iPosition);
    vertexBuf.position(3);
    GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf);
    GLES20.glEnableVertexAttribArray(iTexCoords);

    //Enable Alpha blending and set blending function   
    GLES20.glEnable(GLES20.GL_BLEND); 
    GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

    //Draw it
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0,  6 * numOfSpritesInBatch);

    //Disable Alpha blending
    GLES20.glDisable(GLES20.GL_BLEND);
}

着色

String strVShader =  
     "uniform mat4 uMVPMatrix;" +
     "attribute vec4 a_position;\n"+
     "attribute vec2 a_texCoords;" +
     "varying vec2 v_texCoords;" +
     "void main()\n" +
     "{\n" +
     "gl_Position = uMVPMatrix * a_position;\n"+  
     "v_texCoords = a_texCoords;" +
     "}";

String strFShader =
    "precision mediump float;" +
    "uniform float opValue;"+
    "varying vec2 v_texCoords;" +
    "uniform sampler2D u_baseMap;" +
    "void main()" +
    "{" +
    "gl_FragColor = texture2D(u_baseMap, v_texCoords);" +
    "gl_FragColor *= opValue;"+
    "}";

目前,我的Sprite类中有一个方法允许我更改opacty。例如,像这样:

spriteBatch.setOpacity(0.5f); //Half opacity

这有效,但改变了整个批次 - 而不是我所追求的。

应用

我需要这个,因为我想在玩家摧毁敌人时绘制小指标 - 显示从该动作获得的分数。 (许多游戏中发生的事情类型) - 我希望这些小的“得分指标”一旦出现就会淡出。当然,所有指标都是一批创建的,因此可以通过一次平局调用绘制所有指标。

唯一的其他选择是:

  • 以不同的不透明度创建10个纹理,并在它们之间切换以创建淡化效果。不是太浪费的选择。
  • 分别创建这些对象,并使用自己的绘制调用绘制每个对象。可以工作,但是屏幕上最多有10个这样的对象,我可能会使用10个绘图调用来绘制这些项目 - 而整个游戏目前只使用大约20个绘制调用来绘制数百个项目。

我需要在粒子系统等中看看它的未来用途......所以我真的想弄清楚如何做到这一点(能够分别调整每个项目的不透明度)。如果我需要在着色器中执行此操作,如果您能够展示其工作原理,我将不胜感激。或者,是否可以在着色器外执行此操作?

当然,这可以通过某种方式完成吗?欢迎所有建议......

1 个答案:

答案 0 :(得分:2)

实现此目的的最直接方法是使用顶点属性作为不透明度值,而不是均匀值。这将允许您设置每个顶点的不透明度,而不会增加绘制调用的数量。

要实现此功能,您可以按照已用于纹理坐标的模式。它们作为属性传递到顶点着色器中,然后作为变量变量传递给片段着色器。

所以在顶点着色器中,你添加:

...
attribute float a_opValue;
varying float v_opValue;
...
    v_opValue = a_opValue;
...

在片段着色器中,删除opValue的统一声明,并将其替换为:

varying float v_opValue;
...
    gl_FragColor *= v_opValue;
...

在Java代码中,您使用不透明度的附加值扩展顶点数据,每个顶点使用6个值(3个位置,2个纹理坐标,1个不透明度),并相应地更新状态设置:

vertexBuf.position(0);
GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 6 * 4, vertexBuf);
GLES20.glEnableVertexAttribArray(iPosition);
vertexBuf.position(3);
GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 6 * 4, vertexBuf);
GLES20.glEnableVertexAttribArray(iTexCoords);
vertexBuf.position(5);
GLES20.glVertexAttribPointer(iOpValue, 1, GLES20.GL_FLOAT, false, 6 * 4, vertexBuf);
GLES20.glEnableVertexAttribArray(iOpValue);