更改 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' 一旦出现就淡出。当然,所有指标都将创建为一批,因此它们都可以通过一次绘制调用绘制。
唯一的其他选择是:
- 创建 10 个不同透明度的纹理,然后在它们之间切换以创建淡入淡出效果。实在是太浪费了。
- 分别创建这些 object 中的每一个,并使用各自的绘制调用进行绘制。会工作,但最多有 10 个 objects on-screen,我可能只为这些项目使用 10 个绘制调用来绘制 - 而整个游戏目前只使用大约 20 个绘制调用绘制数百个项目。
我也需要看看它在粒子系统等中的未来用途....所以我真的很想弄清楚如何做到这一点(能够分别调整每个项目的不透明度)。如果我需要在着色器中执行此操作,如果你能展示它是如何工作的,我将不胜感激。或者,是否可以在着色器之外执行此操作?
确定这可以通过某种方式完成吗?欢迎所有建议....
实现此目的的最直接方法是为不透明度值使用顶点属性,而不是统一。这将允许您设置每个顶点的不透明度,而无需增加绘制调用的数量。
要实现这一点,您可以遵循已经用于纹理坐标的模式。它们作为属性传递到顶点着色器,然后作为可变变量传递给片段着色器。
所以在顶点着色器中,你添加:
...
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);
概览
在我的应用程序(这是一个游戏)中,我利用项目的批处理来减少绘制调用的次数。因此,我将创建一个名为 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' 一旦出现就淡出。当然,所有指标都将创建为一批,因此它们都可以通过一次绘制调用绘制。
唯一的其他选择是:
- 创建 10 个不同透明度的纹理,然后在它们之间切换以创建淡入淡出效果。实在是太浪费了。
- 分别创建这些 object 中的每一个,并使用各自的绘制调用进行绘制。会工作,但最多有 10 个 objects on-screen,我可能只为这些项目使用 10 个绘制调用来绘制 - 而整个游戏目前只使用大约 20 个绘制调用绘制数百个项目。
我也需要看看它在粒子系统等中的未来用途....所以我真的很想弄清楚如何做到这一点(能够分别调整每个项目的不透明度)。如果我需要在着色器中执行此操作,如果你能展示它是如何工作的,我将不胜感激。或者,是否可以在着色器之外执行此操作?
确定这可以通过某种方式完成吗?欢迎所有建议....
实现此目的的最直接方法是为不透明度值使用顶点属性,而不是统一。这将允许您设置每个顶点的不透明度,而无需增加绘制调用的数量。
要实现这一点,您可以遵循已经用于纹理坐标的模式。它们作为属性传递到顶点着色器,然后作为可变变量传递给片段着色器。
所以在顶点着色器中,你添加:
...
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);