Making a glow effect - Problems with alpha values - glsl

I want to create a glow effect for my game. In order to keep this minimalistic let's say I want to glow an Image. :)
Starting with this one:
To get something like this:
It's a three step way.
save all bright pixels from the scene (= luminescence)
Apply a blur effect on those pixels (= blur)
draw original picture and the blur texture ontop (= assemble)
Step 1 and 3 are no Problem. The blur part just doesn't want to work correctly.
Before I explain further, here's my luminescence result:
(threshold = 0.67f)
An now when I blur this, I get some unlucky results:
This black edge comes from the fact, that any transparent color is black vec4(0.0, 0.0, 0.0, 0.0). It's not an unkown Problem within SFML/GLSL, and the suggestion was to use SFML's sf::BlendMode for this and multiply the .rgb value of the final pixel color in the fragment shader with its alpha value. So I did and now this my result:
It's better, but definetely not good. The blur shader now also avarages out the surrounding pixels of the luminescence mask. After assembling it's just a blurry picture:
.. I tried "fixing" this in the shader files by checking if the pixel's alpha is zero. This way I don't value them when avaraging out. But since sf::BlendMode is activated, I don't know how alpha behaves now - So I deactivated the blendmode but I still have weird results. (at the very of this question I provided the code and a result from this attempt)
none of my attempts to fix this work. I really could use some help here. Maybe I'm doing something fundamentally wrong in the shaders.. here's the full code -
If you want to compile it, make a folder resources with the 2 Fragment shaders and the background.jpg (in 1280x720).
luminescence.frag
#version 120
uniform sampler2D texture;
uniform float threshold;
void main(void){
vec3 current_color = texture2D(texture, gl_TexCoord[0].xy).rgb;
vec4 pixel = vec4(current_color.rgb, 0.0);
float brightness = dot(current_color.rgb, vec3(0.2126, 0.7152, 0.0722));
if (brightness >= threshold){
pixel = texture2D(texture, gl_TexCoord[0].xy);
}
gl_FragColor = pixel;
}
boxblur.frag
#version 120
uniform sampler2D texture;
uniform float texture_inverse;
uniform int blur_radius;
uniform vec2 blur_direction;
void main(void){
vec4 sum = texture2D(texture, gl_TexCoord[0].xy);
for (int i = 0; i < blur_radius; ++i){
sum += texture2D(texture, gl_TexCoord[0].xy + (i * texture_inverse) * blur_direction);
sum += texture2D(texture, gl_TexCoord[0].xy - (i * texture_inverse) * blur_direction);
}
vec4 pixel = vec4(sum / (blur_radius * 2 + 1));
pixel.rgb *= pixel.a;
gl_FragColor = pixel;
}
main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <exception>
void run() {
const sf::Vector2f SIZE(1280, 720);
sf::Texture background_tex;
background_tex.loadFromFile("resources/background.jpg");
sf::Sprite background(background_tex);
sf::Shader luminescence;
luminescence.loadFromFile("resources/luminescence.frag", sf::Shader::Fragment);
luminescence.setUniform("texture", sf::Shader::CurrentTexture);
luminescence.setUniform("threshold", 0.67f);
sf::Shader blur;
blur.loadFromFile("resources/boxblur.frag", sf::Shader::Fragment);
blur.setUniform("texture", sf::Shader::CurrentTexture);
blur.setUniform("texture_inverse", 1.0f / SIZE.x);
sf::RenderStates shader_states;
shader_states.blendMode = sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcAlpha);
sf::ContextSettings context_settings;
context_settings.antialiasingLevel = 12;
//draws background
sf::RenderTexture scene_render;
scene_render.create(SIZE.x, SIZE.y, context_settings);
//draws luminescence and blur
sf::RenderTexture shader_render;
shader_render.create(SIZE.x, SIZE.y, context_settings);
sf::RenderWindow window(sf::VideoMode(SIZE.x, SIZE.y), "glsl fun", sf::Style::Default, context_settings);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
}
scene_render.clear();
scene_render.draw(background);
scene_render.display();
//apply luminescence
shader_states.shader = &luminescence;
shader_render.clear(sf::Color::Transparent);
shader_render.draw(sf::Sprite(scene_render.getTexture()), shader_states);
shader_render.display();
//apply two pass gaussian blur 3 times to simulate gaussian blur.
shader_states.shader = &blur;
float blur_radius = 30.0f;
for (int i = 0; i < 3; ++i) {
blur.setUniform("blur_radius", static_cast<int>(blur_radius));
//vertical blur
blur.setUniform("blur_direction", sf::Glsl::Vec2(1.0, 0.0));
shader_render.draw(sf::Sprite(shader_render.getTexture()), shader_states);
shader_render.display();
//horizontal blur
blur.setUniform("blur_direction", sf::Glsl::Vec2(0.0, 1.0));
shader_render.draw(sf::Sprite(shader_render.getTexture()), shader_states);
shader_render.display();
//decrease blur_radius to simulate a gaussian blur
blur_radius *= 0.45f;
}
//assembly
window.clear();
window.draw(sf::Sprite(scene_render.getTexture()));
window.draw(sf::Sprite(shader_render.getTexture()));
window.display();
}
}
int main() {
try {
run();
}
catch (std::exception e) {
std::cerr << "caught exception - - - " << e.what() << '\n';
return 1;
}
return 0;
}
This is the boxblur.frag where I tried to exclude zero alpha values: (I removed shader_states.blendMode = sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcAlpha);on line 29 in main.cpp of course):
#version 120
uniform sampler2D texture;
uniform float texture_inverse;
uniform int blur_radius;
uniform vec2 blur_direction;
void main(void){
float div = 0.0;
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 temp_color = texture2D(texture, gl_TexCoord[0].xy);
if (temp_color.a > 0.0){
sum += temp_color;
div += 1.0;
}
for (int i = 0; i < blur_radius; ++i){
temp_color = texture2D(texture, gl_TexCoord[0].xy + (i * texture_inverse) * blur_direction);
if (temp_color.a > 0.0){
sum += temp_color;
div += 1.0;
}
temp_color = texture2D(texture, gl_TexCoord[0].xy - (i * texture_inverse) * blur_direction);
if (temp_color.a > 0.0){
sum += temp_color;
div += 1.0;
}
}
vec4 pixel;
if (div == 0.0){
pixel = vec4(texture2D(texture, gl_TexCoord[0].xy).rgb, 0.0);
}
else{
pixel = vec4(sum / div);
}
gl_FragColor = pixel;
}
Resulting in:
[I am using Visual Studio 2017 Community] - Thanks for any help!

