更改 openGL ES 2.0 Quad Batch 中单个项目的不透明度

Changing opacity of individual items in openGL ES 2.0 Quad Batch

概览

在我的应用程序(这是一个游戏)中,我利用项目的批处理来减少绘制调用的次数。因此,我将创建一个名为 platforms 的 Java object,它适用于游戏中的 all 平台。所有的敌人和所有收藏品等都放在一起......

这真的很好用。目前,我可以独立地调整批次中单个项目的大小和位置,但是,我已经到了真正需要更改 individual 项目的不透明度的地步.目前,我只能更改整个批次的不透明度。

批处理

我正在上传要显示的批次中所有项目的顶点(如果我不想绘制它们,我可以关闭个别项目),然后一旦它们全部完成,我只需一次调用绘制它们。

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

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 class 中有一个方法允许我更改透明度。例如,像这样:

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

这有效,但改变了整批 - 不是我想要的。

申请

我需要这个,因为我想在玩家消灭敌人时绘制小指示器 - 显示从该动作中获得的分数。 (很多游戏中都会发生这种事情)- 我希望这些 'score indicators' 一旦出现就淡出。当然,所有指标都将创建为一批,因此它们都可以通过一次绘制调用绘制。

唯一的其他选择是:

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

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

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

要实现这一点,您可以遵循已经用于纹理坐标的模式。它们作为属性传递到顶点着色器,然后作为可变变量传递给片段着色器。

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

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