Changing colors in a shader - opengl

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]);

Related

How can I render a textured quad so that I fade different corners?

I'm drawing textured quads to the screen in a 2D environment. The quads are used as a tile-map. In order to "blend" some of the tiles together I had the idea like:
A single "grass" tile drawn on top of dirt would render it as a faded circle of grass; faded from probably the quarter point.
If there was a larger area of grass tiles, then the edges would gradually fade from the quarter point that is on the edge of the grass.
So if the entire left-edge of the quad was to be faded, it would have 0 opacity at the left-edge, and then full opacity at one quarter of the width of the quad. Right edge fade would have full opacity at the three-quarters width, and fade down to 0 opacity at the right-most edge.
I figured that setting 4 corners as "on" or "off" would be enough to have the fragment shader work it out. However, I can't work it out.
If corner0 were 0 the result should be something like this for the quad:
If both corner0 and corner1 were 0 then it would look like this:
This is what I have so far:
#version 330
layout(location=0) in vec3 inVertexPosition;
layout(location=1) in vec2 inTexelCoords;
layout(location=2) in vec2 inElementPosition;
layout(location=3) in vec2 inElementSize;
layout(location=4) in uint inCorner0;
layout(location=5) in uint inCorner1;
layout(location=6) in uint inCorner2;
layout(location=7) in uint inCorner3;
smooth out vec2 texelCoords;
flat out vec2 elementPosition;
flat out vec2 elementSize;
flat out uint corner0;
flat out uint corner1;
flat out uint corner2;
flat out uint corner3;
void main()
{
gl_Position = vec4(inVertexPosition.x,
-inVertexPosition.y,
inVertexPosition.z, 1.0);
texelCoords = vec2(inTexelCoords.x,1-inTexelCoords.y);
elementPosition.x = (inElementPosition.x + 1.0) / 2.0;
elementPosition.y = -((inElementPosition.y + 1.0) / 2.0);
elementSize.x = (inElementSize.x) / 2.0;
elementSize.y = -((inElementSize.y) / 2.0);
corner0 = inCorner0;
corner1 = inCorner1;
corner2 = inCorner2;
corner3 = inCorner3;
}
The element position is provided in the range of [-1,1], the corner variables are all either 0 or 1. These are provided on an instance basis, whereas the vertex position and texelcoords are provided per-vertex. The vertex y-coord is inverted because I work in reverse and just flip it here for ease. ElementSize is on the scale of [0,2], so I'm just converting it to [0,1] range.
The UV coords could be any values, not neccessarily [0,1].
Here's the frag shader
#version 330
precision highp float;
layout(location=0) out vec4 frag_colour;
smooth in vec2 texelCoords;
flat in vec2 elementPosition;
flat in vec2 elementSize;
flat in uint corner0;
flat in uint corner1;
flat in uint corner2;
flat in uint corner3;
uniform sampler2D uTexture;
const vec2 uScreenDimensions = vec2(600,600);
void main()
{
vec2 uv = texelCoords;
vec4 c = texture(uTexture,uv);
frag_colour = c;
vec2 fragPos = gl_FragCoord.xy / uScreenDimensions;
// What can I do using the fragPos, elementPos??
}
Basically, I'm not sure what I can do using the fragPos and elementPosition to fade pixels toward a corner if that corner is 0 instead of 1. I kind of understand that it should be based on the distance of the frag from the corner position... but I can't work it out. I added elementSize because I think it's needed to determine how far from the corner the given frag is...
To achieve a fading effect, you have to use Blending. YOu have to set the alpha channel of the fragment color dependent on a scale:
frag_colour = vec4(c.rgb, c.a * scale);
scale has to be computed dependent on the texture coordinates (uv). If a coordinate is in range [0.0, 0.25] or [0.75, 1.0] then the texture has to be faded dependent on the corresponding cornerX variable. In the following the variables uv is assumed to be a 2 dimensional vector, in range [0, 1].
Compute a linear gradients for the left, right, bottom and top side, dependent on uv:
float gradL = min(1.0, uv.x * 4.0);
float gradR = min(1.0, (1.0 - uv.x) * 4.0);
float gradT = min(1.0, uv.y * 4.0);
float gradB = min(1.0, (1.0 - uv.y) * 4.0);
Or compute Hermite gradients by using smoothstep:
float gradL = smoothstep(0.0, 0.25, uv.x);
float gradR = 1.0 - smoothstep(0.75, 1.0, uv.x);
float gradT = smoothstep(0.0, 0.25, uv.y);
float gradB = 1.0 - smoothstep(0.75, 1.0, uv.y);
Compute the fade factor for the 4 corners and the 4 sides dependent on gradL, gradR, gradT, gradB and the corresponding cornerX variable. Finally compute the maximum fade factor:
float fade0 = float(corner0) * max(0.0, 1.0 - dot(vec2(0.707), vec2(gradL, gradT)));
float fade1 = float(corner1) * max(0.0, 1.0 - dot(vec2(0.707), vec2(gradL, gradB)));
float fade2 = float(corner2) * max(0.0, 1.0 - dot(vec2(0.707), vec2(gradR, gradB)));
float fade3 = float(corner3) * max(0.0, 1.0 - dot(vec2(0.707), vec2(gradR, gradT)));
float fadeL = float(corner0) * float(corner1) * (1.0 - gradL);
float fadeB = float(corner1) * float(corner2) * (1.0 - gradB);
float fadeR = float(corner2) * float(corner3) * (1.0 - gradR);
float fadeT = float(corner3) * float(corner0) * (1.0 - gradT);
float fade = max(
max(max(fade0, fade1), max(fade2, fade3)),
max(max(fadeL, fadeR), max(fadeB, fadeT)));
At the end compute the scale and set the fragment color:
float scale = 1.0 - fade;
frag_colour = vec4(c.rgb, c.a * scale);