I posted this question also on en.sfml-dev.org (here) and fallahn showed me the correct approach.
Before tackling that, here are the picture results:
Luminescence (threshold = 0.24f):
Blur (4 layers):
Assembled:
Yay! The solution is to set all transparent pixels to solid black vec4(0.0, 0.0, 0.0, 1.0) and than after they've been blurred, just add them ontop the Scene:
vec4 tex_color = texture2D(texture, gl_TexCoord[0].xy);
vec4 add_color = texture2D(add_texture, gl_TexCoord[0].xy);
gl_FragColor = tex_color + add_color;
This way, if add_color is black ("transparent"), we add tex_color + vec4(0.0, 0.0, 0.0, 1.0) which results in no change!
This is great, because now you can ignore the alpha channel completely.
To understand why I find this so great, you can read this little rant here (feel free to skip it):
Without worrying about alpha you can ignore any sf::BlendMode like the confusing sf::BlendMode::OneMinusSrcAlpha which caused me headaches for 2 solid days. Try calculating any reasonable "true" alpha value when you know they are all premultiplied. Of course you also have to multiply all rgb values with the pixel's alpha to reverse the prumultiplication… the formulas escalate quite quickly from here. Also subtract 1 from alpha because it's OneMinusSrcAlpha... and don't forget to check for cases where the sum of all alphas (yes, you need to sum that) is 0 (or in OneMinusSrcAlpha matter, something else), because otherwise you get division by 0 (or in OneMinusSrcAlpha matter a division by 0 when all surrounding pixels are solid). Also sometimes weird alpha values might work, but only for a single pass of blur, but in my case I have multiple passes.. etc.
Here's the final code:
luminescence.frag
#version 120
uniform sampler2D texture;
uniform float threshold;
void main(void){
vec3 current_color = texture2D(texture, gl_TexCoord[0].xy).rgb;
vec4 pixel = vec4(0.0, 0.0, 0.0, 1.0);
float brightness = dot(current_color.rgb, vec3(0.2126, 0.7152, 0.0722));
if (brightness >= threshold){
pixel = texture2D(texture, gl_TexCoord[0].xy);
}
gl_FragColor = pixel;
}
boxblur.frag
#version 120
uniform sampler2D texture;
uniform float texture_inverse;
uniform int blur_radius;
uniform vec2 blur_direction;
void main(void){
vec4 sum = texture2D(texture, gl_TexCoord[0].xy);
for (int i = 0; i < blur_radius; ++i){
sum += texture2D(texture, gl_TexCoord[0].xy + (i * texture_inverse) * blur_direction);
sum += texture2D(texture, gl_TexCoord[0].xy - (i * texture_inverse) * blur_direction);
}
gl_FragColor = sum / (blur_radius * 2 + 1);
}
multiply.frag
#version 120
uniform sampler2D texture;
uniform float multiply;
void main(void){
gl_FragColor = texture2D(texture, gl_TexCoord[0].xy) * multiply;
}
assemble.frag
#version 120
uniform sampler2D texture;
uniform sampler2D add_texture;
uniform float add_weight;
void main(void){
vec4 tex_color = texture2D(texture, gl_TexCoord[0].xy);
vec4 add_color = texture2D(add_texture, gl_TexCoord[0].xy) * add_weight;
gl_FragColor = tex_color + add_color;
}
main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <array>
void run() {
const sf::Vector2f SIZE(1280, 720);
sf::Texture background_tex;
background_tex.loadFromFile("resources/background.jpg");
sf::Sprite background(background_tex);
sf::Shader luminescence_shader;
luminescence_shader.loadFromFile("resources/luminescence.frag", sf::Shader::Fragment);
luminescence_shader.setUniform("texture", sf::Shader::CurrentTexture);
luminescence_shader.setUniform("threshold", 0.24f);
sf::Shader blur_shader;
blur_shader.loadFromFile("resources/boxblur.frag", sf::Shader::Fragment);
blur_shader.setUniform("texture", sf::Shader::CurrentTexture);
blur_shader.setUniform("texture_inverse", 1.0f / SIZE.x);
sf::Shader assemble_shader;
assemble_shader.loadFromFile("resources/assemble.frag", sf::Shader::Fragment);
assemble_shader.setUniform("texture", sf::Shader::CurrentTexture);
sf::Shader multiply_shader;
multiply_shader.loadFromFile("resources/multiply.frag", sf::Shader::Fragment);
multiply_shader.setUniform("texture", sf::Shader::CurrentTexture);
sf::RenderStates shader_states;
//no blendmode! we make our own - assemble.frag
sf::ContextSettings context_settings;
context_settings.antialiasingLevel = 12;
//draws background
sf::RenderTexture scene_render;
scene_render.create(SIZE.x, SIZE.y, context_settings);
sf::RenderTexture luminescence_render;
luminescence_render.create(SIZE.x, SIZE.y, context_settings);
//draws luminescence and blur
sf::RenderTexture assemble_render;
assemble_render.create(SIZE.x, SIZE.y, context_settings);
//addding multiple boxblurs with different radii looks really nice! in this case 4 layers
std::array<sf::RenderTexture, 4> blur_renders;
for (int i = 0; i < blur_renders.size(); ++i) {
blur_renders[i].create(SIZE.x, SIZE.y, context_settings);
}
const int BLUR_RADIUS_VALUES[] = { 250, 180, 125, 55 };
float blur_weight = blur_renders.empty() ? 0.0 : 1.0 / blur_renders.size();
sf::RenderWindow window(sf::VideoMode(SIZE.x, SIZE.y), "glsl fun", sf::Style::Default, context_settings);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
}
//first draw the scene
scene_render.clear();
scene_render.draw(background);
scene_render.display();
//apply luminescence
shader_states.shader = &luminescence_shader;
luminescence_render.clear();
luminescence_render.draw(sf::Sprite(scene_render.getTexture()), shader_states);
luminescence_render.display();
//apply two pass gaussian blur n times to simulate gaussian blur.
shader_states.shader = &blur_shader;
for (int i = 0; i < blur_renders.size(); ++i) {
blur_shader.setUniform("blur_radius", BLUR_RADIUS_VALUES[i]);
blur_renders[i].clear();
blur_renders[i].draw(sf::Sprite(luminescence_render.getTexture()));
blur_renders[i].display();
//vertical blur
blur_shader.setUniform("blur_direction", sf::Glsl::Vec2(1.0, 0.0));
blur_renders[i].draw(sf::Sprite(blur_renders[i].getTexture()), shader_states);
blur_renders[i].display();
//horizontal blur
blur_shader.setUniform("blur_direction", sf::Glsl::Vec2(0.0, 1.0));
blur_renders[i].draw(sf::Sprite(blur_renders[i].getTexture()), shader_states);
blur_renders[i].display();
}
//load blur_renders[0] into assemble_render so we can add the other blurs ontop of it
shader_states.shader = &multiply_shader;
multiply_shader.setUniform("multiply", blur_weight);
assemble_render.clear();
assemble_render.draw(sf::Sprite(blur_renders[0].getTexture()), shader_states);
assemble_render.display();
//adding the rest ontop creating a final blur
shader_states.shader = &assemble_shader;
assemble_shader.setUniform("add_weight", blur_weight);
for (int i = 1; i < blur_renders.size(); ++i) {
assemble_shader.setUniform("add_texture", blur_renders[i].getTexture());
assemble_render.draw(sf::Sprite(assemble_render.getTexture()), shader_states);
assemble_render.display();
}
//final result; scene + blur
assemble_shader.setUniform("add_weight", 1.0f);
assemble_shader.setUniform("add_texture", assemble_render.getTexture());
assemble_render.draw(sf::Sprite(scene_render.getTexture()), shader_states);
assemble_render.display();
window.clear();
window.draw(sf::Sprite(assemble_render.getTexture()));
window.display();
}
}
int main() {
try {
run();
}
catch (std::exception e) {
std::cerr << "caught exception - - - " << e.what() << '\n';
return 1;
}
return 0;
}

