OpenGL ES 2.0, how to animate texture's opacity - opengl-es

I'm using OpenGL ES 2.0 to create the following scene:
Draw a background image on the entire screen and above it draw another overlay image that fades in and out (alpha changes)
I also need to use "Screen blend" to blend the overlay and the background textures.
So I created a shader that blends the two textures, I thought that I can use a uniform (randomAlpha) to change the overlay texture alpha over time and create a fade animation, but the following code doesn't do the trick, the overlay texture opacity doesn't changes!
I know there is an "Alpha Blend" that I can use to blend the overlay and the background textures, but the problem is that I want the final overlay (after opacity changes) to blend the background with a "Screen Blend" not an "Alpha Blend"
This is how my fragment shader main method looks like:
void main()
{
mediump vec4 background = texture2D(backgroundTexture, backgroundCoords);
mediump vec4 overlay = texture2D(overlayTexture, overlayCoords);
overlay.a = randomAlpha;
// add overlay to background (using screen blend)
mediump vec4 whiteColor = vec4(1.0);
gl_FragColor = whiteColor - ((whiteColor - overlay) * (whiteColor - background));
}
Clearly I missing something important here..
How can I change the texture's opacity? how can I create the fade effect?

Like you already figured it's just a matter of blending.
What you're missing is that you need to re-calculate the rgb channels, when you change the alpha value when you want to blend to textures together.
void main()
{
mediump vec4 background = texture2D(backgroundTexture, backgroundCoords);
mediump vec4 overlay = texture2D(overlayTexture, overlayCoords);
overlay.a = randomAlpha;
background.a = 1.0 - overlay.a;
gl_FragColor = vec4(background.rgb * background.a + overlay.rgb * overlay.a, 1.0);
}
Here is a simplified version of the above code, the above code is just easier to understand and read.
void main()
{
mediump vec4 background = texture2D(backgroundTexture, backgroundCoords);
mediump vec4 overlay = texture2D(overlayTexture, overlayCoords);
overlay.rgb *= randomAlpha;
background.rgb *= 1.0 - randomAlpha;
gl_FragColor = vec4(background.rgb + overlay.rgb, 1.0);
}

Related

Blending issues between InstancedMesh using a ShaderMaterial (trying to reproduce mix-blend-mode: overlay from Figma)

I've been working on blending between InstancedMesh using a ShaderMaterial. The blending between the InstancedMesh works fine with THREE.JS blending mode (Additive, Substractive, ...) but i struggle to match the Figma design with thoses (See the attached screenshots, first is the current result with THREE.JS using Additive blend mode, second is the result i need from Figma).
Current Result using Additive Blending
Result needed from Figma
A mix-blend-mode: overlay is used on Figma between all the circles (the InstancedMesh in Three.js), so i tried to add some glsl blend overlay code (https://github.com/jamieowen/glsl-blend) like that in the ShaderMaterial used by the InstancedMesh :
uniform vec3 uColors[6];
uniform float uThresholds[6];
varying vec2 vUv;
float blendOverlay(float base, float blend) {
return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend));
}
vec3 blendOverlay(vec3 base, vec3 blend) {
return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b));
}
vec3 blendOverlay(vec3 base, vec3 blend, float opacity) {
return (blendOverlay(base, blend) * opacity + base * (1.0 - opacity));
}
void main() {
vec3 color = mix(uColors[0], uColors[1], smoothstep(uThresholds[0], uThresholds[1], vUv.y));
color = mix(color, uColors[2], smoothstep(uThresholds[1], uThresholds[2], vUv.y));
color = mix(color, uColors[3], smoothstep(uThresholds[2], uThresholds[3], vUv.y));
color = mix(color, uColors[4], smoothstep(uThresholds[3], uThresholds[4], vUv.y));
color = mix(color, uColors[5], smoothstep(uThresholds[4], uThresholds[5], vUv.y));
gl_FragColor = vec4(blendOverlay(color.rgb, ???), 1.0);
}
I understood that i would need some sampler2D uniforms to use them as texture2D for the blendOverlay method to work, but my problem is how can i render those textures ?
If the overlay was just between a "background" and all the InstancedMesh i could render the InstancedMesh in a renderTarget once and use it as a texture. But here i need the overlay blending to be between all the InstancedMesh objects. Should i render the InstancedMesh one by one in a renderTarget and store every textures ? I'm a bit lost here hehe.

WebGL: Change color saturation or luminosity in fragment shader

