0

Here you see a scene comprised of planes lit by a point light. In nature, the brightness for each "fragment" is determined, for the most part, by it's distance from the source and I would like to see that smooth transition here, from wall to wall.

The only variable factor is the vertex normals, and no doubt they are causing this sharp change in colour. What can be done to light the room more realistically?

enter image description here

Vertex Shader

#version 330

precision highp float;

uniform mat4 projection_matrix;
uniform mat4 model_matrix;
uniform mat4 view_matrix;

in vec3 vert_position;
in vec2 vert_texcoord;
in vec3 vert_normal;

out vec3 frag_normal;
out vec2 frag_texcoord;

uniform vec3 LightPosition;

out vec3 toLightVector;

void main(void)
{
    vec4 world_position = model_matrix * vec4(vert_position, 1);
    frag_texcoord = vert_texcoord;

    frag_normal = (model_matrix * vec4(vert_normal, 0)).xyz;
    toLightVector = LightPosition - world_position.xyz;

    gl_Position = projection_matrix * view_matrix * world_position;
}

Fragment Shader

#version 330

precision highp float;

in vec3 frag_normal;
in vec2 frag_texcoord;
in vec3 toLightVector;

uniform sampler2D MyTexture0;
uniform vec3 LightColour;
uniform vec3 LightAttenuation;

out vec4 finalColor;

void main(void)
{
        float distance = length(toLightVector);
        float attFactor = LightAttenuation.x + (LightAttenuation.y * distance) + (LightAttenuation.z * distance * distance);

        vec3 unitNormal = normalize(frag_normal);
        vec3 unitLightVector = normalize(toLightVector);

        float nDot1 = dot(unitNormal, unitLightVector);
        float brightness = max(nDot1, 0);

        vec3 diffuse = (brightness * LightColour) / attFactor;

        finalColor = vec4(diffuse, 1.0) * texture(MyTexture0, frag_texcoord);
}
livin_amuk
  • 1,285
  • 12
  • 26
  • Probably irrelevant but worth pointing: Do you transform the normal with the [inverse transpose](https://stackoverflow.com/questions/13654401/what-is-the-logic-behind-transforming-normals-with-the-transpose-of-the-inverse) of the model matrix? – Margaret Bloom Apr 15 '16 at 15:23
  • No I don't, I merely pass a normalized directional vector for each vertex. I have a Vector3 array of 4x identical normals for each plane, how would I transform that with the inverse model matrix? – livin_amuk Apr 15 '16 at 15:28
  • "*he brightness for each fragment is determined by it's distance from the source*" No, it is not. That may be *part* of the determination, but that dot product with the normal and the light direction is pretty important too. If your normal is discontinuous, there's no reason to expect that the lighting will be too. – Nicol Bolas Apr 15 '16 at 15:31
  • My question was rhetorical, what I really meant was: that is another thing to consider. I don't know what's wrong with your code, but as Nicol pointed out beware of being deceived by real life optic, you don't have radiosity or ambient occluding and the lighting is very strong. – Margaret Bloom Apr 15 '16 at 15:37
  • I see, it's the sharp changes in normals creating the sharp change in colour. Would facing each vertex 45° towards the centre of it's parent plane create a smooth transition? – livin_amuk Apr 15 '16 at 15:43

3 Answers3

1

You're not going to like this Nicol Bolas, but simplifying the calculations to depend solely on distance provided precisely the effect I was after.

Skiving on design and aesthetics will destroy any art piece, but saying that, I'm not writing Doom 4 here, I'm a one man rent strike writing a rogue.

enter image description here

enter image description here

Fragment shader

#version 330

precision highp float;

in vec2 frag_texcoord;
in vec3 toLightVector;

uniform sampler2D MyTexture0;
uniform vec3 LightColour;
uniform vec3 LightAttenuation;

out vec4 finalColor;

void main(void)
{
        float distance = length(toLightVector);
        float attFactor = LightAttenuation.x + (LightAttenuation.y * distance) + (LightAttenuation.z * distance * distance);
        vec3 diffuse = (LightColour) / attFactor;

        finalColor = vec4(diffuse, 1.0) * texture(MyTexture0, frag_texcoord);
}
livin_amuk
  • 1,285
  • 12
  • 26
  • So... your question was about your lighting model not seeming realistic. Thus, the answer is to take away the actual *lighting model* part of your lighting model, turning it into simply multiplying a value by a distance? How was *anybody* supposed to guess that making things less realistic would be a valid answer? – Nicol Bolas Apr 15 '16 at 16:59
  • It doesn't always have to be a war you know. My question made it pretty clear which aspects were bothering me. In any case, thanks for the input, you are wise and a valuable resource to this community. – livin_amuk Apr 15 '16 at 17:05
0

Your problem is your expectations of your lighting model.

Your lighting lighting model is behaving exactly as it would be expected to. But it's just a model of reality, an approximation.

Real lighting is far more complex that a simple dot product and attenuation. It's a highly complicated interplay between lots and lots of small light sources and such. This explains why you don't (usually) see such discontinuities in lighting in real life.

The correct way to resolve this problem is not to change your attenuation or your normals. It's to investigate more accurate lighting models.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Can you suggest a more accurate model? The end goal is to write the lighting information for each wall to a light map in a pre-pass if that makes a difference. – livin_amuk Apr 15 '16 at 16:21
  • @livin_amuk: If that's your goal, OpenGL is probably the wrong tool. What you want is some sort of radiosity-based lighting system. The result will take a long time to generate on the CPU, but that's an off-line process. – Nicol Bolas Apr 15 '16 at 16:55
  • I'm not generating the lightmap with shaders, I'm doing it on the CPU, with the same algorithm as in my shaders. That way, the static environment will have the same luminosity as the dynamically lit objects. – livin_amuk Apr 15 '16 at 16:59
-1

Just put more weight on distance and less on normals. Make LightAttenuation look more like (0,0,1).

Sorin
  • 11,863
  • 22
  • 26
  • http://s9.postimg.org/8b5u4onbj/Screen_Shot_2016_04_16_at_1_56_02_AM.png I appreciate the suggestion, but I'm looking for a permanent solution. – livin_amuk Apr 15 '16 at 15:58