SpriteKit: SKShader with custom shader not doing `mix` properly - ios

I am using a custom shader to create a sprite in SpriteKit.
The main part of the shader does this...
vec4 col = mix(baseColor, overlayColor, overlayColor.a);
The colours I have are something like...
baseColor = UIColor(red:0.51, green:0.71, blue:0.88, alpha:1.0)
and...
overlay = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5)
According to everywhere on the internet (links to follow) the blend function I'm using above is the same as a Normal blend mode in Photoshop, Pixelmator, Sketch, etc... this should result in the colour...
col = UIColor(red:0.75, green:0.85, blue:0.95, alpha:1.00)
Which is a bright blue colour. However, what I'm getting is...
col = UIColor(red:0.51, green:0.61, blue:0.69, alpha:1.00)
Which is a murky grey colour.
You can see what it should look like here... https://thebookofshaders.com/glossary/?search=mix
If you enter the code...
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform float u_time;
vec4 colorA = vec4(0.5, 0.7, 0.9, 1.0);
vec4 colorB = vec4(1.0, 1.0, 1.0, 0.5);
void main() {
vec4 color = vec4(0.0);
// Mix uses pct (a value from 0-1) to
// mix the two colors
color = mix(colorA, colorB, colorB.a);
color.a = 1.0;
gl_FragColor = color;
}
The ideal output colour looks like this...
But it looks like this...
I’m gonna investigate this more tomorrow. I wish I knew why the output was completely different than everywhere else says it should be.

OK, thanks to #Reaper's comment I started out on a full investigation of what was going wrong with this.
When mixing the hard coded colours in our shader the colour was actually correct.
So it lead me to look at the texture images we were using.
The one that had the white with 50% alpha was definitely white. (not grey).
But... (quirk in the system?) open GL was picking it up as 50% grey with 50% alpha.
And so the mix wasn't actually mixing the correct colours in the first place.
We fixed this by using a 100% alpha image for the colours and a 100% image for the alpha map (black -> white).
By doing this it fixed the problem we were having.

Related

Compositing colors and textures in webgl

How to do color compositing in webgl? I am not sure what to search for exactly maybe I am missing a word. I want to be able to draw a color or texture as overlay. For example, here I tried to add black overlay with 0.2 opacity but instead of using color directly I am substracting opacity. If I want to use different color as overlay, I will have to use different work around for it. How can I overlay/composite different colors or textures without using any work around? Shadertoy link
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord/iResolution.xy;
vec4 col = texture(iChannel0, uv);
vec4 overlay = vec4(0., 0., 0., 0.2);
col -= overlay.a;
fragColor = col;
}
If you want to darken the texture color towards black, you could use a simple multiplication:
vec4 col = texture(iChannel0, uv);
col *= 0.8; // 20% darker
Or if you'd like to use a color, you could also multiply those
vec4 col = texture(iChannel0, uv);
vec4 tint = vec4(1.0, 0.5, 0.0, 1.0); // Orange
col *= tint;
There are a lot of ways to blend colors together. Another alternative to create smooth gradients between colors is by using the mix() function. There is no one answer.

Multiple-passes SSAO border artifact

I am playing with multiple passes in WebGL to apply some visual enhancements to my renders.
I am ping-ponging two textures (taken from here: WebGL Image Processing Continued), and this is basically my workflow:
draw the geometry and store the depth vales in a texture buffer
apply the SSAO pass (based on this Fiddle from Rabbid76)
at the end, I am rendering the texture to the screen
Now, I am not able to understand why there is a black border around some parts of the final image.
I tried to fine adjust some SSAO parameters, but I wasn't able to get rid from that artifact, so, just guessing, i believe now that this black border is due a wrong blending setup of my texture buffers.
This is actually the code in the depth pass:
gl.disable(gl.BLEND);
gl.enable(gl.DEPTH_TEST);
gl.depthMask(true);
... drawings
I tried also this way:
gl.enable(gl.BLEND);
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA);
...but is not leading me to any result.
In the picture below, this artifact is clearly to see as a thin black line around the stanford dragon:
As I am completely lost with this issue, can someone point me to the right direction?
My question: I need to draw a geometry with transparent background - which is the correct blending mode for that, when rendering to a back buffer and ping-ponging two textures to apply multiple effects?
For the posterity, I was using:
gl.clearColor(0, 0, 0, 1);
so i changed the pack/unpack functions as follows:
vec4 PackDepth32_0(float depth) {
const vec4 bit_shift = vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0);
const vec4 bit_mask = vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
vec4 res = fract(depth * bit_shift);
res -= res.xxyz * bit_mask;
return res;
}
float UnpackDepth32_0(vec4 color) {
const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
return dot(color, bit_shift);
}
which solves my problem.