Try to make a tiny example where you just want to average TWO pixels. Left (L) and right (R). Then the left pixel is made up of R(L), G(L), B(L), A(L) and the right pixel is made up of R(R), G(R), B(R) and A(R).
Without alpha, the averaging of Blue would just be:
(B(L)+B(R)) / 2
Taking alpha into account, it becomes:
(B(L)*A(L)+B(R)*A(R)) / (A(L)+A(R))
We can directly see that in the case of completely solid pixels (alpha=1) we get exactly the same formula as above:
(B(L)*1+B(R)*1) / (1+1) = (B(L)+B(R)) / 2
Furthermore, let's say that the right pixel is completely transparent and the left is solid, then the right pixel's color component won't affect anything, leaving the result exactly like the left pixel, which is exactly what we want:
(B(L)*1+B(R)*0) / (1+0) = (B(L)) / 1 = B(L)
Both pixels being completely transparent becomes a degenerate case which must be handled in some elegant way.
Now all you have to do is to extend this beyond two pixels. :-)

Related

Optimizing pixel-swapping shader

I'm using a shader that swaps colors/palettes on a texture. The shader checks a pixel for transparency and then sets the pixel if not transparent. Is there an efficient way to ignore 0 alpha pixels other than a potential branch? In this case, where I set pixel = newPixel:
uniform bool alternate;
uniform sampler2D texture;
void main()
{
vec4 pixel = texture2D(bitmap, openfl_TextureCoordv);
if(alternate)
{
vec4 newPixel = texture2D(texture, vec2(pixel.r, pixel.b));
if(newPixel.a != 0.0)
pixel = newPixel;
}
gl_FragColor = pixel;
}
You can use mix and step:
void main()
{
vec4 pixel = texture2D(bitmap, openfl_TextureCoordv);
vec4 newPixel = texture2D(texture, vec2(pixel.r, pixel.b));
gl_FragColor = mix(pixel, newPixel,
float(alternate) * (1.0 - step(newPixel.a, 0.0)));
}
You may want to make a smooth transition depending on the alpha channel. In this case you only need mix:
gl_FragColor = mix(pixel, newPixel, float(alternate) * newPixel.a);
I would look into the step function. You can express the if statement as a product of two conditions.
For example:
if (a >= 0) {
b = c;
}
Is equivalent to
b = (step(a, 0)*c) + (1.0 - step(a, 0)*b);

