Point sprite alpha blending issue (Android / OpenGL ES 2.0) -


i've started looking opengl es android , working on drawing app. i've implemented basics such point sprites, path smoothing , fbo double buffering. @ moment playing around glblendfunc, more when put 2 textures close each other same color/alpha values, alpha gets added appears darker @ intersection of sprites. problem because stroke opacity not preserved if lot of points close together, color tends more opaque rather staying same opacity. there way make textures have same color on intersection, i.e. have same alpha value intersecting pixels, keep alpha values rest of pixels?

here's how i've done relevant parts of app:

  • for drawing list of point sprites use blending this:

    gles20.glenable(gles20.gl_blend); gles20.glblendfunc(gles20.gl_one, gles20.gl_one_minus_src_alpha); 
  • the app uses fbo texture, renders each brush stroke first , texture rendered main screen. blending func there is:

    gles20.glenable(gles20.gl_blend); gles20.glblendfunc(gles20.gl_src_alpha, gles20.gl_one_minus_src_alpha); 
  • opengl es 2.0 doesn't support alpha masking;

  • there no depth_test function used anywhere in app;
  • the textures point sprites pngs transparent backgrounds;
  • the app supports texture masking means 1 texture used shape , 1 texture used content;
  • my fragment shader looks this:

    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; } 
  • my vertex shader this:

    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 , size.     gl_position = umvpmatrix * (aposition + ajitter);     gl_pointsize = apointsize;      // pass values fragment shader.     vcolor = acolor;     vshaperotation = ashaperotation;     vfillrotation = afillrotation;     vfillposition = afillposition; } 

i've tried playing around glblendfunc parameters can't find right combination draw want. i've attached images showing achieve , have @ moment. suggestions?

enter image description here

the solution

finally managed working few lines @ rabbid76. first of had configure depth test function before draw fbo:

gles20.glenable(gles20.gl_depth_test); gles20.gldepthfunc(gles20.gl_less);  // drawing code fbo.  gles20.gldisable(gles20.gl_depth_test); 

then in fragment shader had make sure pixels alpha < 1 in mask discarded this:

... vec4 colormask = texture2d(umasktexture, gl_pointcoord); if (colormask.a < 1.0)     discard; else     gl_fragcolor = calculatedcolor; 

and result (flickering due android emulator , gif capture tool):

enter image description here

if set glblendfunc functions (gl_src_alpha, gl_one_minus_src_alpha) , use glblendequation equation gl_func_add destination color calculated follows:

c_dest = c_src * a_src + c_dest * (1-a_src) 

if blend example c_dest = 1 c_src = 0.5 , a_src = 0.5 then:

c_dest = 0.75 = 1 * 0.5 + 0.5 * 0.5 

if repeat blending same color c_src = 0.5 , a_src = 0.5 destination color becomes darker:

c_dest = 0.625 = 0.75 * 0.5 + 0.5 * 0.5 

since new target color function of original target color , source color, color can not remain equel when blending 2 times, because target color has changed after 1st time blending (except gl_zero).

you have avoid fragment blended twice. if fragments drawn same depth (2d) can use depth test this:

glenable( gl_depth_test ); gldepthfunc( gl_less );  // drawing color  gldisable( gl_depth_test ); 

or stencil test can used. example, stencil test can set pass when stencil buffer equal 0. every time fragment written stencil buffer incremented:

glclear( gl_stencil_buffer_bit ); glenable( gl_stencil_test ); glstencilop( gl_keep, gl_keep, gl_incr ); glstencilfunc( gl_equal, 0, 255 );  // drawing color  gldisable( gl_stencil_test ); 

extension answer

note can discard fragments should not drawn. if fragment in sprite texture has alpha channel of 0 should discard it.

note, if discard fragment neither color nor depth , stencil buffer written.

fragment shaders have access discard command. when executed, command causes fragment's output values discarded. thus, fragment not proceed on next pipeline stages, , fragment shader outputs lost.

fragment shader

if ( color.a < 1.0/255.0 )     discard; 

Comments

Popular posts from this blog

php - Vagrant up error - Uncaught Reflection Exception: Class DOMDocument does not exist -

vue.js - Create hooks for automated testing -

Add new key value to json node in java -