I'm very new to GLSL and started with a simple greyscale shade. I used the code of GamesFromScratch's tutorial:
vertexshader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
Fragmentshader:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform mat4 u_projTrans;
void main() {
vec3 color = texture2D(u_texture, v_texCoords).rgb;
float gray = (color.r + color.g + color.b) / 3.0;
vec3 grayscale = vec3(gray);
gl_FragColor = vec4(grayscale, 1.0);
}
The effect and the problem: Everything is rendered in grayscale only, but transparent parts of the textures become white. For example: A simple filled circle is usually drawn as a circle. Now its a circle within a white box. Next to the removed transparent parts also changes on the alpha are not visible.
The problem is in your fragment shader. You create a vec3 color imagine (r,g,b) then you set gl_FragColor to a vec4 (r,g,b,a). Use use the first three from grayscale and then set the "a" to a hard coded alpha value of 1, removing any transparency.
You could get the rgba from the sampler and use its alpha in the final vec4.
Also if you are looking for a more true grayscale conversion the general standard is
color = 0.299 * r + 0.587 * g + 0.114 * b
https://en.wikipedia.org/wiki/Grayscale
I think these changes will help you.
vec4 color = texture2D(u_texture, v_texCoords);
float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(grayscale, color.a);
In my changes, I read color with alpha from texture and apply it to output.
Related
This is the process I go through to render the scene:
Bind MSAA x4 GBuffer (4 Color Attachments, Position, Normal, Color and Unlit Color (skybox only. I also have a Depth component/Texture).
Draw SkyBox
Draw Geo
Blit all Color and Depth Components to a Single Sample FBO
Apply Lighting (I use the depth texture to check if it should be lit by checking if depth texture value is less than 1).
Render Quad
And this is what is happening:
As you can see I get these white and black artefacts around the edge instead of smooth edge. (Good to note that if I remove the lighting and just render the texture without lighting, I don't get this and it smooths correctly).
Here is my shader (it has SSAO implemented but that seem to not effect this).
#version 410 core
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D texFramebuffer;
uniform sampler2D ssaoTex;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedo;
uniform sampler2D gAlbedoUnlit;
uniform sampler2D gDepth;
uniform mat4 View;
struct Light {
vec3 Pos;
vec3 Color;
float Linear;
float Quadratic;
float Radius;
};
const int MAX_LIGHTS = 32;
uniform Light lights[MAX_LIGHTS];
uniform vec3 viewPos;
uniform bool SSAO;
void main()
{
vec3 color = texture(gAlbedo, Texcoord).rgb;
vec3 colorUnlit = texture(gAlbedoUnlit, Texcoord).rgb;
vec3 pos = texture(gPosition, Texcoord).rgb;
vec3 norm = normalize(texture( gNormal, Texcoord)).rgb;
vec3 depth = texture(gDepth, Texcoord).rgb;
float ssaoValue = texture(ssaoTex, Texcoord).r;
// then calculate lighting as usual
vec3 lighting;
if(SSAO)
{
lighting = vec3(0.3 * color.rgb * ssaoValue); // hard-coded ambient component
}
else
{
lighting = vec3(0.3 * color.rgb); // hard-coded ambient component
}
vec3 posWorld = pos.rgb;
vec3 viewDir = normalize(viewPos - posWorld);
for(int i = 0; i < MAX_LIGHTS; ++i)
{
vec4 lightPos = View * vec4(lights[i].Pos,1.0);
vec3 normLight = normalize(lightPos.xyz);
float distance = length(lightPos.xyz - posWorld);
if(distance < lights[i].Radius)
{
// diffuse
vec3 lightDir = normalize(lightPos.xyz - posWorld);
vec3 diffuse = max(dot(norm.rgb, lightDir), 0.0) * color.rgb *
lights[i].Color;
float attenuation = 1.0 / (1.0 + lights[i].Linear * distance + lights[i].Quadratic * distance * distance);
lighting += (diffuse*attenuation);
}
}
if(depth.r >= 1)
{
outColor = vec4(colorUnlit, 1.0);
}
else
{
outColor = vec4(lighting, 1.0);
}
}
So the last if statement checks if it is in the depth texture, if it is then apply lighting, if it is not then just draw the skybox (this is so lighting is not applied to the skybox).
I have spent a few days trying to work this out, changing ways of checking if it should be light by comparing normals, position and depth, changing the formats to a higher res (e.g. using RGB16F instead of RGB8 etc.) but I can't figure out what is causing it and doing lighting per sample (using texel fetch) would be way to intensive.
Any Ideas?
This question is a bit old now but I thought I would say how I solved my issue.
I run basic Sobel Filter in my shader which I use to do screen-space outlines, but in addition I also check if MSAA is enabled and if so compute lighting per texel around the edge pixels!
Let's say the concept is to create a map consisting of cubes with a neon aesthetic, such as:
Currently I have this vertex shader:
// Uniforms
uniform mat4 u_projection;
uniform mat4 u_view;
uniform mat4 u_model;
// Vertex atributes
in vec3 a_position;
in vec3 a_normal;
in vec2 a_texture;
vec3 u_light_direction = vec3(1.0, 2.0, 3.0);
// Vertex shader outputs
out vec2 v_texture;
out float v_intensity;
void main()
{
vec3 normal = normalize((u_model * vec4(a_normal, 0.0)).xyz);
vec3 light_dir = normalize(u_light_direction);
v_intensity = max(0.0, dot(normal, light_dir));
v_texture = a_texture;
gl_Position = u_projection * u_view * u_model * vec4(a_position, 1.0);
}
And this pixel shader:
in float v_intensity;
in vec2 v_texture;
uniform sampler2D u_texture;
out vec4 fragColor;
void main()
{
fragColor = texture(u_texture, v_texture) * vec4(v_intensity, v_intensity, v_intensity, 1.0);
}
How would I use this to create a neon effect such as in the example for 3D cubes? The cubes are simply models with a mesh/material. The only change would be to set the material color to black and the outlines to a bright pink or blue (maybe with a glow).
Any help is appreciated. :)
You'd normally implement this as a post-processing effect. First render with bright, saturated colours into a texture, then apply a bloom effect, when drawing that texture to screen.
I've been trying to study opengl for a fun side project and ran into some issue while learning.
Below is a fragment shader:
#version 330 core
in vec3 Normal;
in vec3 Position;
in vec2 TexCoords;
out vec4 color;
uniform vec3 cameraPos;
uniform samplerCube skybox;
struct Material{
sampler2D diffuse0;
sampler2D specular0;
sampler2D emitter0;
sampler2D reflection0;
float shininess;
};
uniform Material material;
void main(){
vec3 I = normalize(Position - cameraPos);
vec3 R = reflect(I, normalize(Normal));
float intensity = 0;
intensity += texture(material.reflection0, TexCoords).x;
vec4 rfl = texture(skybox, R);
//this line doesnt produce anything
color = rfl * intensity;
}
When i used the code above, my model is completely gone from view.
But, if i debug it out separately such as changing the line
color = rfl * intensity;
to
color = rfl;
This actually renders and returns the following picture
And changing that line to
color = vec4(intensity);
It renders and returns the following picture
I've tried changing
color = rfl * some constant
//or
color = vec4(0.5) * intensity
And both rendered my model normally. I'm stumped as to why it doesnt render when i tried multiplying both rfl and intensity together. I think it might be because there are values that the multiplication to fail, but i have no idea what they might be.
Then you change
color = rfl * intensity;
to
color = rfl;
GLSL compiler will drop
uniform Material material;
due optimization. Same happens with skybox when you change line to:
color = intensity;
Make sure that you binding of texture uniforms is correct.
I have a problem with my fragment shader.
I want to get the size of a texture (which is loaded from an image).
I know that it is possible to use textureSize(sampler) to get an ivec2 which contains the texture size. But i don't know why this isn't working (it doesn't compile):
#version 120
uniform sampler2D tex;
float textureSize;
float texelSize;
void main()
{
textureSize = textureSize(tex).x;//first line
//textureSize = 512.0;//if i set the above line as comment and use this one the shader compiles.
texelSize = 1.0 / textureSize;
vec4 color = texture2D(tex,gl_TexCoord[0].st);
gl_FragColor = color * gl_Color;
}
Th problem was that my GLSL version was to low (implemented in 1.30) and that i was missing a parameter.
Here the working version:
#version 130
uniform sampler2D tex;
float textureSize;
float texelSize;
void main()
{
ivec2 textureSize2d = textureSize(tex,0);
textureSize = float(textureSize2d.x);
texelSize = 1.0 / textureSize;
vec4 color = texture2D(tex,gl_TexCoord[0].st);
gl_FragColor = color * gl_Color;
}
I'm trying to create a "transition" effect between two 2D scenes. I have 3 textures: before, after, and mask. before and after are self-explanatory. mask is a simple monochrome texture that defines how the first two get composited. It changes over time, to perform the transition. All 3 textures are the same size.
I've verified that all 3 textures contain the correct data, but when I try to perform the compositing, I end up with either before in its entirety, or after in its entirety, seemingly at random.
Here's what I'm doing:
Application code:
glEnable(GL_MULTISAMPLE);
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
after.handle.bind;
glActiveTextureARB(GL_TEXTURE2_ARB);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
mask.handle.bind;
glActiveTextureARB(GL_TEXTURE0_ARB);
before.handle.bind;
GShaders.UseShaderProgram(maskProgramHandle); //GShaders: Global shader engine
GShaders.SetUniformValue(maskProgramHandle, 'before', 0);
GShaders.SetUniformValue(maskProgramHandle, 'after', 1);
GShaders.SetUniformValue(maskProgramHandle, 'mask', 2);
before.DrawFull; //draws the texture to the screen as a quad.
glDisable(GL_MULTISAMPLE);
Vertex shader:
varying vec4 v_color;
varying vec2 texture_coordinate;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
texture_coordinate = vec2(gl_MultiTexCoord0);
v_color = gl_Color;
gl_FrontColor = gl_Color;
}
Fragment shader:
uniform sampler2DRect before;
uniform sampler2DRect after;
uniform sampler2DRect mask;
varying vec2 texture_coordinate;
void main()
{
vec3 maskValue = texture2DRect(mask, texture_coordinate).rgb;
float alpha = (maskValue.r + maskValue.g + maskValue.b) / 3.0;
vec4 beforeValue = texture2DRect(before, texture_coordinate);
vec4 afterValue = texture2DRect(after, texture_coordinate);
gl_FragColor = mix(beforeValue, afterValue, alpha);
}
Any idea what's going wrong?
This is only guessing, have you tried this
gl_FragColor = mix(beforeValue, afterValue, alpha / 255.0f);