Move pixel with texture direction and texture velocity / GLSL

I write a little program to explain simply my problem, I try to change the pixel position of picture with a texture one where the component x is the direction, and where the other represent the velocity. The final objective is to use my data from CPU where are compute a NAVIER-STROKE fluid to move the pixel in GLSL. The CPU code is in Processing java library.
I try to undestand what is buggy in my code, but I don't understand how work the pixel translation.
in the first I transform my direction in value color from 0 to 255 in the CPU and after in the GPU transform this one in vectorial direction, and multiply this one by the velocity and scale this one in 1x1 but that's don't work... sorry if my explication is not really understable, but english is not really fluent.
link to the sketch
Processing :
PImage tex_velocity, tex_direction ;
PShader warping;
PImage img ;
int grid_w, grid_h ;
void setup() {
size(600,375,P2D);
// img = loadImage("pirate_small.jpg");
img = loadImage("puros_girl_small.jpg");
grid_w = 60 ;
grid_h = 37 ;
tex_velocity = createImage(grid_w,grid_h,RGB);
tex_direction = createImage(grid_w,grid_h,RGB);
warping = loadShader("shader/warp/rope_warp_frag.glsl");
noise_img(tex_velocity, 20, .1, .1); // max translate for the pixel
noise_img(tex_direction, 360, .1, .1); // degree direction
}
void draw() {
println(frameRate);
if(frameCount%30 == 0) {
noise_img(tex_velocity, 20, .1, .1); // max translate for the pixel
noise_img(tex_direction, 360, .1, .1); // degree direction
}
warping.set("mode", 0) ;
warping.set("texture",img);
warping.set("roof_component_colour",g.colorModeX);
warping.set("wh_ratio",1f/grid_w, 1f/grid_h);
warping.set("vel_texture",tex_velocity);
warping.set("dir_texture",tex_direction);
shader(warping);
image(img,0,0);
resetShader();
image(tex_velocity,5,5);
image(tex_direction,grid_w +15 ,5 );
}
float x_offset, y_offset ;
void noise_img(PImage dst, int max, float ratio_x, float ratio_y) {
noiseSeed((int)random(10000));
for(int x = 0 ; x < dst.width ; x++) {
x_offset += ratio_x ;
for(int y = 0 ; y < dst.height ; y++) {
y_offset += ratio_y ;
float v = map(noise(x_offset,y_offset),0,1,0,max);
v = (int)map(v,0,max,0,g.colorModeX);
int c = color(v,v,v,g.colorModeA) ;
dst.set(x,y,c);
}
}
}
GLSL
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PROCESSING_TEXTURE_SHADER
#define PI 3.1415926535897932384626433832795
varying vec4 vertTexCoord;
uniform sampler2D texture;
uniform int mode;
uniform float roof_component_colour;
uniform sampler2D vel_texture;
uniform sampler2D dir_texture;
uniform vec2 wh_ratio;
float map(float value, float start1, float stop1, float start2, float stop2) {
float result = start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
return result;
}
vec2 cartesian_coord(float angle) {
float x = cos(angle);
float y = sin(angle);
return vec2(x,y);
}
vec2 translate(float fdir, float fvel) {
float angle_in_radian = map(fdir, 0, roof_component_colour, -PI, PI);
vec2 dir_cart = cartesian_coord(angle_in_radian);
return dir_cart *fvel ;
}
void main() {
vec2 ratio = gl_FragCoord.xy *wh_ratio;
vec4 vel = texture2D(vel_texture, ratio);
vec4 dir = texture2D(dir_texture, ratio);
// rendering picture ;
if(mode == 0) {
float direction = dir.x;
float velocity = vel.x;
vec2 translation = translate(direction,velocity);
// not bad, but totaly wrong
// vec2 coord_dest = vertTexCoord.st +translation
vec2 coord_dest = vertTexCoord.st *ratio +translation ;
// not bad, but totaly wrong
vec2 coord_dest = vertTexCoord.st *ratio +translation ;
vec4 tex_colour = texture2D(texture, coord_dest);
gl_FragColor = tex_colour;
}
// velocity
if(mode == 1 ) {
gl_FragColor = texture2D(vel_texture, vertTexCoord.st);;
}
// direction force field
if(mode == 2) {
gl_FragColor = texture2D(dir_texture, vertTexCoord.st);;
}
}
The texture format is GL_RGBA8, this means each color channel is stored to a byte in, which is a integral data tyoe in rage from 0 to 255.
But when you read texts from the texture sampler, the you will get a floating point value in the range from 0.0 to 1.0. (see glTexImage2D - GL_RGBA).
In the fragment shader you have to map the color channel (in [0, 1]), which you read from the texture sampler, to the range from -PI to PI. For this you can use the GLSL function mix, which does a linear interpolation between 2 values:
vec2 translate(float fdir, float fvel) // fdir, fvel in [0.0, 1.0]
{
float angle = mix(-PI, PI, fdir);
return vec2(cos(angle), sin(angle)) * fvel;
}
The texture coordinates are in range [0, 1]. You have to transform the translation to texture coordinates. For this you have to know the size of your image texture:
vec2 wh_ratio; // 1f/grid_w, 1f/grid_h
vec2 imageTexSize; // size of "texture"
vec2 scale = imageTexSize * wh_ratio;
vec2 coord_dest = vertTexCoord.st + translation / scale;
Thx for the help, now I know the picture size of picture in GLSL :) [0,1], but that's don't work expected, I use the the rendering size or the picture of the must be warp, so in my idea the vec2 imageTexSize is img.widthand img.height is passed from Processing for imageTexSize
uniform vec2 imageTexSize;
.../...
vec2 scale = imageTexSize * wh_ratio;
vec2 coord_dest = vertTexCoord.st + translation / scale;
the result is the top image
and when I try this code
vec2 ratio = gl_FragCoord.xy *wh_ratio;
vec2 coord_dest = vertTexCoord.st +translation / ratio ;
the result is the middle image
and when I try this one
vec2 coord_dest = vertTexCoord.st +translation / wh_ratio ;
the result is the bottom image
Sorry i post a single image because I cannot post more than one pic with my beginner reputation :)
I fix the display bug for the full window display, but now it's the y coord who is reverse for the translation, that's weird because the texture velocity and direction are not reversed in y, the reverse y effect is in the interpretation. that's happened on the 3 mode. I try to reverse coord_dest.y like that
float coord_dest_y = mix(coord_dest.y, vertTexCoord.t, 0);
gl_FragColor = texture2D(texture, vec2(coord_dest.x, coord_dest_y));
but that's change nothing.
I try : float coord_dest_y = mix(coord_dest.y, 0, vertTexCoord.t);but that's make something really strange, so that's don't work too...
here the full the GLSL code
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PROCESSING_TEXTURE_SHADER
#define PI 3.1415926535897932384626433832795
varying vec4 vertTexCoord;
uniform sampler2D texture;
uniform int mode;
uniform sampler2D vel_texture;
uniform sampler2D dir_texture;
uniform vec2 wh_grid_ratio;
uniform vec2 wh_renderer_ratio;
vec2 cartesian_coord(float angle) {
float x = cos(angle);
float y = sin(angle);
return vec2(x,y);
}
vec2 translate(float fdir, float fvel) {
//float angle = mix(PI, -PI,fdir);
float angle = mix(fdir, PI, -PI);
return cartesian_coord(angle) *fvel ;
}
void main() {
vec2 ratio = gl_FragCoord.xy *wh_renderer_ratio;
vec4 vel = texture2D(vel_texture, ratio);
vec4 dir = texture2D(dir_texture, ratio);
float direction = dir.x;
float velocity = vel.x;
vec2 translation = translate(direction,velocity);
// mode 0 perfect
// mode 1 interesting
// mode 2 bizarre, but fun
// mode 500 warp image direction
// mode 501 warp image velocity
// perfect
if(mode == 0) {
vec2 scale = gl_FragCoord.xy *wh_renderer_ratio;
vec2 coord_dest = vertTexCoord.st +translation /scale;
float coord_dest_y = mix(coord_dest.y, vertTexCoord.t, 0);
// float coord_dest_y = mix(coord_dest.y, 0, vertTexCoord.t);
gl_FragColor = texture2D(texture, vec2(coord_dest.x, coord_dest_y));
// gl_FragColor = texture2D(texture, coord_dest);
}
// interesting
if(mode == 1) {
vec2 scale = gl_FragCoord.xy *wh_grid_ratio;
vec2 coord_dest = vertTexCoord.st +translation /scale ;
gl_FragColor = texture2D(texture, coord_dest);
}
// bizarre
if(mode == 2) {
vec2 coord_dest = vertTexCoord.st +translation /wh_grid_ratio;
gl_FragColor = texture2D(texture, coord_dest);
}
// velocity
if(mode == 500 ) {
vec4 tex_colour = texture2D(vel_texture, vertTexCoord.st);;
gl_FragColor = tex_colour;
}
// direction force field
if(mode == 501) {
vec4 tex_colour = texture2D(dir_texture, vertTexCoord.st);;
gl_FragColor = tex_colour;
}
}
and the picture result here, to see the cursor error y in the final warping
enter image description here

