GLSL correct specular light - opengl

I am trying to use specular highlights in GLSL shaders, but I can't quite get it to work correctly. I am using Haskell, but it should not matter.
I am using OpenGL's matrices instead of uniforms.
Here is how I am "transforming" the player.
glLoadIdentity
glPushAttrib gl_TRANSFORM_BIT
-- Rotate Player
let (xr, yr, zr) = playerRotation player
glRotatef xr (-1) 0 0
glRotatef yr 0 (-1) 0
glRotatef zr 0 0 (-1)
-- Translate Player
let (x, y, z) = playerPosition player
glTranslatef (-x) (-y) (-z)
-- Reset attributes to former state?
glPopAttrib
After that section of code, I render all the actual renderable objects. So from GLSL's perspective, the camera is at (0, 0, 0), and everything else is transformed inversely to the player's position. Pretty standard.
So the following shaders don't work, they basically make it look like the light follows the player everywhere:
Vertex:
#version 400 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoord;
layout(location = 3) in vec3 color;
layout(location = 4) in float textureId;
out vec3 fragColor;
out vec3 vertex;
out vec2 textureCoord;
out vec3 norm;
out int texId;
void main()
{
vertex = position;
textureCoord = texCoord;
norm = normal;
fragColor = color;
// Excuse this
texId = int(textureId);
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
}
Fragment:
#version 400
in vec3 fragColor;
in vec3 vertex;
in vec3 norm;
in vec2 textureCoord;
in int texId;
out vec4 outColor;
// Not used
layout(location = 6) uniform vec3 cameraPosition;
layout(location = 7) uniform sampler2D[7] textures;
vec3 lightPos = vec3(3, 1, 0);
void main()
{
//Position of vertex in modelview space
vec3 vertexPosition = (gl_ModelViewMatrix * vec4(vertex, 1.0)).xyz;
//Surface normal of current vertex
vec3 surfaceNormal = normalize((gl_NormalMatrix * norm).xyz);
//Direction light has traveled to get to vertexPosition
vec3 lightDirection = normalize(lightPos - vertexPosition);
//Basically how much light is hitting the vertex
float diffuseLightIntensity = max(0.0, dot(surfaceNormal, lightDirection));
//"Main color"(diffuse) of vertex
vec3 diffColor = diffuseLightIntensity * fragColor;
//Adjust color depending upon distance from light
diffColor /= max(distance(lightPos, vertexPosition)/10, 1);
//Lowest light level possible
vec3 ambColor = vec3(0.01, 0.01, 0.01);
//"View vector"
vec3 viewVec = normalize(-vertexPosition);
//Direction light is reflected off of surface normal
vec3 reflectionDirection = normalize(reflect(-lightDirection, surfaceNormal));
//The intensity of reflection (specular)
float specular = max(0.0, dot(reflectionDirection, viewVec));
float shininess = 2.0;
float totalSpec = pow(specular, shininess);
totalSpec /= max(distance(gl_LightSource[0].position.xyz, vertexPosition)/4, 1);
vec3 specColor = vec3(totalSpec, totalSpec, totalSpec);
// Excuse this
if(texId != -1)
{
vec4 textureColor = texture(textures[texId], textureCoord);
outColor = vec4(ambColor, 1.0) + textureColor + vec4(specColor, 1.0);
}
else
{
outColor = vec4(ambColor, 1.0) + vec4(diffColor + specColor, 1.0);
}
}
I am simply passing the position of the player to cameraPosition using glUniform.
How can I make the specular highlights work with my given variables?

Looks to me as is the light direction us always the same, regardless of the camera position. Try to define the light position in the vertex shader, transform it using the model view matrix and pass it to the fragment shader.

Related

Trying to implement shadow using OpenGL; depth texture seems correct but shadow is not displaying

