Opengl the light position always on the origin point therefore the diffuse and specular does not work

by GuangWu   Last Updated September 11, 2019 23:13 PM

I am newbie of opengl, so I did the tutorial by learnopengl. I have a strange problem when I was trying to do the light effect (ambient, diffuse and specular). For the diffuse, the effect appears on incorrect surface,and it seems like the light position always local on the origin point even I have change the position of it(the right cube position and the light position as the image shows):

The light now on the top of the right cube and there is no diffuse effect on the top surface of the cube, however the image shows that there is a light on the original point

I was also tried to add the specular in fragment shader but it also only appear on the left surface of that cube(the green arrow, that surface should not be lighten because now the vector is parallel the surface, so theoretically that surface should be black). I have passed the light position and camera position to fragment shader of the cube (also the light fragment shader):

    glm::vec3 lightPos(0.0f, 2.5f, 3.0f);
    cubeShader->use();
    cubeShader->setVec3("lightPos", lightPos); 
    cubeShader->setVec3("cameraPos", secondCamera->Position);

and the fragment shader is, as simply as the tutorial's example:

out vec4 FragColor;
in vec3 Normal;
in vec3 FragPos;
in vec3 lightPos;
uniform vec3 cameraPos;
uniform vec3 lightColor;
uniform vec3 objectColor;
void main()
{

    //ambient CONDITION
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;        
    //diffuse CONDITION 
    vec3 norm = normalize(Normal);
    vec3 lightDirection = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDirection), 0.0);
    vec3 diffuse =  diff* lightColor;
    //specular CONDITON
    float specularStrength = 0.5;
    vec3 viewDirection = normalize(cameraPos- FragPos);
    vec3 reflectDirection = reflect(-1.0 * lightDirection, norm);  
    float spec = pow(max(dot(viewDirection, reflectDirection), 0.0), 32);
    vec3 specular = specularStrength * spec * lightColor;  
    //Result
    vec3 Result = (ambient + diffuse + specular) * objectColor;
    FragColor = vec4(Result, 1.0f);

}

Even I add the specular, the specular appears on the incorrect surface. I was also refer this answer, thought it might be the transformation of model from camera to world by using inverse and transpose:

glsl directional light specular seems to be relative to origin not camera

However I did this in my vertex shader:

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
out vec3 Normal;
out vec3 FragPos; 
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec3 cPosition[10];

void main()
{
vec3 newPosition = cPosition[gl_InstanceID];
gl_Position =  projection * view  * model * vec4(aPos + newPosition,1.0);
FragPos = vec3(model * vec4(aPos +newPosition,1.0)); 
Normal = mat3(transpose(inverse(model))) * aNormal;
}  

So in totally, the problem is, when the light position changed, the effect will not change because it only control by the "ghost" light which locals on the origin point. Could you guys please tell me, why there is a light on the origin? Thanks!



Answers 1


I believe you may be experiencing what happens when you use quantities belonging to distinctly different spaces. I have a number of questions for you which will hopefully lead you to your answer.

First, why are you using the inverse transpose of your model matrix to transform your normal? assuming your model matrix is your ObjectSpace => WorldSpace transformation, and your normal should be in object space, simply multiplying your normal by your Model matrix should map your normal into World Space.

Second, what's the deal with newPosition? It's not clear to me what this is for, but you appear to be translating your ObjectSpace quantities, which means your pipeline from ObjectSpace => ModelSpace => ViewSpace => NDC coordinates is no longer valid, as your ObjectSpace vertex is no longer centered at the origin? gl_Position should be the MVP * SomeVertexPosition in Object space, which converts it to NDC.

You may want to get in the habit of including a prefix for your shader variables which could help you denote which space each variable is in. When you move on to a more complicated phong implementation, you will have to deal with tangent space as well. I'm not sure if it's a comon practice, but labeling my spaces and labeling my matrices in a XSpaceToXSpace fashion certainly helps me keep track of where each variable is supposed to go, as well as help me track down the bugs quicker. You just see the names don't match up, and voila your hour-long bug hunt is cut short. I'll give you an example from one of my vertex shaders

  // deal with position and normal in world space  
  WorldPosition = ModelMatrix * vec4(vPosition, 1);

  //convert TBN vectors to view space
  WorldNormal = normalize(ModelMatrix * vec4(vNormal, 0));
  WorldTangent = normalize(ModelMatrix * vec4(vTangent,0.f));
  WorldBitangent = normalize(ModelMatrix * vec4(vBitangent,0.f));

  mat4 WorldToTangent;
  WorldToTangent[0] = WorldTangent;
  WorldToTangent[1] = WorldBitangent;
  WorldToTangent[2] = WorldNormal;
  WorldToTangent[3] = vec4(0.f,0.f,0.f,1.f);

  //because we orthonormalized, TBN will now be our TangentToWorld (the transpose of an orthogonal matrix is equivalent to its inverse)
  if (Material.NormalMapTextureEnabled)
    TBN = mat4(transpose(mat3(WorldToTangent)), vec4(0,0,0,1));;
  else
    TBN = mat4(1.f);


  //Use TBN to convert world-space light positions and directions into tangent space
  for (int i=0;i<LightCount;++i)
    setLightDirection(i);

  ViewVector = Material.NormalMapTextureEnabled ? TBN * vec4(Camera.Position - WorldPosition.xyz, 0) :vec4(Camera.Position - WorldPosition.xyz, 0) ;
  CameraPosition = Material.NormalMapTextureEnabled ? TBN * vec4(Camera.Position, 1.f) : vec4(Camera.Position, 1.f); 

...

  gl_Position = ModelViewProjectionMatrix * vec4(vPosition, 1);
Jon Koelzer
Jon Koelzer
September 11, 2019 21:57 PM

Related Questions


Unity, per vertex lighting tutorial

Updated March 16, 2017 07:13 AM

How to set up OpenGL for CLion on Windows

Updated September 02, 2016 08:05 AM

Learning 3D Libgdx game programming

Updated July 10, 2019 17:13 PM

Best tutorials for openGL and Libgdx?

Updated February 21, 2017 10:13 AM