1

I've been working on OpenGL for a while now, and I'm now working at diffuse lighting. I've set up a way to change the light source, but my object acts as if it were in the same place each time.

I've continued checking whether or not my fragment shader and vertex shader is correct, but no problems seem to arise.

This is the light position sent to the core shader:

vec3 lightPos0 = vec3(0.f, 0.f, 2.f);

glUniform3fv(glGetUniformLocation(coreShader.getID(), "lightPos0"), 1, value_ptr(lightPos0));

And here are the fragment and vertex shaders (with all usual variables implied to exist):

#version 450
layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec2 vertex_texcoord;
layout (location = 3) in vec3 vertex_normal;

out vec3 vs_position;
out vec3 vs_color;
out vec2 vs_texcoord;
out vec3 vs_normal;

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

void main()
{
  vs_position = vec4(ModelMatrix * vec4(vertex_position, 1.f)).xyz;
  vs_color = vertex_color;

  vs_texcoord = vec2(vertex_texcoord.x, vertex_texcoord.y * -1.f);

  vs_normal = mat3(ModelMatrix) * vertex_normal;

  gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(vertex_position, 1.f);
}
#version 450

in vec3 vs_position;
in vec3 vs_color;
in vec2 vs_texcoord;
in vec3 vs_normal;

out vec4 fs_color;

uniform sampler2D texture0;
uniform sampler2D texture1;

uniform vec3 lightPos0;

void main()
{
  //Ambient light
  vec3 ambientLight = vec3(0.1f, 0.1f, 0.1f);

  //Diffuse light
  vec3 posToLightDirVec = normalize(lightPos0 - vs_position);
  vec3 diffuseColor = vec3(1.f, 1.f, 1.f);
  float diffuse = max(dot(posToLightDirVec, vs_normal), 0.0);
  vec3 diffuseFinal = diffuseColor * diffuse;

  fs_color =
  (texture(texture0, vs_texcoord)) * vec4(vs_color, 1.f)
  * (vec4(ambientLight, 1.f) + vec4(diffuseFinal, 1.f));
}

If you actually managed to take all of this and get it to about what this program looks like, you would notice that it wouldn't quite matter where you put the light point. You would always have to move back slightly to actually see anything. Also, you would see that it isn't quite diffuse, but more like specular lighting. If you need any more code, ask me in the comments.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
XnossisX
  • 57
  • 6
  • *"that it isn't quite diffuse, but more like specular lighting"* No. `dot(posToLightDirVec, vs_normal)` is a perfect [Lambertian](https://en.wikipedia.org/wiki/Lambertian_reflectance) diffuse light. See [How does this faking the light work](https://stackoverflow.com/questions/7061745/how-does-this-faking-the-light-work-on-aerotwist/45121641#45121641). – Rabbid76 Sep 13 '19 at 08:20
  • How do you change the position of the light source? When you change the position (`glUniform3fv`), then the shader program was installed before (`glUseProgram(coreShader.getID())`), isn't it? – Rabbid76 Sep 13 '19 at 14:56
  • @Rabbid76 I'm changing it by changing the first statement. For example, if it was (0.f, 2.f, 2.f), what you would see is that once the light is hitting the object, it would be in the y direction. However, it seems to do nothing. – XnossisX Sep 13 '19 at 21:23
  • 1
    I see. But do you call `glUseProgram(coreShader.getID())` before? Note, `glUniform3fv` changes the value of a uniform in the default uniform block of the currently installed program. – Rabbid76 Sep 13 '19 at 21:25
  • 1
    That was the exact problem, actually. I thought that back before the VAOs were worked on, it was loaded, but apparently not. Thank you, again! – XnossisX Sep 13 '19 at 21:33

2 Answers2

1

Vou've to install the program as object as part of current rendering state, before you can set the value of the uniform variable lightPos0:

glUseProgram(coreShader.getID())

Note, glUniform3fv changes the value of a uniform in the default uniform block of the currently installed program.

Of course you can get the index of a active program resource (e.g. glGetUniformLocation) before the program is installed. For that it sufficient that the program is linked, but it is not necessary that it is the current program.
If you compare the function glGetUniformLocation and glUniform, then you can see, that the program object is a parameter to the former, but not to the later function. For the use of glUniform the program has to be current.
Since OpenGL 4.1 glProgramUniform is provided, which can specify the value of a uniform variable for a specified program object.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
0

This is your problem:

    vec3 posToLightDirVec = normalize(lightPos0 - vs_position);

vs_position is in local space, and so is unaffected by transformations. Transform it first....

    vec3 posToLightDirVec = normalize(lightPos0 - (ModelMatrix * vs_position).xyz);
robthebloke
  • 9,331
  • 9
  • 12
  • ModelMatrix is a 4x4 matrix, and vs_position is only 3 long. Those don't multiply, and I get error C1101: ambiguous overloaded function reference. – XnossisX Sep 13 '19 at 02:14
  • After I stopped the compiler error, I get the same problem. – XnossisX Sep 13 '19 at 02:30
  • vec3 posToLightDirVec = normalize(lightPos0 - (ModelMatrix * vec4(vs_position, 1.0)).xyz); – robthebloke Sep 13 '19 at 04:14
  • This answer is wrong. `lightPos0` is a position in world space. Since `vs_normal` and `vs_position` are transformed by the model matrix (`ModelMatrix`), they are in world space, too and everything is fine. The fragment shader does the light calculations in world space and that's fine. – Rabbid76 Sep 13 '19 at 10:18