trying to implement shadow. I checked my depth texture on a quad, and it seems correct, but the shadow is not displaying. I check my shadow vertex and fragment shaders, and I believe I have done the light space transformation correctly.
Here are my code.
directional light source matrix setup:
//light source states
glm::vec3 Window::lightColor = glm::vec3(0.9f, 0.9f, 0.9f);
glm::vec3 Window::lightDir = glm::vec3(-1.f, -1.f, 0.f);
glm::mat4 Window::lightView = glm::lookAt(glm::vec3(0.f) - glm::normalize(lightDir) * 15.f, glm::vec3(0.0f), glm::vec3(0.f, 1.f, 0.f));
float Window::near_plane = 0.01f;
float Window::far_plane = 50.1f;
float camWidth = 10.f;
glm::mat4 Window::lightProj = glm::ortho(-10.f, 10.f, -10.f, 10.f, Window::near_plane, Window::far_plane);
glm::mat4 Window::lightProjView = lightProj * lightView;
shadow drawing logic:
void Renderer::drawWithShadow(Object* obj) {
//set shader uniforms
Shader* shader = shadowShader;
shader->bind();
shader->setUniformMat4("model", obj->model);
shader->setUniformMat4("projView", projView);
shader->setUniformVec3("viewPos", eyePos);
//need another projection matrix
shader->setUniformMat4("lightSpaceMatrix", shadowProjView);
glcheck(glActiveTexture(GL_TEXTURE0));
glcheck(glBindTexture(GL_TEXTURE_2D, textID));
//light uniforms
shader->setUniformVec3("directionalLightDir", directionalLightDir);
shader->setUniformVec3("lightColor", lightColor);
glcheck(glBindVertexArray(obj->vao));
for (auto i = 0; i < obj->meshList.size(); i++) {
Mesh* mesh = obj->meshList[i];
prepMaterial(mesh->material, shader);
glcheck(glDrawElements(GL_TRIANGLES, mesh->size, GL_UNSIGNED_INT, (GLvoid*)(sizeof(GLuint) * mesh->vertexOffset)));
}
}
vert and frag shaders to prepare shadow depth textures
//vertex shader
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 projView;
uniform mat4 model;
void main() {
gl_Position = projView * model * vec4(position, 1.0);
}
//fragment shader
#version 330 core
void main()
{
}
vert and frag shaders to draw shadows with Phong lighting
//vertex shader
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoord;
out VS_OUT {
vec4 fragPos;
vec3 normal;
vec2 texCoord;
vec4 fragPosLightSpace;
} vs_out;
uniform mat4 projView;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;
void main()
{
vs_out.fragPos = model * vec4(position, 1.0);
vs_out.normal = transpose(inverse(mat3(model))) * normal;
vs_out.texCoord = texCoord;
vs_out.fragPosLightSpace = lightSpaceMatrix * vs_out.fragPos;
gl_Position = projView * vs_out.fragPos;
}
//fragment shader
#version 330 core
uniform vec3 viewPos; //just the eye pos
uniform vec3 diffuseFactor; //kd
uniform vec3 ambientColor; //ka
uniform vec3 specColor; //ks
uniform float specHighlight; //ns, the larger this value is, the more apparent the light dot on the surface
uniform float dissolve; //d
//lights
uniform vec3 directionalLightDir;
uniform vec3 pointLightPos;
uniform vec3 lightColor;
uniform sampler2D shadowMap;
//uniform sampler2DShadow shadowMap;
in VS_OUT {
vec4 fragPos;
vec3 normal;
vec2 texCoord;
vec4 fragPosLightSpace;
} fs_in;
out vec4 fragColor;
float ShadowCalculation(vec4 fragPosLightSpace)
{
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
vec2 shadowCoords;
shadowCoords.x = projCoords.x * 0.5 + 0.5;
shadowCoords.y = projCoords.y * 0.5 + 0.5;
float closestDepth = texture(shadowMap, shadowCoords).r;
float currentDepth = projCoords.z * 0.5 + 0.5;
float shadowValue = currentDepth + 0.00001 > closestDepth ? 1.0 : 0.0;
//if(currentDepth < 0.0)
//shadowValue = 0.0;
return shadowValue;
}
void main()
{
vec3 lightDir = normalize(-directionalLightDir);
vec3 norm = normalize(fs_in.normal);
//diffuse lighting
float diffStrength = max(dot(norm, lightDir), 0.0); // this calculates diffuse intensity based on angle
vec3 diffuse = lightColor * diffStrength * diffuseFactor;
//specular
vec3 viewDir = normalize(viewPos - fs_in.fragPos.xyz);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = 0.0;
if(specHighlight > 0.0) { // if specHighlight is < 0, pow might produce undefined result if base is also 0
spec = pow(max(dot(viewDir, reflectDir), 0.0), specHighlight);
}
vec3 specular = spec * specColor * lightColor;
float shadow = ShadowCalculation(fs_in.fragPosLightSpace);
//float shadow = textureProj(shadowMap, fs_in.fragPosLightSpace);
//vec3 result = ambientColor * 0.05 * lightColor + (diffuse + specular)*(1-shadow);
vec3 result = (diffuse + specular)*(1.0 - shadow);
fragColor = vec4(result, 1);
}
with just Phong shading, the scene looks like this:
Phong shading
when the scene is seen from the light source as depth value:
depth texture on quad
when I finally render the scene, it is mostly black; I made sure the far plane covers all of the bunnies:
render shadow

OpenGL - How could I color objects in pixelated fashion through shaders?