Is it possible to tween the red color to blue?

I have some code I wrote in the book of shaders editor:
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
float remap(float a, float b, float c, float d, float t) {
return ((t - a) / (b - a)) * (d-c) + c;
}
float outline(vec2 st) {
return smoothstep(0.99, 1.0, st.y) + smoothstep(0.99, 1.0, st.x) + smoothstep(0.01, 0.0, st.y) + smoothstep(0.01, 0.0, st.x);
}
float mouseFoo(vec2 scaledSt, vec2 u_mouse, float scaleVal) {
vec2 scaledMouse = u_mouse * scaleVal;
if(scaledSt.x < ceil(scaledMouse.x) && scaledSt.x > floor(scaledMouse.x) && scaledSt.y < ceil(scaledMouse.y) && scaledSt.y > floor(scaledMouse.y)) {
// if(u_mouse.x < 100.0) {
return 1.0;
} else {
return 0.0;
}
}
void main(){
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(0.03,0.07,0.15);
vec3 redColor = vec3(1.0, 0.0, 0.0);
vec3 outlineColor = vec3(1.0);
float floorSt;
float scaleVal = 5.0;
vec2 scaledSt = st * scaleVal;
// tile
st *= scaleVal;
floorSt = floor(st.x);
st = fract(st);
// inner color
color = mix(color, redColor, mouseFoo(scaledSt, u_mouse/u_resolution.xy, scaleVal));
// outline
color = mix(color, outlineColor, outline(st));
gl_FragColor = vec4(color, 1.0 );
}
I'm wondering if it's possible to have the red color tween to the blue color when a box is hovered off? I think I might have an idea of how to do it if I were to write data to a texture and look that up, but even then I'm not entirely sure.
Use mix
Use mix to interpolate between red and blue. You need another variable that transitions from 0-1 to do the blend, which is mix's 3rd parameter.
ShaderToy example:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;
vec3 red = vec3(1,0,0);
vec3 blue = vec3(0,0,1);
// Output to screen
fragColor = vec4(mix(red, blue, uv.x),1.0);
}
which produces:
In your case, you'll want the 3rd parameter (the alpha or lerp parameter) to be driven over some time (say, .2 seconds) after the mouse entered the hover area. You'll need to do one of the following:
Detect the hover entered at a higher level and then pass the mouse down time in as a uniform
Drive the 3rd parameter directly from a uniform

How to make a shader fade to a color?

