OpenGL - Unrealistic per-fragment point lighting

时间:2016-04-15 15:14:58

标签: opengl glsl

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);
}

3 个答案:

答案 0 :(得分:1)

你不会喜欢这个Nicol Bolas,但是简化计算仅仅取决于距离,这恰恰提供了我所追求的效果。

在设计和美学方面的削弱会摧毁任何艺术作品,但是说,我不是在这里写Doom 4,我是一个男人租罢工写一个流氓。

enter image description here

enter image description here

片段着色器

#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);
}

答案 1 :(得分:0)

您的问题是您对照明模型的期望。

您的照明照明模型的行为与预期完全一致。但它只是现实的模型,近似值。

真正的照明比简单的点积和衰减要复杂得多。这是很多很多小型光源之间的高度复杂的相互作用。这就解释了为什么你(通常)不会在现实生活中看到这种不连续性。

解决此问题的正确方法不是改变衰减或法线。这是为了研究更准确的照明模型。

答案 2 :(得分:-1)

只是增加距离,减少法线。使LightAttenuation看起来更像(0,0,1)。