I'm trying to figure out a way to light up my object in a pixelated fashion through the use of shaders.
To ilustrate, my goal is to turn this:
Into this:
I've tried looking up ways to do this through the fragment shader, however, there is no way I can access the local position of a fragment to determine the "fake pixel" it would belong to. I also had the idea to use a geometry shader to create a vertex for each of those boxes, but I'm under suspicion there could be a better way to do this. Would it be possible?
EDIT: These are the shaders currently being used for the object illustrated by the first image:
vertex shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTex;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 oColor; //Output of a color
out vec2 oTex; //Output of a Texture
out vec3 oPos; //Output of Position in space for light calculation
out vec3 oNormal; //Output of Normal vector for light calculation.
void main(){
gl_Position = projection * view * model * vec4(aPos, 1.0);
oColor = aColor;
oTex = aTex;
oPos = vec3(model * vec4(aPos, 1.0));
oNormal = vec3(0, 0, -1); //Not being calculated at the moment.
}
fragment shader:
#version 330 core
in vec3 oColor;
in vec2 oTex;
in vec3 oPos;
in vec3 oNormal;
out vec4 FragColor;
uniform sampler2D tex;
uniform vec3 lightColor; //Color of the light on the scene, there's only one
uniform vec3 lightPos; //Position of the light on the scene
void main(){
//Ambient Light Calculation
float ambientStrength = 0.1;
//vec3 ambient = ambientStrength * lightColor * vec3(texture(tex, oTex));
vec3 ambient = ambientStrength * lightColor;
//Diffuse Light Calculation
float diffuseStrength = 1.0;
vec3 norm = normalize(oNormal);
vec3 lightDir = normalize(lightPos - oPos);
float diff = max(dot(norm, lightDir), 0.0);
//vec3 diffuse = diff * lightColor* vec3(texture(tex, oTex)) * diffuseStrength;
vec3 diffuse = diff * lightColor;
//Specular Light Calculation
float specularStrength = 0.25;
float shinnyness = 8;
vec3 viewPos = vec3(0, 0, -10);
vec3 viewDir = normalize(viewPos - oPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), shinnyness);
vec3 specular = specularStrength * spec * lightColor;
//Result Light
vec3 result = (ambient+diffuse+specular) * oColor;
FragColor = vec4(result, 1.0f);
}
The lighting depends on oPos. You need to "cascade" the position. e.g:
vec3 pos = vec3(round(oPos.xy * 10.0) / 10.0, oPos.z);
In the following use pos instead of oPos.
Note that this only works if oPos is a position in the view space, respectively if the XY plane of the oPos` coordinate system is parallel to the XY plane of the view.
Alternatively you can compute the a position depending on gl_FragCoord.
Add a uniform variable with the resolution of the screen:
uniform vec2 resolution;
Compute pos depending on resolution and gl_FragCoord:
vec3 pos = vec3(round(20.0 * gl_FragCoord.xy/resolution.y) / 20.0, oPos.z);
If you want to align the inner squares with the object you need to introduce texture coordinates. Where the bottom left coordinate of the object is (0, 0) and the top right is (1, 1).

Normal mapping working incorrectly, weird half-light effect

We are trying to implement normal mapping in our 2D Game Engine and get weird effect.
If normal is set manually like that
vec3 Normal = vec3(0.0, 0.0, 1.0) light works correctly, but we dont get "deep" effect that we want to achieve by normal mapping:
But if we get normal using normal map texture: vec3 Normal = texture(NormalMap, TexCoord).rgb it doesn't work at all. What should not be illuminated is illuminated and vice versa (such as the gaps between the bricks). And besides this, a dark area is on the bottom (or top, depending on the position of the light) side of the texture.
Although the texture of the normal map itself looks fine:
This is our fragment shader:
#version 330 core
layout (location = 0) out vec4 FragColor;
in vec2 TexCoord;
in vec2 FragPos;
uniform sampler2D OurTexture;
uniform sampler2D NormalMap;
struct point_light
{
vec3 Position;
vec3 Color;
};
uniform point_light Light;
void main()
{
vec4 Color = texture(OurTexture, TexCoord);
vec3 Normal = texture(NormalMap, TexCoord).rgb;
if (Color.a < 0.1)
discard;
vec3 LightDir = vec3(Light.Position.xy - FragPos, Light.Position.z);
float D = length(LightDir);
vec3 L = normalize(LightDir);
Normal = normalize(Normal * 2.0 - 1.0);
vec3 Diffuse = Light.Color * max(dot(Normal, L), 0);
vec3 Ambient = vec3(0.3, 0.3, 0.3);
vec3 Falloff = vec3(1, 0, 0);
float Attenuation = 1.0 /(Falloff.x + Falloff.y*D + Falloff.z*D*D);
vec3 Intensity = (Ambient + Diffuse) * Attenuation;
FragColor = Color * vec4(Intensity, 1);
}
And vertex as well:
#version 330 core
layout (location = 0) in vec2 aPosition;
layout (location = 1) in vec2 aTexCoord;
uniform mat4 Transform;
uniform mat4 ViewProjection;
out vec2 FragPos;
out vec2 TexCoord;
void main()
{
gl_Position = ViewProjection * Transform * vec4(aPosition, 0.0, 1.0);
TexCoord = aTexCoord;
FragPos = vec2(Transform * vec4(aPosition, 0.0, 1.0));
}
I google about that and found some people that get the same result, but their questions remained unanswered.
Any idea of what is the cause?
What texture format are you using for the normal map? SRGB, SNORM, etc? That might be the issue. Try UNORM.
Additionally, since you are not using a tangent space, make sure the plane's Z axis aligns with the Z axis of the normals. Also OGL reads Y in the reversed direction, so you need to flip the Y coordinates of the normals that you read from the normal map. Alternatively, you can use a reversed Y normal map (green pointing down).

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)

Specular Light appears on both sides

I have a very strange behaviour of specular(phong light model) light. It seems to be appering on both sides of all objects. Does anyone know what could be the issue ?
The actual calculation seems to be alright, as I can see that the light changes its position as object rotates.
#version 330
in vec4 CameraPos0;
in vec3 Pos0;
in vec4 Colour0;
in vec3 Normal0;
out vec4 FragColor;
// Ambient light parameters
uniform vec3 gAmbientLightIntensity;
// Directional light parameters
uniform vec3 gDirectionalLightIntensity;
uniform vec3 gDirectionalLightDirection;
// Specular light parameter
uniform vec3 gSpecularLightIntensity;
uniform vec3 gLightSourcePosition;
uniform vec3 gCameraPosition;
// Material constants
uniform float gKa;
uniform float gKd;
uniform float gKs;
void main()
{
// Calculate the ambient light intensity at the vertex
// Ia = Ka * ambientLightIntensity
vec4 ambientLightIntensity = gKa * vec4(gAmbientLightIntensity, 1.0);
// Setup the light direction and normalise it
vec3 lightDirection = normalize(-gDirectionalLightDirection);
//lightDirection = normalize(gDirectionalLightDirection);
// Id = kd * lightItensity * N.L
// Calculate N.L
float diffuseFactor = dot(Normal0, lightDirection);
diffuseFactor = clamp(diffuseFactor, 0.0, 1.0);
// N.L * light source colour * intensity
vec4 diffuseLightIntensity = gKd * vec4(gDirectionalLightIntensity, 1.0f) * diffuseFactor;
// Phong light
vec3 L = normalize(gLightSourcePosition - Pos0);
vec3 V = normalize(-Pos0);
vec3 R = normalize(2 * Normal0 * dot(Normal0, L) - L);
float specularFactor = pow(dot(R, V), 0.1f);
vec4 specularLightIntensity = gKs * vec4(gSpecularLightIntensity, 1.0f) * specularFactor;
specularLightIntensity = clamp(specularLightIntensity, 0.0, 1.0);
// Final vertex colour is the product of the vertex colour
// and the total light intensity at the vertex
vec4 lightedFragColor = Colour0 * (ambientLightIntensity + diffuseLightIntensity + specularLightIntensity);
FragColor = lightedFragColor;
}
Vertex Shader
#version 330
layout (location = 0) in vec3 Position;
layout (location = 1) in vec3 Normal;
layout (location = 2) in vec4 Colour;
out vec3 Pos0;
out vec4 Colour0;
out vec3 Normal0;
out vec4 CameraPos0;
uniform mat4 gModelToWorldTransform;
uniform mat4 gWorldToViewTransform;
uniform mat4 gProjectionTransform;
void main()
{
vec4 vertexPositionInModelSpace = vec4(Position, 1);
vec4 vertexInWorldSpace = gModelToWorldTransform * vertexPositionInModelSpace;
vec4 vertexInViewSpace = gWorldToViewTransform * vertexInWorldSpace;
vec4 vertexInHomogeneousClipSpace = gProjectionTransform * vertexInViewSpace;
gl_Position = vertexInHomogeneousClipSpace;
vec3 normalInWorldSpace = (gModelToWorldTransform * vec4(Normal, 0.0)).xyz;
normalInWorldSpace = normalize(normalInWorldSpace);
Normal0 = normalInWorldSpace;
CameraPos0 = vertexInViewSpace;
Pos0 = vertexInWorldSpace.xyz;
Colour0 = Colour;
}
you need to clamp the dot result from the saturation calculus because on the back side the result is negative and the pow can return a positive number instead of clamping it to zero.
float specularFactor = pow(clamp(dot(R, V),0.0,1.0), 0.1f);
Edit:
Also the V should be a vector pointing to the camera position, not to the vertex position in world space:
vec3 V = normalize(CameraPos0 - Pos0);