This is the current shader I am using. It fades the object by slowly reducing the opacity. I want to fade to purple. How can this be done?
shader.frag:
uniform sampler2D texture;
uniform float opacity;
void main()
{
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
gl_FragColor = pixel * vec4(1.0, 1.0, 1.0, opacity);
}
shader.vert:
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
}
application of shader in main function:
sf::Shader shader;
if (!shader.loadFromFile("shader.vert", "shader.frag"))
return EXIT_FAILURE;
float opacity = 1.0; //transparency of shader
shader.setParameter("texture", sf::Shader::CurrentTexture); //shader.vert
shader.setParameter("opacity", opacity); //shader.frag
////////////////////////////
//Delete Text Display
counter1 = 0;
for (iter8 = textDisplayArray.begin(); iter8 != textDisplayArray.end(); iter8++)
{
if (textDisplayArray[counter1].destroy == true)
{
//shader
opacity -= 0.1;
if (opacity <= 0)
{
textDisplayArray.erase(iter8);
opacity = 1;
}
shader.setParameter("opacity", opacity);
}
The RGB value for purple is vec3( 1.0, 0.0, 1.0 ) (maximum red, minimal green and maximum blue). You have to interpolate between your frgment color and the color value of purpel, similar as you do it with opacity. Use mix for this. mix(x, y, a) performs a linear interpolation between x and y using a to weight between them. The return value is computed as x×(1−a)+y×ax×(1−a)+y×a.
uniform sampler2D texture;
uniform float opacity;
uniform float purpleFac;
void main()
{
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
vec3 mixedCol = mix( vec3( 1.0, 0.0, 1.0 ), pixel.rgb, purpleFac );
gl_FragColor = vec4( mixedCol , opacity );
}
Note you have to set uniform purpleFac similar as you do it with opacity. purpleFac shoud be in range [0.0, 1.0]. If purpleFac is 1.0 your fragment is colord purple and if it is 0.0 your fragment colol is the color of the texture only.

openGL linear depth information

I want to implement Screen Space rendering fluid but I have a trouble with getting depth information.
the depth image I have got is too white.I think is because the depth is not linear.When I look this image very close, it will have a reasonable performance, I can see the depth change. In the same circle, colour in the centre is black and the colour will become white and white when it close to the edge.
So I do a linear for the depth, it looks better but the depth also won't change in the same circle. here is my vertex shader:
#version 400
uniform float pointScale;
layout(location=0) in vec3 position;
uniform mat4 viewMat, projMat, modelMat;
uniform mat3 normalMat;
out vec3 fs_PosEye;
out vec4 fs_Color;
void main()
{
vec3 posEye = (viewMat * vec4(position.xyz, 1.0f)).xyz;
float dist = length(posEye);
gl_PointSize = 1.0f * (pointScale/dist);
fs_PosEye = posEye;
fs_Color = vec4(0.5,0.5,0.5,1.0f);
gl_Position = projMat * viewMat * vec4(position.xyz, 1.0);
}
here is my fragment shader:
#version 400
uniform mat4 viewMat, projMat, modelMat;
uniform float pointScale; // scale to calculate size in pixels
in vec3 fs_PosEye;
in vec4 fs_Color;
out vec4 out_Color;
out vec4 out_Position;
float linearizeDepth(float exp_depth, float near, float far) {
return (2 * near) / (far + near - exp_depth * (far - near));
}
void main()
{
// calculate normal from texture coordinates
vec3 N;
N.xy = gl_PointCoord.xy* 2.0 - 1;
float mag = dot(N.xy, N.xy);
if (mag > 1.0) discard; // kill pixels outside circle
N.z = sqrt(1.0-mag);
//calculate depth
vec4 pixelPos = vec4(fs_PosEye + normalize(N)*1.0f,1.0f);
vec4 clipSpacePos = projMat * pixelPos;
//clipSpacePos.z = linearizeDepth(clipSpacePos, 1, 400);
float depth = clipSpacePos.z / clipSpacePos.w;
//depth = linearizeDepth(depth, 1, 100);
gl_FragDepth = depth;
float diffuse = max(0.0, dot(N, vec3(0.0,0.0,1.0)));
out_Color = diffuse * vec4(0.0f, 0.0f, 1.0f, 1.0f);
out_Color = vec4(N, 1.0);
out_Color = vec4(depth, depth, depth, 1.0);
}
I want to interpolation based on normal after linear.

OpenGL GLSL blend two textures by arbitrary shape

I have a full screen quad with two textures.
I want to blend two textures in arbitrary shape according to user selection.
For example, the quad at first is 100% texture0 while texture1 is transparent.
If the user selects a region, for example a circle, by dragging the mouse on the quad, then
circle region should display both texture0 and texture1 as translucent.
The region not enclosed by the circle should still be texture0.
Please see example image, textures are simplified as colors.
For now, I have achieved blending two textures on the quad, but the blending region can only be vertical slices because I use the step() function.
My frag shader:
uniform sampler2D Texture0;
uniform sampler2D Texture1;
uniform float alpha;
uniform float leftBlend;
uniform float rightBlend;
varying vec4 oColor;
varying vec2 oTexCoord;
void main()
{
vec4 first_sample = texture2D(Texture0, oTexCoord);
vec4 second_sample = texture2D(Texture1, oTexCoord);
float stepLeft = step(leftBlend, oTexCoord.x);
float stepRight = step(rightBlend, 1.0 - oTexCoord.x);
if(stepLeft == 1.0 && stepRight == 1.0)
gl_FragColor = oColor * first_sample;
else
gl_FragColor = oColor * (first_sample * alpha + second_sample * (1.0-alpha));
if (gl_FragColor.a < 0.4)
discard;
}
To achieve arbitrary shape, I assume I need to create a alpha mask texture which is the same size as texture0 and texture 1?
Then I pass that texture to frag shader to check values, if value is 0 then texture0, if value is 1 then blend texture0 and texture1.
Is my approach correct? Can you point me to any samples?
I want effect such as OpenGL - mask with multiple textures
but I want to create mask texture in my program dynamically, and I want to implement blending in GLSL
I have got blending working with mask texture of black and white
uniform sampler2D TextureMask;
vec4 mask_sample = texture2D(TextureMask, oTexCoord);
if(mask_sample.r == 0)
gl_FragColor = first_sample;
else
gl_FragColor = (first_sample * alpha + second_sample * (1.0-alpha));
now mask texture is loaded statically from a image on disk, now I just need to create mask texture dynamically in opengl
Here's one approach and sample.
Create a boolean test for whether you want to blend.
In my sample, I use an equation for a circle centered on the screen.
Then blend (i blended by weighted addition of the 2 colors).
(NOTE: i didn't have texture coords to work with in this sample, so i used the screen resolution to determine the circle position).
uniform vec2 resolution;
void main( void ) {
vec2 position = gl_FragCoord.xy / resolution;
// test if we're "in" or "out" of the blended region
// lets use a circle of radius 0.5, but you can make this mroe complex and/or pass this value in from the user
bool isBlended = (position.x - 0.5) * (position.x - 0.5) +
(position.y - 0.5) * (position.y - 0.5) > 0.25;
vec4 color1 = vec4(1,0,0,1); // this could come from texture 1
vec4 color2 = vec4(0,1,0,1); // this could come from texture 2
vec4 finalColor;
if (isBlended)
{
// blend
finalColor = color1 * 0.5 + color2 * 0.5;
}
else
{
// don't blend
finalColor = color1;
}
gl_FragColor = finalColor;
}
See the sample running here: http://glsl.heroku.com/e#18231.0
(tried to post my sample image but i don't have enough rep) sorry :/
Update:
Here's another sample using mouse position to determine the position of the blended area.
To run, paste the code in this sandbox site: https://www.shadertoy.com/new
This one should work on objects of any shape, as long as you have the mouse data setup correct.
void main(void)
{
vec2 position = gl_FragCoord.xy;
// test if we're "in" or "out" of the blended region
// lets use a circle of radius 10px, but you can make this mroe complex and/or pass this value in from the user
float diffX = position.x - iMouse.x;
float diffY = position.y - iMouse.y;
bool isBlended = (diffX * diffX) + (diffY * diffY) < 100.0;
vec4 color1 = vec4(1,0,0,1); // this could come from texture 1
vec4 color2 = vec4(0,1,0,1); // this could come from texture 2
vec4 finalColor;
if (isBlended)
{
// blend
finalColor = color1 * 0.5 + color2 * 0.5;
}
else
{
// don't blend
finalColor = color1;
}
gl_FragColor = finalColor;
}