简体   繁体   中英

OpenGLES blending bug, alpha is accumulating

I'm making a live wallpaper for android, I will explain how it works as I believe it's related to the problem, I'm sorry for the long question but I need to explain everything because the problem is hard to describe.

I'm using OpenGLES 2.0, I have a GLSurfaceView and a wallpaper service implementation, I pass it my renderer to call the drawing methods, like most OpenGL live wallpapers.

The way I've implemented my renderer is: in the wallpaper service I have an independent thread that will call the draw method every X seconds, the GLSurfaceView is set to RENDERMODE_WHEN_DIRTY, so this update thread is what decides when drawing occurs.

Furthermore in the service there is a pause and resume method, when the visibility changes. So even if I exit the wallpaper the service will run, conserving the state of everything until it's resumed.

Now for the problem, I've gotten transparency working as you can see here: 第一次渲染

But when I lose focus and regain to the wallpaper, I press the back button on android's wallpaper selector, or change the wallpaper and then come back to it. The alpha value of things will go up.

Here is 2 meshes, the one on the left has an initial alpha value of 0.1, the one on the right 0.5. 初始设置,尚未失去焦点

Now as I leave and come back, the GLSurfaceView onVisibilityChanged method will be called, it works as expected but as you can see the alpha values will increase for some reason, and keep increasing as I leave and go back:

退出并返回1次 1 time 退出并返回2次 2 times

The way I have the mesh drawing set up is in my fragment shader I will set the value of an uniform before drawing the mesh, and that uniform will multiply by the texture color.

Here is the fragment shader:

precision mediump float;

uniform vec4 u_color;       
uniform sampler2D u_texture;
varying vec2 v_textcoord;

void main()
{
    gl_FragColor = u_color * texture2D(u_texture, v_textcoord); 
}  

Of course before drawing the mesh I set the blending and blendfunc:

GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

GLES20.glUniform4f(DayAndNightRenderer.BaseShader.GetUniform("u_color"), color.r, color.g, color.b, 0.5f);      

texture.Bind();

mesh.Draw(GLES20.GL_TRIANGLE_FAN, DayAndNightRenderer.BaseShader);

GLES20.glDisable(GLES20.GL_BLEND);

And the mesh drawing, even though the color uniform is set before drawing:

GLES20.glUniformMatrix4fv(shader.GetUniform("u_transmat"), 1, false, Transform.GetProjectedTransformationMatrix().ToFloatBuffer());     

GLES20.glEnableVertexAttribArray(shader.GetAttribute("a_pos"));
GLES20.glEnableVertexAttribArray(shader.GetAttribute("a_textcoord"));

GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, VBO[0]);

GLES20.glVertexAttribPointer(shader.GetAttribute("a_pos"), 3, GLES20.GL_FLOAT, false, Vertex.SIZE, 0);
GLES20.glVertexAttribPointer(shader.GetAttribute("a_textcoord"), 3, GLES20.GL_FLOAT, false, Vertex.SIZE, Vertex.POS_SIZE);

GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, IBO[0]);    

GLES20.glDrawElements(primitive, size, GLES20.GL_UNSIGNED_INT, 0);      

GLES20.glDisableVertexAttribArray(shader.GetAttribute("a_textcoord"));
GLES20.glDisableVertexAttribArray(shader.GetAttribute("a_pos"));

The things I've tried so far:

  • Changing the blend funcs, doesn't seem to affect the bug that is adding to the alpha value
  • Reloading the shader between focus losses
  • Clearing the framebuffer, I set GLES20.glClearColor(0f, 0f, 0f, 0f); on start and call GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); every frame

None of the above worked, and it's not some variable I use to set the alpha that's getting accumulated, the alpha of things is set to a constant as you can see in the code where I set the color uniform.

I'm clueless to what's causing this, it really only happens by losing focus of the wallpaper and getting back to it, on the first run without going back, it draws everything perfectly.

Here is the onVisibilityChanged method by the way:

@Override
public void onVisibilityChanged(boolean visible) 
{
    super.onVisibilityChanged(visible);

    if (hassetrenderer) 
    {
        if (visible) 
        {                       
            OpenGLES2WallpaperService.updatehandler.Start();
            glsurfaceview.onResume();                               
            Log.i("DN", "State: running");

        }
        else
        {
            OpenGLES2WallpaperService.updatehandler.Stop();
            glsurfaceview.onPause();
            Log.i("DN", "State: not running");
        }
    }
}       

Well I fixed it by killing the wallpaper's process when the GLSurfaceView is destroyed(android.os.Process.killProcess(android.os.Process.myPid())).

It works well, but I'm not very satisfied, it wasn't the shader as it'd sitll happen even after setting gl_FragColor.a to 0.5 in the fragment shader, so I still have no idea what was causing it.

Never the less I'll take killing the process as a solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM