GLSL shader that draws an outline around my object - glsl

I'm trying to make a GLSL shader. The shader should display a red outline around my character. The shader works, but on some specific characters there are red lines, which I don't know how to fix
This is how my shader fragmetn looks:
uniform mat4 u_Color;
varying vec2 v_TexCoord;
varying vec2 v_TexCoord2;
uniform sampler2D u_Tex0;
const float ALPHA_TOLERANCE = 0.01;
void main()
{
vec4 baseColor = texture2D(u_Tex0, v_TexCoord);
vec4 texcolor = texture2D(u_Tex0, v_TexCoord2);
if(texcolor.r > 0.9) {
baseColor *= texcolor.g > 0.9 ? u_Color[0] : u_Color[1];
} else if(texcolor.g > 0.9) {
baseColor *= u_Color[2];
} else if(texcolor.b > 0.9) {
baseColor *= u_Color[3];
}
vec4 pixel1 = texture2D(u_Tex0, vec2(v_TexCoord.x + 0.001, v_TexCoord.y));
vec4 pixel2 = texture2D(u_Tex0, vec2(v_TexCoord.x - 0.001, v_TexCoord.y));
vec4 pixel3 = texture2D(u_Tex0, vec2(v_TexCoord.x, v_TexCoord.y + 0.001));
vec4 pixel4 = texture2D(u_Tex0, vec2(v_TexCoord.x, v_TexCoord.y - 0.001));
bool neighbourColor = pixel4.a > ALPHA_TOLERANCE || pixel3.a > ALPHA_TOLERANCE || pixel2.a > ALPHA_TOLERANCE || pixel1.a > ALPHA_TOLERANCE;
if (baseColor.a < ALPHA_TOLERANCE && neighbourColor) {
baseColor.rgb = vec3(1.0, 0.0, 0.0);
baseColor.a = 0.7;
}
gl_FragColor = baseColor;
if(gl_FragColor.a < 0.01) discard;
}
This is how my vertex shader looks:
attribute vec2 a_Vertex;
attribute vec2 a_TexCoord;
uniform mat3 u_TextureMatrix;
varying vec2 v_TexCoord;
varying vec2 v_TexCoord2;
uniform mat3 u_TransformMatrix;
uniform mat3 u_ProjectionMatrix;
uniform vec2 u_Offset;
void main()
{
gl_Position = vec4((u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0)).xy, 1.0, 1.0);
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
v_TexCoord2 = (u_TextureMatrix * vec3(a_TexCoord + u_Offset,1.0)).xy;
}
The shader works like this: it checks if the color is transparent, if it is, then it checks if a neighboring pixel has a real "color", if it is then it's replaced with red. But for some reason there are some random red lines outside of my character. There isn't any "real" colors next to those lines, so I don't understand why it's making those pixels red.
Example of a bugged character

Related