Artefact in shader for iOS

kernel vec4 custom(__sample s1, __sample s2) {
if(s1.a == 0.0)
return s2;
if(s2.a == 0.0)
return s1;
vec4 res;
float temp = 1.0 - s2.a;
res.rgb = s2.rgb * s2.aaa + s1.rgb * (temp, temp, temp);
res.a = 1.0;
return res;
}
I am trying to merge 2 images, but have artifacts in bounds, where due to aliasing the pixels have less than 1 alpha. Is there any suggestions what I am doing wrong :/ For example the cheeks have some kind of bound, which doesn't appear if I place one over the other via UIImageViews
OpenGL ES uses post-multiplied alpha, which means that channels are blended independently, but which is inaccurate for a lot of blending operations.
Imagine blending a source fragment [1.0, 0.0, 0.0, 0.5] (red, half transparent) on to a destination framebuffer [0.0, 0.0, 1.0, 0.0] (blue, fully transparent). You would logically expect "half transparent red" as the original destination color is not visible due to the 0.0 alpha value. However, because the channels are blended independently you would end up with the final RGB color being purple [0.5, 0.0, 0.5].
The fast way to fix this is by propagating the color values out into the transparent region, so that the opaque pink color extends out in to the feather region where you start to fade it out.
A better way to fix this is using pre-multipled alpha, but that starts to have side-effects (loss of precision in texel storage, and you need a different blend equation).

Specifing the color for webGL cube in fragment shader

I want to draw a single colour cube in WebGL and I want to specify the color with in the fragment shader. I know that I can do that when I drawing a square. To eloborate my question can I avoid using the color buffer in the way that it is mention in this tutorial.
"MDN WebGl Tutorial"
If you really "want to specify the color within the fragment shader", this is your fragment shader:
precision mediump float;
void main(void) {
gl_FragColor = vec4 (0.0, 1.0, 0.0, 1.0);
}
This would give you green (values in the vec4() are r, g, b, a). Of course, in this case you can eliminate all the color stuff under the heading "Define the vertices' colors" in the tutorial.

OpenGL ES Green Screen... But I want to use black

This works great for green screen, my background is green and using this code it makes green = alpha.
lowp vec4 textureColor = texture2D(u_samplers2D[0], vTextu);
lowp float rbAverage = textureColor.r * 0.5 + textureColor.b * 0.5;
lowp float gDelta = textureColor.g - rbAverage;
textureColor.a = 1.0 - smoothstep(0.0, 0.25, gDelta);
textureColor.a = textureColor.a * textureColor.a * textureColor.a;
gl_FragColor = textureColor;
How do I change the code so that it use a black background instead of green? I'm thinking I could get values for the dark red, green, blues then use that as the alpha? Any pointers would be kind.
You can calculate how close value to black, simplest way is to take maximum of the r g and b values, then set some threshold when you consider color opaque, and map your alpha values to [0..1] in pseudo code:
float brightness = max(textureColor.r, textureColor.g, textureColor.b);
float threshold = 0.1;
float alpha = brightness > threshold ? 1 : (threshold - brightness) / threshold;
gl_FragColor = vec4(textureColor.rgb, alpha);
lowp vec4 textureColor = texture2D(u_samplers2D, vTextu);
lowp float gtemp = smoothstep(0.0, 0.5, textureColor.r);
gl_FragColor = vec4(1.0, 1.0, 1.0, gtemp);
This works for my situation. I was using a greyscale image with black background and just needed the white elements. The problem I had was that I was applying the alpha to grey pixels, but now Im using white and applying the alpha to that. I can adjust the smoothstep values to change the effect. And also add another alpha to fade in or out the image.

Resources