Shader only rendering 1/4th of the screen

I'm currently trying to create a gaussian blur shader, and while I've successfully created the blur effect my shader only renders the lower right quarter of my screen like the image shows: And just to make it clear; it has NOT re-scaled the image, it just doesn't render the rest of it.
Here's my shader code with comments of my thoughts:
Vertex (horizontal, vertical almost identical. See below)
#version 400
in vec2 a_texCoord0; //My tex coords
out vec2 blurTextureCoords[11]; //Sample 11px (i.e, 5 right 5 left of center)
uniform float u_width; //Width of the screen. Used to calculate pixel size
void main(void){
gl_Position = vec4(a_texCoord0, 0.0, 1.0);
vec2 centerTexCoords = a_texCoord0 * 0.5 + 0.5; //Maybe this is somehow wrong?
float pixelSize = 1.0 / u_width; //This is kind of interesting, because my shader sometimes tells me that "no uniform value was found with name 'u_width', but it still seems to work as if I change the values manually (ex. set it to 1920) it still looks normal.
for(int i=-5; i<=5; i++) {
blurTextureCoords[i+5] = centerTexCoords + vec2(pixelSize * i, 0.0); //I also thought that it might be because I multiply a float with an integer, but if I do float(i) instead of just i it still looks the same.
}
}
Fragment
#version 400
#ifdef GL_ES
precision mediump float;
#endif
in vec2 blurTextureCoords[11];
out vec4 out_colour;
uniform sampler2D u_texture;
void main(void){
//The actual bluring
out_colour = vec4(0.0);
out_colour += texture(u_texture, blurTextureCoords[0]) * 0.0093;
out_colour += texture(u_texture, blurTextureCoords[1]) * 0.028002;
out_colour += texture(u_texture, blurTextureCoords[2]) * 0.065984;
out_colour += texture(u_texture, blurTextureCoords[3]) * 0.121703;
out_colour += texture(u_texture, blurTextureCoords[4]) * 0.175713;
out_colour += texture(u_texture, blurTextureCoords[5]) * 0.198596;
out_colour += texture(u_texture, blurTextureCoords[6]) * 0.175713;
out_colour += texture(u_texture, blurTextureCoords[7]) * 0.121703;
out_colour += texture(u_texture, blurTextureCoords[8]) * 0.065984;
out_colour += texture(u_texture, blurTextureCoords[9]) * 0.028002;
out_colour += texture(u_texture, blurTextureCoords[10]) * 0.0093;
}
Additional code
Creating a shader:
//I also have one for the vertical shader, it's almost exactly the same.
horizontalShader = new ShaderProgram(
Gdx.files.internal("graphics/shaders/post-processing/blur/horizontalBlur.vert"),
Gdx.files.internal("graphics/shaders/post-processing/blur/blur.frag"));
horizontalShader.pedantic = false;
horizontalShader.begin();
horizontalShader.setUniformf("u_width", Gdx.graphics.getWidth());
horizontalShader.end();
if (horizontalShader.getLog().length() != 0) {
System.out.println("Horizontal shader! \n" + horizontalShader.getLog());
}
Rendering to FBO then to screen:
// Horozontal blur
horizontalFBO.begin();
spriteBatch.begin();
spriteBatch.setShader(horizontalShader);
background_image.draw(spriteBatch);
spriteBatch.end();
horizontalFBO.end();
// Vertical blur
verticalFBO.begin();
spriteBatch.begin();
spriteBatch.setShader(verticalShader);
spriteBatch.draw(horizontalFBO.getColorBufferTexture(), 0, 0);
spriteBatch.end();
verticalFBO.end();
// Normal FBO (screen)
spriteBatch.begin();
spriteBatch.setShader(null);
spriteBatch.draw(verticalFBO.getColorBufferTexture(), 0, 0);
spriteBatch.end();
Additional info
I use two FBOs, but it seems that those are not the root of the problem, as the problem still persists if I just render directly to the screen using these shaders.
I have two vertex shaders, one for the horizontal and one for the vertical blur. The only difference is the uniform name u_width becomes u_height and the blurTextureCoords[i+5] = centerTexCoords + vec2(pixelSize * i, 0.0); becomes blurTextureCoords[i+5] = centerTexCoords + vec2(0.0, pixelSize * i);

