WebGL alpha blending - glsl

I'm trying to layer one texture over another, but I'm having alpha blending issues around the edges. I've tried many blending combinations with no luck. Where am I going wrong?
Current state of framebuffer (opaque):
Transparent texture rendered in off-screen framebuffer:
Result when I try to blend the two. Notice the edges on the circle:
Here's the blendFunc:
_gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
Here's the shader. Just basic rendering of a texture:
uniform sampler2D texture;
varying vec2 vUv;
void main() {
vec4 tColor = texture2D(texture, vUv);
gl_FragColor = tColor;
}

Most likely your textures are using premultiplied alpha and so your blend function should be
_gl.blendFunc(_gl.ONE, _gl.ONE_MINUS_SRC_ALPHA);
If your textures are not premultiplied you probably want to premultiply them either in your shader
gl_FragColor.rgb *= gl_FragColor.a
or when you load them (before you call gl.texImage2D) you can tell the browser to premultiply them
_gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
This document probably explains the issues better
and you might find this relevant as well
WebGL: How to correctly blend alpha channel png

Related

OpenGL / Cocos2d-x What's difference between v_texCoord vs gl_FragCoord in shader?

I've seen the shader code using these two. But i don't understand what's difference between them, between texture and fragment.
As i know, fragment is pixels, so what's texture?
Some use these code:
vec2 uv = gl_FragCoord.xy / rectSize.xy;
vec4 bkg_color = texture2D(CC_Texture0, uv);
some use:
vec4 bkg_color = texture2D(CC_Texture0, v_texCoord);
with v_texCoord = a_texCoord;
Both works, except the first way displays inverted image.
In your second example 'v_texCoord' looks like a pre-calculated texture coordinate that is passed to the Fragment Shader as a Vertex Attribute, versus the 'uv' coordinate calculated within the Fragment Shader of the first example.
You can base texture coordinates off whatever you like - so long as you give the texture2D sampler normalised coordinates - its all about your use case and what you want to display from a texture.
Perhaps there is such a use-case difference here, which is why they give different visual outputs.
For more information about how texture coordinates work I recommend this question's answer: How do opengl texture coordinates work?

In OpenGL, is there a way to blend based on a separate channel's value in the shader?

In OpenGL (not ES), is there a universal way to blend based a texture while drawing based on another texture or variable's value? On OpenGLES, I know that I can do custom blending on some platforms via extensions like GL_EXT_shader_framebuffer_fetch. The reason I ask, is that I have a special texture where the forth channel is not alpha, and I need to be able to blend it on a separate alpha which is available on a different map.
You want dual-source blending, which is available in core as of OpenGL 3.3. This allows you to provide a fragment shader with two outputs and use both of them in the blend function.
You would declare outputs in the fragment shader like this:
layout(location = 0, index = 0) out vec4 outColor;
layout(location = 0, index = 1) out vec4 outAlpha;
You could then set the blending function like this, for premultiplied alpha:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC1_COLOR);
Or non-premultiplied alpha:
glBlendFunc(GL_SRC1_COLOR, GL_ONE_MINUS_SRC1_COLOR);
Note that SRC1 here is the second output of the fragment shader. If I remember correctly, this blending will only work for one location.

How to invert texture colours in OpenGL

I'm texturing a 2D object in OpenGL, and while I have the texture loading fine, I'm just not quite sure how to invert the colours. How do I access the colour information of the bitmap and invert it? Would this be done best in a shader or in the Main program?
I'm leaving this kind of open as I'm not looking for a "fix my code" type of answer, but rather "this is how you access the colour information of the bitmap".
Its s simple as
gl_FragColor = vec4(1.0 - textureColor.r,1.0 -textureColor.g,1.0 -textureColor.b,1)
It is best to do this kind of thing in the shader, if you want to do it once and then reuse it for future draws just use render to texture. This is the fastest way to do color inversion.
EDIT: You use
vec4 textureColor = texture2D(uSampler,vTexCoords)
before your do gl_FragColor
using .r ,.g,.b and .a access the red, green, blue and alpha values respectively.
I'm writing a vision impaired game and for this I wanted to invert the colors, so white is black etc... which sounds like what you're doing. I eventually hit on this that works and does not involve shaders or modifying the textures. However it does kill blending. So I render to a texture buffer and then do
glLogicOp (GL_COPY_INVERTED);
glEnable (GL_COLOR_LOGIC_OP);
<bind to texture buffer and blit that>
glLogicOp (GL_COPY);
glDisable (GL_COLOR_LOGIC_OP);
Actually, you have to invert the texture coordinates before sampling the texture to achieve that.
So, in fragment shader:
vec2 vert_uv_New=vec2(1-vert_uv.x,1-vert_uv.y);
Now sample it:
gl_FragColor=texture2D(sampler,vert_uv_New);
This will do the job.
precision mediump float;
uniform sampler2D u_tex;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = vec4(1,1,1,1) - texture2D(u_tex, v_texCoord);
}