Problems with water shader (don't want to refract object above water)

I have created a water shader which has a problem with refraction. It's not only refracting object under water (which it should) - it's also refracting object which is not in water.
Here is the full source of the fragment shader.
varying vec2 v_UV1;
uniform sampler2D u_Scene;
uniform sampler2D u_Depth;
uniform sampler2D u_WaterDUDV;
uniform vec2 u_ViewSize;
uniform float u_Time;
uniform vec3 u_Color;
uniform float u_Transparency;
void main() {
float transparency = u_Transparency;
vec4 waterColor = vec4(u_Color, 1.0);
vec2 uv = v_UV1 + vec2(0.3, 0.1) * u_Time;
vec2 dudv = texture2D(u_WaterDUDV, uv).rg * 2.0 - 1.0;
vec2 finalSceneUV = gl_FragCoord.xy / u_ViewSize;
vec2 sceneUV = gl_FragCoord.xy / u_ViewSize;
vec2 sceneOffsetUV = sceneUV + dudv * 0.007;
float sceneDepth = texture2D(u_Depth, sceneUV).r;
float sceneOffsetDepth = texture2D(u_Depth, sceneOffsetUV).r;
if (sceneDepth < gl_FragCoord.z) {
transparency = 0.0;
} else {
// The cube is viewed though water.
finalSceneUV = sceneOffsetUV;
}
vec4 sceneColor = texture2D(u_Scene, finalSceneUV);
vec4 finalColor = mix(sceneColor, waterColor, transparency);
gl_FragColor = finalColor;
}
Any ideas how this could be fixed?

How can I make a smoother my heightmap? (Perlin noise, openGL)

I generate 2D perlin noise and I'm doing it terrain. But I have a problem with this. It's too gradual.
I tried x,z coordinates are divided or multiplied but doesn't work. How can I solve this problem without tessellation shader?
EDIT:
fragment shader code:
#version 430
in vec3 pos;
in vec2 text;
in vec3 norm;
layout(binding=3) uniform sampler2D texture_1;
layout(binding=4) uniform sampler2D texture_2;
layout(binding=5) uniform sampler2D texture_3;
vec3 lightPosition = vec3(-200, 700, 50);
vec3 lightAmbient = vec3(0,0,0);
vec3 lightDiffuse = vec3(1,1,1);
vec3 lightSpecular = vec3(1,1,1);
out vec4 fragColor;
vec4 theColor;
void main()
{
vec3 lightVector = normalize(lightPosition) - normalize(pos);
float cosTheta = clamp(dot(normalize(lightVector), normalize(norm)), 0.5, 1.0);
if(pos.y <= 120){
fragColor = texture2D(texture_2, text*0.05) * cosTheta;
}
if(pos.y > 120 && pos.y < 150){
fragColor = (texture2D(texture_2, text*0.05) * (1 - (pos.y-120)/30) + texture2D(texture_3, text*0.05) * ((pos.y-120)/30))*cosTheta;
}
if(pos.y >= 150)
{
fragColor = texture2D(texture_3, text*0.05) * cosTheta;
}
}
vertex shader code:
#version 430
in layout(location=0) vec3 position;
in layout(location=1) vec2 textCoord;
in layout(location=2) vec3 normal;
out vec3 pos;
out vec2 text;
out vec3 norm;
uniform mat4 transformation;
void main()
{
gl_Position = transformation * vec4(position, 1.0);
norm = normal;
pos = position;
text = position.xz;
}
It looks like you're using an 8bit heightmap which only gives you 256 different elevations. You could try using 16bit greyscale or encode the height in rgb.

Same shaders behaving differently on Nvidia and ATI cards

Me and a friend are developing an editor (CAD-like) to use in our future game.
We are using the Qt framework and OpenGL.
The problem we are encountering is that on his laptop with an integrated nVidia card, the shading is working as expected and renders well. On my laptop with an integrated ATI card, as well as on my desktop with Radeon HD5850, the phong lighting is behaving slightly differently. There are more bright spots and dark spots and the image doesn't look good. Also, we are using a toon shader to draw a silhouette around the edges and to limit the amount of shades a color can have.
The toon shader uses 2-pass rendering - first pass renders the object in black, slightly larger than original (shifting each vertex in its normals direction slightly) to make the silhouette and then the second pass renders the object normally (only limiting the shade spectrum, so it looks more comic-like).
The images are of the same thing on our 2 computers. The first difference I mentioned above, the second is that the silhouette is stretched out as it should be on my friends computer, so it makes an even silhouette around the object, but is moved slightly up on my computer, making a thick line on the top and no line on the bottom.
The other thing is the phong lighting, illuminating the cube within which the object is edited. Again, rendering well on my friends computer, but being almost all-black or all-white on mine.
First image (nVidia card):
Second image (ATI cards):
I understand that the code is long and maybe the problem lays in some Qt settings, not in the shaders, but if you see anything that strikes you as bad practice, please answer.
Code for the phong shading follows
#version 400
in vec4 aVertex;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uPVM;
uniform mat4 uViewModel;
uniform mat4 uNormal;
uniform int uLightsOn;
out vec2 vTexCoord;
out vec3 vNormal;
flat out vec3 mEye;
flat out vec3 mLightDirection;
flat out vec4 mAxisColor;
void main(void)
{
if(uLightsOn == 1) {
mEye = (uViewModel * aVertex).xyz;
mLightDirection = vec4(2.0,-2.0,1.0,0.0).xyz;
vNormal = (uNormal * aNormal).xyz;
}
gl_Position = uPVM * aVertex;
vTexCoord = aTexCoord;
mAxisColor = aNormal;
}
The phong fragment shader :
#version 400
uniform sampler2D uTexture0;
uniform int uLightsOn;
uniform vec3 uHighlightColor;
uniform int uTextured;
uniform int uAxisRender;
in vec2 vTexCoord;
in vec3 vNormal;
flat in vec3 mEye;
flat in vec3 mLightDirection;
out vec4 fragColor;
flat in vec4 mAxisColor;
struct TMaterial {
vec4 diffuse;
vec4 ambient;
vec4 specular;
float shininess;
};
TMaterial material;
void setup() {
// setupMaterials
material.ambient = vec4(0.4);
material.diffuse = vec4(0.9);
material.specular = vec4(0.0);
material.shininess = 0.3;
}
void main(void)
{
setup();
vec3 finalHighlightColor = uHighlightColor;
if(finalHighlightColor.x <= 0.0) finalHighlightColor.x = 0.1;
if(finalHighlightColor.y <= 0.0) finalHighlightColor.y = 0.1;
if(finalHighlightColor.z <= 0.0) finalHighlightColor.z = 0.1;
if(uLightsOn == 0) {
if(uAxisRender == 1) fragColor = mAxisColor;
else fragColor = vec4(finalHighlightColor,1.0);
return;
}
vec4 diffuse;
vec4 spec = vec4(0.0);
vec4 ambient;
vec3 L = normalize(mLightDirection - mEye);
vec3 E = normalize(-mEye);
vec3 R = normalize(reflect(-L,vNormal));
ambient = material.ambient;
float intens = max(dot(vNormal,L), 0.0);
diffuse = clamp( material.diffuse * intens , 0.0, 1.0 );
if(intens > 0.0) spec = clamp ( material.specular * pow(max(dot(R,E),0.0),material.shininess) , 0.0, 1.0 );
if(uTextured == 1) fragColor = (ambient + diffuse + spec) * texture(uTexture0,vTexCoord);
else fragColor = (ambient + diffuse + spec) * vec4(finalHighlightColor,1.0);
}
And the toon shaders :
#version 400
in vec4 aVertex;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uPV;
uniform mat4 uM;
uniform mat4 uN;
uniform vec3 uLightPosition;
uniform vec3 uCameraPosition;
uniform int uSilhouetteMode;
uniform float uOffset;
// if this uniform is passed, all the toon rendering is going off and only simple axis are rendered
// last data in aNormal are colors of those axis if everything was ser properly.
uniform int uAxisRendering;
flat out vec4 fAxisColor;
out vec4 vNormal;
out vec2 vTexCoord;
out vec3 vDirectionToCamera;
out vec3 vDirectionToLight;
void silhouetteMode() {
gl_Position = uPV * uM * vec4(aVertex.xyz + aNormal.xyz * uOffset,1.0f);
}
void toonMode() {
vec4 worldPosition = uM * aVertex;
vDirectionToCamera = uCameraPosition - worldPosition.xyz;
vDirectionToLight = uLightPosition - worldPosition.xyz;
vNormal = uN * aNormal;
gl_Position = uPV * worldPosition;
}
void axisMode() {
fAxisColor = aNormal;
gl_Position = uPV * uM * aVertex;
}
void main(void)
{
vTexCoord = aTexCoord;
if(uSilhouetteMode == 1) {
silhouetteMode();
} else {
if(uAxisRendering == 1) axisMode();
else toonMode();
}
}
and the fragment shader
#version 400
uniform sampler2D uTexture;
uniform vec3 uBaseColor;
uniform float uNumShades;
uniform int uSilhouetteMode;
uniform int uAxisRendering;
flat in vec4 fAxisColor;
in vec4 vNormal;
in vec2 vTexCoord;
in vec3 vDirectionToCamera;
in vec3 vDirectionToLight;
out vec4 outFragColor;
void main(void)
{
if(uSilhouetteMode == 1) {
outFragColor = vec4(uBaseColor,1.0);
return;
}
if(uAxisRendering == 1) {
outFragColor = fAxisColor;
return;
}
float l_ambient = 0.1;
float l_diffuse = clamp(dot(vDirectionToLight,vNormal.xyz),0.0,1.0);
float l_specular;
vec3 halfVector = normalize(vDirectionToCamera + vDirectionToLight);
if(dot(vDirectionToLight,vNormal.xyz) > 0.0) {
l_specular = pow(clamp(dot(halfVector,vNormal.xyz),0.0,1.0),64.0);
} else {
l_specular = 0.0;
}
float intensity = l_ambient + l_diffuse + l_specular;
float shadeIntesity = ceil(intensity * uNumShades)/ uNumShades;
outFragColor = vec4(texture(uTexture,vTexCoord).xyz * shadeIntesity * uBaseColor,1.0);
}
And finally, our OpenGLWindow initialization (in Qt)
OpenGLWindow::OpenGLWindow(QWindow *parent) :
QWindow(parent),m_animating(false), m_initialized(false), m_animationTimer(NULL)
{
setSurfaceType(QWindow::OpenGLSurface);
QSurfaceFormat format;
format.setDepthBufferSize( 24 );
format.setMajorVersion( 4 );
format.setMinorVersion( 0 );
format.setSamples( 4 );
format.setProfile( QSurfaceFormat::CoreProfile );
setFormat( format );
create();
if(!m_context) {
m_context = new QOpenGLContext(this);
m_context->setFormat(requestedFormat());
m_context->create();
m_context->makeCurrent(this);
initializeOpenGLFunctions();
}
m_animationTimer = new QTimer(this);
connect(m_animationTimer, SIGNAL(timeout()), this, SLOT(renderer()));
m_animationTimer->setInterval(16);
}
To my eyes the nVidia image seems to be using alpha whereas the AMD one is not. I also can't see a
format.setAlpha(true);
in your Qt setup so may be that.

Issue with lighting, possibly normal related?

I'm using OpenGL 3.3 and having some odd lighting issue, I'll first show two screenshots at different angles and then give the shader code.
First angle:
Second angle:
What you see here is:
A cube, with its middle on the origin;
A directional light source, coming from the yellow point through the origin;
In cyan you see the normals of the vertices.
I know the normals of the vertices are "wrong", but I was exactly trying to debug those.
What I expected was: A (from top-to-bottom) varying color of every face, depending on the position of the "sun" and the camera.
But what I get is that two parts of the cube (upper and lower) that both have varying colors, but not in the way I expected.
There is code for shadows in the shader, but I deliberately disabled them here to avoid confusion.
Vertex shader:
#version 430 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 normal;
layout(location = 0) uniform mat4 model_matrix;
layout(location = 1) uniform mat4 view_matrix;
layout(location = 2) uniform mat4 proj_matrix;
layout(location = 3) uniform mat4 shadow_matrix;
out VS_OUT {
vec3 N;
vec3 L;
vec3 V;
vec4 shadow_coord;
} vs_out;
uniform vec4 light_pos = vec4(-20.0, 7.5, -20.0, 1.0);
void main(void) {
vec4 local_light_pos = view_matrix * light_pos;
vec4 p = view_matrix * model_matrix * position;
//normal
vs_out.N = normalize(normal);
//light vector
vs_out.L = local_light_pos.xyz - p.xyz;
//view vector
vs_out.V = -p.xyz;
//light space coordinates
vs_out.shadow_coord = shadow_matrix * position;
gl_Position = proj_matrix * p;
}
Fragment shader:
#version 430 core
out vec4 color;
in VS_OUT {
vec3 N;
vec3 L;
vec3 V;
vec4 shadow_coord;
} fs_in;
layout(binding = 0) uniform sampler2DShadow shadow_tex;
uniform vec3 light_ambient_albedo = vec3(1.0);
uniform vec3 light_diffuse_albedo = vec3(1.0);
uniform vec3 light_specular_albedo = vec3(1.0);
uniform vec3 ambient_albedo = vec3(0.0, 0.2, 0.0);
uniform vec3 diffuse_albedo = vec3(0.2, 0.7, 0.2);
uniform vec3 specular_albedo = vec3(0.0, 0.0, 0.0);
uniform float specular_power = 128.0;
vec3 rgb_to_grayscale_luminosity(vec3 color) {
float value = color.r * 0.21 + color.g * 0.71 + color.b * 0.07;
return vec3(value);
}
void main(void) {
//normalize
vec3 N = normalize(fs_in.N);
vec3 L = normalize(fs_in.L);
vec3 V = normalize(fs_in.V);
//calculate R
vec3 R = reflect(-L, N);
//calcualte ambient
vec3 ambient = ambient_albedo * light_ambient_albedo;
//calculate diffuse
vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo * light_diffuse_albedo;
//calcualte spcular
vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo * light_specular_albedo;
//apply shadow and write color
float shadow_value = textureProj(shadow_tex, fs_in.shadow_coord);
if (shadow_value > 0.0001 || true) {
//no shadow
color = vec4(ambient + diffuse + specular, 1.0);
}
else {
//in shadow
//color = vec4(rgb_to_grayscale_luminosity((ambient + diffuse) * (1 - shadow_value)), 0.5);
//color = vec4(vec3(shadow_value), 0.5);
color = vec4((ambient + diffuse) * (1 - shadow_value) * 0.5, 1.0);
}
}
What could be going wrong here?
Assuming your normals only point upwards/downwards (x=0 and z=0 in the OpenGL coordinate system) what you see should be the expected behavior (no bug concerning the shaders/graphics pipeline).
During the rasterization stage in the graphics pipeline the attributes are interpolated among the vertices (barycentric coordinates).
Assuming that all normals above the plane "y=0" are
"vec3(0, 1, 0)"
and all normals below this plane are
"vec3(0, -1, 0)"
then for every pixel the interpolated normal will be
"vec3(0, *, 0)" where * is >0 above the "y=0"-plane and <0 below that plane.
In your fragment shader you normalize all normals hence they will all again be
"vec3(0, 1, 0)" if the corresponding vertex lies above the "y=0"-plane and
"vec3(0, -1, 0)" if the corresponding vertex lies below that plane.
This will result in the same color for all vertices below and above the "y=0"-plane.
You could check this if you would remove the normal-"normalization" within the fragment shader or if you add a minimal offset to the x- or z-coordinate of some normals e.g.
vec3(0.0000001, +/-1, 0)

GLSL Parallax mapping issue

I wrote parallax mapping shader in GLSL but it is working wrong. In some places it shows correct image with good bump but in other positions it becomes flat. It's became most flat when I moving camera father than platform(forward)
#version 120
varying vec3 pos;
varying vec3 normal;
varying vec2 tc;
varying vec3 color;
uniform vec3 camera;
void main(void)
{
pos = (-gl_Vertex.xyz + camera);
tc = gl_MultiTexCoord0.xy;
normal = normalize(gl_Normal);
color = gl_Color.xyz;
gl_Position = ftransform();
}
#version 120
uniform sampler2D normal_map;
uniform sampler2D diffuse_map;
uniform sampler2D displacement;
uniform float mode;
varying vec2 tc;
varying vec3 pos;
void main(void)
{
vec3 lightPos = vec3( 0.0, -45.0, -40.0);
vec4 color;
if (mode > 1)
{
vec3 eyeVec = normalize(pos);
vec2 eyeProj = normalize(eyeVec.xz);
float curHeight = texture2D(displacement, tc).r - 0.5;
vec2 trTc = tc - (eyeProj) * curHeight * 0.035;
vec3 normal = normalize(texture2D(normal_map, trTc).xzy*2.0 - 1.0);
color = texture2D(diffuse_map, trTc) * dot( normalize(pos - lightPos), normal) * 1.0;
color.w = 1.0;
}
else
{
vec3 normal = normalize(texture2D(normal_map, tc).xzy*2.0 - 1.0);
color = texture2D(diffuse_map, tc) * dot( normalize(pos - lightPos), normal) * 1.0;
}
gl_FragColor = color;
}
I can't even imagine where can be mistake. I was experimenting with camera and vertex values but it is not help;