0
\$\begingroup\$

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!

\$\endgroup\$
0
\$\begingroup\$

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);
\$\endgroup\$
  • \$\begingroup\$ Hi Dear Jon, thanks for your answer. For your questions: first, the normal matrix keeps the normal vector when the objects were transformed like compress. However the normal matrix does not contain the translate effect of the normal vector, that means, if I mulit the normal matrix with the model and its normal vector, I should got the a new normal vector which belongs to transformed model. \$\endgroup\$ – GuangWu Sep 15 at 18:48
  • \$\begingroup\$ The second question, about newPosition. I have simply set a array which contains 10 object location, which like newPosition[1.0,2.0,3.0, .........] then the vertax shader take this data to give different location of 10 object like my image shows and as you see in my vertax shader : gl_Position = projection * view * model * vec4(aPos + newPosition,1.0);. In total, my problem is, it seems like I can not pass the light position into fragment shader and the fragment shader seems set a value (0,0,0) as a default to my light position. \$\endgroup\$ – GuangWu Sep 15 at 18:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.