Changing colors in a shader

I have a Grey Scale Shader for the Shaders Mod for Minecraft. I have the final.fsh, and it works real nice with this resource pack:
"Craftboy Grey"
However, I'd like to modify the shader to show up in green, similar to the grey does.
"Craftboy Green"
The reason I need the shader, is to modify all the colors the resource pack cannot, and also change other player's skins to the same scale, without them needing to manually do it.
Here's the code for the shader:
// Grayscale shader by daxnitro.
// Small edit by Edrem
// It makes the green brighter =D
uniform sampler2D sampler0;
uniform sampler2D sampler1;
uniform sampler2D sampler2;
uniform float near;
uniform float far;
float getBrightness(vec4 color);
float getDepth(vec2 coord);
void applyEffect() {
float brightness = getBrightness(gl_FragColor);
gl_FragColor = vec4(brightness, brightness, brightness, gl_FragColor[3]);
}
void main() {
vec4 baseColor = texture2D(sampler0, gl_TexCoord[0].st);
gl_FragColor = baseColor;
float depth = getDepth(gl_TexCoord[0].st);
if (gl_FragColor[3] == 0.0) {
gl_FragColor = gl_Fog.color;
}
applyEffect();
}
float getBrightness(vec4 color) {
return color[0] * 0.299f + color[1] * 0.587f + color[2] * 0.114f;
}
float getDepth(vec2 coord) {
float depth = texture2D(sampler1, coord).x;
float depth2 = texture2D(sampler2, coord).x;
if (depth2 < 1.0) {
depth = depth2;
}
depth = 2.0 * near * far / (far + near - (2.0 * depth - 1.0) * (far - near));
return depth;
}
To make it "green scale" instead of grey scale, write the brightness only to the green component of the output:
void applyEffect() {
float brightness = getBrightness(gl_FragColor);
gl_FragColor = vec4(0.0, brightness, 0.0, gl_FragColor[3]);
}
If you want more overall brightness while still having the whole thing tinted green, you can add some brightness back in the red and blue components. For example:
gl_FragColor = vec4(brightness * vec3(0.5, 1.0, 0.5), gl_FragColor[3]);

GLSL blending modes, creating additive transparency

I have a little shader that looks like this, and has a neat effect.
uniform float beatScale;
varying vec3 vPos;
void main() {
vec3 normPos = (normalize(vPos) + vec3(1, 1, 1)) / vec3(2, 2, 2);
float alpha;
if (normPos.y < beatScale - 0.1) {
alpha = 0.0;
} else if (normPos.y < beatScale) {
alpha = 1.0 - (beatScale - normPos.y) / 0.1;
} else {
alpha = 1.0;
}
gl_FragColor = vec4(normPos, alpha);
}
But the transparent parts of my objects in front block the objects behind, knocking out pixels that should have been rendered.
My sorry attempt was:
gl_FragColor = gl_FragColor + vec4(normPos, alpha);
But that didn't seem to change it. I was hoping gl_FragColor had the previous pixel color, but no dice.
How can I add the computed color the color that was there before? I don't care about what's on top, this is all glowy stuff I can simply add together.
If you're doing additive blending, then you should turn off depth writes.