GLSL - Trying to blend vertex color lightmaps and textures

I am working with an old game format and am trying to finish up a rendering project. I am working on lighting and am trying to get a multiply blend mode going in my shader.
The lighting is provided as vertex values which are they interpolated over the triangle.
I have taken a screenshot of an unlit scene, and just the light maps and put them in Photoshop with a multiply layer. It provides exactly what I want.
I also want to factor in the ambient light which is kind of a like a 'Opacity' on the Photoshop color layer.
I have tried just multiplying them, which works great but again, I want to be able to control the amount of the lightmaps. I tried mix, which just blended the lightmaps and the textures but not in a multiply blend.
Here are the images. The first is the diffuse, the second is the lightmap and the third is them combined at 50% opacity with the lightmaps.
http://imgur.com/Zwg9IZr,6hq0t0p,7hR88I2#0 [1]
So, my question is, how do I multiply blend these with the sort of ambient light "opacity" factor. Again, I have tried a direct mix but it's more of an overlay, rather than a multiply blend.
My GLSL fragment source:
#version 120
uniform sampler2D texture;
varying vec2 outtexture; in vec4 colorout;
void main(void)
{
float ambient = 1.0f;
vec4 textureColor = texture2D(texture, outtexture);
vec4 lighting = colorout;
// here is where I want to blend with the ambient light dictating the contribution from each
gl_FragColor = textureColor * lighting;
}

OpenGL Alpha Blending Issue, Blending ignored (maybe)?

EDIT + BETTER SOLUTION:
In case anyone happens to run into the problem I was running into, there are two solutions. One is the solution accepted, but that only applies if you are doing things how I was. Let me explain what I was doing:
1.) Render star background to screen
2.) Render ships, then particles to the FBO
3.) Render FBO to screen
This problem, and therefor the solution to this problem, occurred in the first place because I was blending the FBO with the star background.
The real solution, which is supposedly also slightly faster, is to simply render the star background to the FBO, then render the FBO to screen with blending disabled. Using this method, I do not need to mess with glBlendFuncSeparate...
1.) Render stars, then ships, then particles to FBO
2.) Render FBO to screen with blending disabled
----------ORIGINAL QUESTION:----------
From what I understand of the issue, blending is being ignored somehow. The particle texture with alpha transparency completely overwrites below pixels.
I am creating a top-down game. The camera is slightly angled so that there is some feeling of depth. I am rendering my ships, then rending the particles above them...
After beginning the OpenGL context
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glCullFace(GL_BACK);
In the render loop, I do this:
glBindFramebuffer(GL_FRAMEBUFFER,ook->fbo);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
entitymgr_render(ook); //Render entities. Always 1.0 alpha textures.
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
//glBlendFunc(GL_SRC_ALPHA,GL_ONE); //This would enable additive blending for non-premult
particlemgr_render(ook); //Render particles. Likely always <1.0 alpha textures
//glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBindFramebuffer(GL_FRAMEBUFFER,0);
If I run with the above code, I get results like this...
Particle tex:
Screenshot from OGL Profiler (Mac tool):
Screenshot of the FBO without any particle rendered:
Screenshot of the FBO with some particles rendered on top:
As you can see, the particle, despite having alpha transparency, doesn't blend with the ship rendered below. Instead, it just completely overwrites the pixels.
Final notes, setting pixel transparency in the shader blends correctly - the ship appears below. And here is my shader:
#version 150
uniform sampler2D s_tex1;
uniform float v4_color;
in vec4 vertex;
in vec3 normal;
in vec2 texcoord;
out vec4 frag_color;
void main()
{
frag_color=texture(s_tex1,texcoord)*v4_color;
if(frag_color.a==0.0) discard;
}
Let me know if there is anything I can provide.
Looks to me like it is rendering the alpha channel as well into the frame buffer, so when you write the particles, the src alpha channel is getting mixed with the destination alpha channel, which is not what you want here.
This is exactly why the glblendfuncseparate() function was created. Try this...
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
So, the alpha channel of your particles will be used to determine the colours of the final pixels, but the alpha channels of the source and destination will be added together.
My guess is that the FBO's rgb channels are being rendered correctly, but because it also has an alpha channel, and it is being drawn with blending enabled, the end result has incorrect transparency where the particle overlaps the spaceship.
Either use glBlendFuncSeparate (described here) to use different blend factors for the alpha channel when you're drawing the particles:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
Or turn off blending altogether when you draw your FBO onto the screen.
In order to obtain texture transparency, other than:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
you should assure also that:
when creating the particle tex with glTexImage2D, use as format GL_RGBA (or GL_LUMINANCE_ALPHA if you are using gray shaded textures)
when drawing the particle texture, after the glBindTexture command, call
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
Instead of GL_BLEND, you could use the correct texture functions as described in
the glTexEnv reference: http://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml