我最近开始研究适用于 Android 的 OpenGL ES,并且正在开发一个绘图应用程序。我已经实现了一些基础知识,例如点精灵、路径平滑和用于双缓冲的 FBO。目前我正在使用 glBlendFunc,更具体地说,当我将两个具有相同颜色/alpha 值的纹理彼此靠近时,alpha 会被添加,因此它在精灵的交点处看起来更暗。这是一个问题,因为如果很多点靠得很近,则不会保留笔画不透明度,因为颜色往往更不透明,而不是保持相同的不透明度。有没有办法使纹理在交叉点上具有相同的颜色,即相交像素具有相同的 alpha 值,但保留其余像素的 alpha 值?
以下是我如何完成应用程序的相关部分:
为了绘制点精灵列表,我使用如下混合:
GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
该应用程序使用带有纹理的 FBO,它首先渲染每个笔触,然后将此纹理渲染到主屏幕。混合功能有:
GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
OpenGL ES 2.0 不支持 alpha 遮罩;
- 应用程序的任何地方都没有使用 DEPTH_TEST 函数;
- 点精灵的纹理是具有透明背景的 PNG;
- 该应用程序支持纹理遮罩,这意味着一种纹理用于形状,一种纹理用于内容;
我的片段着色器如下所示:
precision mediump float; uniform sampler2D uShapeTexture; uniform sampler2D uFillTexture; uniform float vFillScale; varying vec4 vColor; varying float vShapeRotation; varying float vFillRotation; varying vec4 vFillPosition; vec2 calculateRotation(float rotationValue) { float mid = 0.5; return vec2(cos(rotationValue) * (gl_PointCoord.x - mid) + sin(rotationValue) * (gl_PointCoord.y - mid) + mid, cos(rotationValue) * (gl_PointCoord.y - mid) - sin(rotationValue) * (gl_PointCoord.x - mid) + mid); } void main() { // Calculations. vec2 rotatedShape = calculateRotation(vShapeRotation); vec2 rotatedFill = calculateRotation(vFillRotation); vec2 scaleVector = vec2(vFillScale, vFillScale); vec2 positionVector = vec2(vFillPosition[0], vFillPosition[1]); // Obtain colors. vec4 colorShape = texture2D(uShapeTexture, rotatedShape); vec4 colorFill = texture2D(uFillTexture, (rotatedFill * scaleVector) + positionVector); gl_FragColor = colorShape * colorFill * vColor; }
我的顶点着色器是这样的:
attribute vec4 aPosition; attribute vec4 aColor; attribute vec4 aJitter; attribute float aShapeRotation; attribute float aFillRotation; attribute vec4 aFillPosition; attribute float aPointSize; varying vec4 vColor; varying float vShapeRotation; varying float vFillRotation; varying vec4 vFillPosition; uniform mat4 uMVPMatrix; void main() { // Sey position and size. gl_Position = uMVPMatrix * (aPosition + aJitter); gl_PointSize = aPointSize; // Pass values to fragment shader. vColor = aColor; vShapeRotation = aShapeRotation; vFillRotation = aFillRotation; vFillPosition = aFillPosition; }
我尝试过使用 glBlendFunc 参数,但找不到合适的组合来绘制我想要的东西。我附上了一些图片,展示了我想要实现的目标以及我目前拥有的目标。有什么建议么?
解决方案
感谢@ Rabbid76,终于设法用几行代码让它正常工作。首先,在绘制到 FBO 之前,我必须配置我的深度测试功能:
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthFunc(GLES20.GL_LESS);
// Drawing code for FBO.
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
然后在我的片段着色器中,我必须确保掩码中所有 alpha < 1 的像素都被丢弃,如下所示:
...
vec4 colorMask = texture2D(uMaskTexture, gl_PointCoord);
if (colorMask.a < 1.0)
discard;
else
gl_FragColor = calculatedColor;
结果是(闪烁是由于Android模拟器和gif捕获工具造成的):