i found this great page hls picker, and i'm wondering if there is possibility to achieve similar effect in WebGL. I'm passing to my fragment shader some color, for example #FF7400, what is the easiest way to convert it to hsl and change its luminosity, or to have smooth transition to black color (luminosity equel 0). I want to make clouds in my page that have different color(luminosity) depends how far they are from sun. Thanks in advance for any help.
thanks for geat links but i think that i found much simplier way to made easy color transition, all i need is to use webGL method T mix(T x, T y, float a) - linear blend of x and y.
This code i use in shadertoy editor:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec4 orange = vec4(0.533, 0.25, 0.145, 1.0);
vec4 blue = vec4(0.18, 0.23, 0.27, 1.0);
vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
vec4 white = vec4(1.0, 1.0, 1.0, 1.0);
float ratio = iResolution.x / iResolution.y;
float PI = 3.14159265359;
vec4 mixC = mix(orange, blue, sin(ratio * uv.y));
mixC = mix(mixC, black, cos(2.0 * PI * uv.x) / ratio);
mixC = mix(mixC, black, cos(2.0 * PI * uv.y) / ratio);
mixC = mix(mixC, white, 0.1);
fragColor = mixC;
}
As you can see there, i've made transition between of four colors with just couple lines of code and the results looks like this:
I think about fragment shader as a little photoshop. Every photoshop operation should be possible with WebGL.
If we are talking about 2D image where sun position is relative and you want to just use some basic image processing, you can use functions from this answer rgb2hsv and hsv2rgb. I think it should work with GLSL 1.
Then you can multiply Sat, Lum or Hue and then transfer it back to RGB.
If it doesnt, you might have to reimplement it from common formula, use wiki or this link: http://www.rapidtables.com/convert/color/rgb-to-hsl.htm
If you want to do some more image processing, when neighbour pixels are needed, I suggest this great tutorial where you can easy do some edge sharpening, blur etc.: http://webglfundamentals.org/webgl/lessons/webgl-image-processing.html
original image
Hi guys, i think i found a unorthodox but easy way to desaturate an RGB image, we just need to find the average color for the pixel,
average _color = (R+G+B)/3 keeping the Alpha...
vec4(average_color,average_color,average_color, Alpha);
void main()
{
//write a color of the current fragment to a variable
lowp vec4 color_of_pixel = texture2D(texture_sampler, var_texcoord0.xy);
//Find the average among red, green and blue and it keeps the "force" of the color...
float average_color = ((color_of_pixel.r + color_of_pixel.g + color_of_pixel.b)/3);
lowp vec4 color_of_pixel_final = vec4(average_color,average_color,average_color,color_of_pixel.a);
gl_FragColor = color_of_pixel_final; // write the color_of_pixel to the output gl_FragColor
}
Desaturated image

Colored Vignette Shader (the outer part) - LIBGDX

I've seen lots of tutorials on vignette shaders just like these but none of them say how to change the color of the vignette, they only talk about applying sepia or grey shaders to the whole composite image.
For example the video above gives the below code for the vignette shader. How do I change the color of the vignette ? So it's not black but red or orange and the part of the image in the interior of the vignette remains unmodified.
const float outerRadius = .65, innerRadius = .4, intensity = .6;
void main(){
vec4 color = texture2D(u_sampler2D, v_texCoord0) * v_color;
vec2 relativePosition = gl_FragCoord.xy / u_resolution - .5;
relativePosition.y *= u_resolution.x / u_resolution.y;
float len = length(relativePosition);
float vignette = smoothstep(outerRadius, innerRadius, len);
color.rgb = mix(color.rgb, color.rgb * vignette, intensity);
gl_FragColor = color;
}
In the shader you posted, it looks like the vignette value is basically a darkness value that's blended over the image, so in the line with the mix function, it's just multiplied by the texture color.
So to modify this to work with arbitrary color, you need to change it to an opacity value (invert it). And now that it's opacity, you can multiply it by intensity to simplify the next calculation. And finally, you can blend to the vignette color you choose.
So first declare the color you want before the main function.
const vec3 vignetteColor = vec3(1.0, 0.0, 0.0); //red
//this could be a uniform if you want to dynamically change it.
Then your second-to-last two lines change to the following.
float vignetteOpacity = smoothstep(innerRadius, outerRadius, len) * intensity; //note inner and outer swapped to switch darkness to opacity
color.rgb = mix(color.rgb, vignetteColor, vignetteOpacity);
By the way, "intensity = .6f" will cause the shader not to compile on mobile, so remove the f. (Unless you target OpenGL ES 3.0, but that's not fully supported by libgdx yet.)

My fragment shader in WebGL program is setting all the colors from my texture to black

I have a simple game that uses three textures with transparent parts. I can see the silhouettes of my textures, but anywhere that doesn't alpha set to zero returns black (0, 0, 0, 1).
Here's my fragment shader:
precision mediump float;
// our texture
uniform sampler2D u_image0;
uniform sampler2D u_image1;
uniform sampler2D u_image2;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
// Look up a color from the texture.
vec4 textureColor = texture2D(u_image0, v_texCoord);
if (textureColor.a < 0.5)
discard;
else
gl_FragColor = vec4(textureColor.rgb, textureColor.a);
vec4 textureColor1 = texture2D(u_image1, v_texCoord);
if (textureColor1.a < 0.5)
discard;
else
gl_FragColor = vec4(textureColor1.rgb, textureColor1.a);
vec4 textureColor2 = texture2D(u_image2, v_texCoord);
if (textureColor2.a < 0.5)
discard;
else
gl_FragColor = vec4(textureColor2.rgb, textureColor2.a);
I got the conditional that tests for alpha from another question, where pixels with zero alpha were being set to white. Solved my problem, but not sure if it scales properly to multiple textures. I'm pretty sure I'm doing it wrong.
Thanks in advance, and let me know if I need to add more code (vertex shader, etc).
It is unclear to me what you actually try to achieve.
The way you wrote this code makes me think that you do not know what the discard statement actually does: it completely discards the fragment, the current invocation of the shader will be aborted immediately.
What you shader does is just discard the whole fragment if any of the 3 textures has an alpha value below 0.5. The fact that you have written to gl_FragCoord before doing the discard does not matter at all. If all of the textures have the some alpha above 0.5, the final color will be that of u_image2.

OpenGL ES 2.0: Alpha blending issues

I trying to blend my gui komponents again the background but atm it looks very strange, even when i set the alpha to 1.0 in the shader the blendings are really strange.
I enable the blending with the following code:
GL.Enable(All.Blend);
GL.BlendFunc(All.SrcAlpha, All.One);
With alpha set to 1.0 the buttons look like this ( Note: One button is missing ):
The pixel shader is simple:
varying lowp vec2 textureCoordinates;
uniform sampler2D texture;
void main()
{
gl_FragColor = vec4(texture2D(texture, textureCoordinates).bgr, 1.0); // r and b switched, because the colors are switched????
}
One of the buttons:
Use OneMinusSrcAlpha instead of One solves the problem.

Resources