I am learning lighting on OpenGL, in this example, I used the phong method. Everything seems to be working as intended, but I notice that this method leaves some "stripes", especially in the diffuse part of the resulting color:
Vertex shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 normal;
struct Light{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;
uniform Light light;
out vec3 aNormal;
out vec3 FragPos;
out vec3 LightPos;
//Usually you would transform the input into coordinates that fall within OpenGL's visible region
void main()
{
aNormal = mat3(transpose(inverse(View * Model))) * normal;
FragPos = vec3(View * Model * vec4(aPos,1.0));
gl_Position = Projection * vec4(FragPos,1.0);
LightPos = vec3(View * vec4(light.position,1.0));
}
#version 330 core
out vec4 FragColor;
in vec3 aNormal;
in vec3 FragPos;
in vec3 LightPos;
struct Material{
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
struct Light{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
precision highp float;
void main()
{
vec3 ambient = material.ambient * light.ambient;
vec3 norm = normalize(aNormal);
//Difuse
vec3 lightDir = normalize(LightPos - FragPos);
float diff = max(dot(norm,lightDir),0.0);
vec3 diffuse = (diff * material.diffuse) * light.diffuse;
vec3 specular = vec3(0);
//Specular
if(diff > 0){
vec3 viewDir = normalize(-FragPos);
vec3 reflectDir = reflect(-lightDir,norm);
float spec = pow(max(dot(viewDir,reflectDir),0.0), material.shininess);
specular = light.specular * (spec * material.specular);
}
vec3 result = diffuse + (ambient + specular);
FragColor = vec4(result, 1.0);
}
Fragment shader:
I was wondering why that happens, I have a suspicion that is related to float precision, however I tried to use precision highp float; and it had no effect. What is causing this? Is there a way to fix it?
Related
I am trying to create a translucent , stained glass effect in OpenGL, using C++.
I use a normal map generated from a perlin noise texture. Refraction is calculated with respect to manipulated normal vectors and it works.
For stained glass, I am trying mixing the colour from skybox through refraction, with another colour. I tried this with a constant value, and that works too.
When I try to get the second colour from a texture, I do not see the object on screen. I can load the texture if i ignore refraction and mixing though.
here is my vertex shader :
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
layout (location = 3) in vec3 aTangent;
layout (location = 4) in vec3 aBitangent;
out vec3 FragPos;
out vec2 texCoord;
out vec3 tangentLightPos;
out vec3 tangentViewPos;
out vec3 tangentFragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
//normal
uniform vec3 lightPos;
uniform vec3 viewPos;
void main()
{
texCoord = aTexCoord;
FragPos = vec3(view * model * vec4(aPos, 1.0));
mat3 normalMatrix = transpose(inverse(mat3(model)));
vec3 T = normalize(normalMatrix * aTangent);
vec3 N = normalize(normalMatrix * aNormal);
T = normalize(T - dot(T, N) * N);
vec3 B = cross(N, T);
mat3 TBN = transpose(mat3(T, B, N));
tangentLightPos = TBN * lightPos;
tangentViewPos = TBN * viewPos;
tangentFragPos = TBN * FragPos;
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
and my fragment shader :
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec2 texCoord;
in vec3 tangentLightPos;
in vec3 tangentViewPos;
in vec3 tangentFragPos;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform samplerCube skybox;
uniform vec3 cameraPos;
void main()
{
//normal map - normal
vec3 normalDir = texture(texture2, texCoord).rgb;
normalDir = normalize(normalDir * 2.0 - 1.0);
vec3 Incident = normalize(tangentFragPos - cameraPos);
vec3 RefractedDir = refract(Incident, normalDir, 1.0/1.2);
float DispersionIndex = 1.0 - dot(Incident, normalDir);
vec3 RefractedFragColor = vec3(texture(skybox, RefractedDir).rgb);
//FIXME:
vec3 texColor = texture(texture1, texCoord).rgb;
vec3 constTexColor = vec3(1.0, 1.0, 1.0);
FragColor = mix( vec4(RefractedFragColor, 1.0), vec4(texColor.rgb, 0.5), 0.2); // doesnt show object on screen
// FragColor = mix( vec4(RefractedFragColor, 1.0), vec4(constTexColor.rgb, 0.5), 0.2); --> works , shows a tint on glass
// FragColor = vec4(texColor, 1.0); ---> shows only texture
}
with constant value for color in mix :
with only texture:
Why does the mix not work with color from texture?
I am working on a shader where the fragment shader should work in the tangent space. It works just as expected for both the ambient and diffuse light, but the specular light is just plain weird. It seems that nearby fragments can have a lot or no light with no obvious reasons.
The vertex shader is:
#version 330 core
layout (location = 0) in vec3 inVertex;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inTexture;
layout (location = 3) in vec3 inTangent;
layout (location = 4) in vec3 inBitangent;
out vec3 FragmentPosition;
out vec2 TextureCoordinate;
out vec3 TangentLightDirection;
out vec3 TangentViewPosition;
out vec3 TangentFragmentPosition;
void main()
{
FragmentPosition = vec3(inVertex);
vec3 normal = normalize(inNormal);
gl_Position = vec4( inVertex, 1 );
TextureCoordinate = inTexture;
vec3 tangent = normalize(inTangent);
vec3 biTangent = normalize(inBitangent);
mat3 toTangentSpaceTransformation = transpose(mat3(tangent,biTangent,normal));
TangentFragmentPosition = toTangentSpaceTransformation * FragmentPosition;
TangentLightPosition = toTangentSpaceTransformation * vec3(0,1,1);
TangentFragmentPosition = toTangentSpaceTransformation * vec3(0,0,3);
}
And the fragment shader is:
#version 330 core
out vec4 FragColor;
in vec3 FragmentPosition;
in vec2 TextureCoordinate;
in vec3 TangentLightDirection;
in vec3 TangentViewPosition;
in vec3 TangentFragmentPosition;
uniform sampler2D Texture;
uniform sampler2D normalTexture;
void main() {
vec3 normal = vec3(0,0,1);
float shininess = 4;
vec3 phongVector = vec3(0.3,0.7,1);
vec4 color = texture(Texture,TextureCoordinate);
vec4 ambientLightColor = vec4(1,1,1,1);//vec4(normalOffset,1);
// Calculation of ambient light
vec4 sunLightColor = vec4(1,1,1,1);
vec3 sunLightDirection = normalize(TangentLightPosition);
vec4 ambientLight = phongVector[0] * ambientLightColor;
// Calculation of diffuse light
float diffuseConst = max(dot(normal,sunLightDirection),0.0);
vec4 diffuseLight = phongVector[1] * diffuseConst * sunLightColor;
// Calculation of specular light
vec3 viewDirection = normalize(TangentViewPosition - TangentFragmentPosition);
vec3 reflectionDirection = reflect(-sunLightDirection,normal);
float spec = pow(max(dot(reflectionDirection,viewDirection),0),shininess);
vec4 specularLight = phongVector[2] * spec * sunLightColor;
FragColor = (specularLight)*color;
}
It was a typo. tangentFragmentPosition was initialized twice, while tangentViewPosition was not initialized at all. Initizalizing tangentViewPosition gave the desired result.
platform: Windows10
context: OpenGL, glew, Win32
So I loaded 2 meshes(using a simple OBJ parser, which only reads the triangulated mesh), with vertexpos,uv and normal data. The first mesh is lighted okay. No black faces.The second one looks like this.
The Strange Effects
my vertex shader:
#version 440
in vec3 pos;
in vec2 tex;
in vec3 nor;
uniform float Scale;
uniform mat4 perspective;
uniform mat4 model;
out vec3 normaldir;
out vec2 texOut;
out vec3 FragPos;
void main()
{
normaldir = normalize(mat3(transpose(inverse(model))) * nor);
gl_Position = perspective * model * vec4(pos.xyz, 1.0);
texOut = tex;
FragPos = vec3(model * vec4(pos, 1.0));
}
my fragment shader:
#version 440
uniform float Scale;
uniform sampler2D diffuse;
uniform sampler2D normal;
uniform vec3 viewPos;
//uniform sampler2D normalMap0;
in vec3 normaldir;
in vec2 texOut;
in vec3 FragPos;
layout(location = 0) out vec4 FragColor0;
void main()
{
vec3 lightPos = {2,6,0};
lightPos.x = sin(Scale)*5;
lightPos.z = cos(Scale)*5;
vec3 lightDir = normalize(lightPos - FragPos);
vec3 lightColor = {1.0,1.0,1.0};
float specularStrength = 1.6;
float diff = max(dot(normaldir, lightDir), 0.0);
vec3 diffuseD = diff * lightColor;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, normaldir);
vec3 ambient = {0.0,0.2,0.4};
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 25);
vec3 specular = specularStrength * spec * lightColor;
vec3 diffuseCol = texture(diffuse, texOut).xyz;
vec3 result = (ambient + diffuseD+ specular) * diffuseCol;
FragColor0 = vec4(result, 1.0);
}
Sorry I made a very dumb mistake. Thank you for all your support #Rabbid76 (Yes I did inverted the normals yes) #paddy
The problem was Binding the normal buffers. I bind glm::vec2 * size instead of glm::vec3 * size for normals' buffers
first of all my Code of my Fragmenshader.
#version 330 core
struct Material{
sampler2D diffuse;
};
struct Light{
vec3 position;
vec3 ambient;
vec3 diffuse;
};
in vec3 Normal;
in vec3 FragPos;
in vec3 TexCoords;
out vec4 color;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
//ambient
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
//Diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm,lightDir),0.0);
vec3 diffuse = light.diffuse * diff *vec3(texture(material.diffuse,TexCoords));
color = vec4(ambient+diffuse,1.0f);
}
If i want to compile i get the error:
'texture': not mathcing overloaded function found (using implicit conversion)
I looked at the GLSL documentation, but i looks correct. After that i searched for an error in my OpenGL file... but i looks ok.
You are trying to read from a 2D sampler using 3D coordinates. Either change the in vec3 TexCoords to in vec2 TexCoords or change the texture lookup from texture(material.diffuse, TexCoords) to texture(material.diffuse, TexCoords.xy)
the title says it all.. using opengls built in lighting system, specularlight does not increase or decrease with distance from the object, but by shader implementation does.
Vertex Shader:
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;
out vec2 texCoord0;
out vec3 normal0;
out vec3 worldPos0;
uniform mat4 transform;
uniform mat4 normalRotation;
uniform mat4 transformProjected;
void main()
{
gl_Position = transformProjected * vec4(position, 1.0);
texCoord0 = texCoord;
normal0 = normalize((normalRotation * vec4(normal, 0.0))).xyz;
worldPos0 = (transform * vec4(position, 1.0)).xyz;
}
Fragment Shader:
#version 330
in vec2 texCoord0;
in vec3 normal0;
in vec3 worldPos0;
out vec4 fragColor;
struct BaseLight
{
vec3 colorDiffuse;
vec3 colorSpecular;
float intensityDiffuse;
};
struct DirectionalLight
{
BaseLight base;
vec3 direction;
};
uniform vec3 tint;
uniform sampler2D sampler;
uniform vec3 eyePos; // camera pos
uniform vec3 ambientLight;
uniform vec3 emissiveLight;
//material
uniform float specularIntensity;
uniform float specularPower;
uniform DirectionalLight directionalLight;
vec4 calcLight(BaseLight base,vec3 direction, vec3 normal)
{
float diffuseFactor = dot(normal, -direction);
vec4 diffuseColorFinal = vec4(0,0,0,0);
vec4 specularColorFinal = vec4(0,0,0,0);
if(diffuseFactor > 0)
{
diffuseColorFinal = vec4(base.colorDiffuse,1) * diffuseFactor * base.intensityDiffuse;
vec3 directionToEye = normalize(eyePos - worldPos0);
vec3 reflectDirection = normalize(reflect(direction, normal));
float specularFactor = dot(directionToEye, reflectDirection);
specularFactor = pow(specularFactor, specularPower);
if(specularFactor > 0)
specularColorFinal = vec4(base.colorSpecular,1) * specularFactor * specularIntensity;
}
//
return diffuseColorFinal + specularColorFinal;
}
void main()
{
vec4 colorD = texture(sampler, texCoord0.xy) * vec4(tint,1);
vec3 normal = normal0;
vec4 totalLight = vec4(ambientLight,1) + vec4(emissiveLight,1);
totalLight += calcLight(directionalLight.base,-directionalLight.direction,normal);
fragColor = colorD * totalLight;
}
As you can see from the 2 images the specular light takes up a larger surface area the farther the camera gets from the plane.In my test with opengls built in lighting, this doesnt happen. is there a way to fix this? im new to lighting, maybe this is normal for directional light sources? thanks for the help!
Im also setting my eyePos uniform to my cameraPos. i dont know if that helps.
Basically you need to have distance between the fragment and the light dist . This can be a problem for directional light though because you have only the direction and distant is assumed to be infinite. Maybe switch to point light?
when youo have the 'dist' you use a formula
att = 1.0 / (Kc + Kl*dist + Kq*dist^2)
Kc - constant attenuation
Kl - linear attenuation
Kq - quadratic attenuation
simpler version (only Kq used, rest set to 1.0):
float attenuation = 1.0 / (1.0 + light.attenuation * pow(distanceToLight, 2));
then in the lighting equation you basically multiply calculated color by this att factor:
vec4 finalColor = ambient + (diffuseColorFinal + specularColorFinal)*att
http://www.ozone3d.net/tutorials/glsl_lighting_phong_p4.php#part_4
http://tomdalling.com/blog/modern-opengl/07-more-lighting-ambient-specular-attenuation-gamma/