OpenGL directional light creating black spots

Posted by AnonymousDeveloper on Game Development See other posts from Game Development or by AnonymousDeveloper
Published on 2014-08-20T16:06:28Z Indexed on 2014/08/20 16:37 UTC
Read the original article Hit count: 248

Filed under:
|
|
|

I probably ought to start by saying that I suspect the problem is that one of my vectors is not in the correct "space", but I don't know for sure.

I am having a strange problem with a directional light. When I move the camera away from (0.0, 0.0, 0.0) it creates tiny black spots that grow larger as the distance increases. I apologize ahead of time for the length of the code.

Vertex shader:

#version 410 core

in vec3 vf_normal;
in vec3 vf_bitangent;
in vec3 vf_tangent;
in vec2 vf_textureCoordinates;
in vec3 vf_vertex;

out vec3 tc_normal;
out vec3 tc_bitangent;
out vec3 tc_tangent;
out vec2 tc_textureCoordinates;
out vec3 tc_vertex;

uniform mat3 vf_m_normal;
uniform mat4 vf_m_model;
uniform mat4 vf_m_mvp;
uniform mat4 vf_m_projection;
uniform mat4 vf_m_view;

uniform float vf_te_inner;
uniform float vf_te_outer;

void main() {
    tc_normal = vf_normal;
    tc_bitangent = vf_bitangent;
    tc_tangent = vf_tangent;
    tc_textureCoordinates = vf_textureCoordinates;
    tc_vertex = vf_vertex;

    gl_Position = vf_m_mvp * vec4(vf_vertex, 1.0);
}

Tessellation Control shader:

#version 410 core

layout (vertices = 3) out;

in vec3 tc_normal[];
in vec3 tc_bitangent[];
in vec3 tc_tangent[];
in vec2 tc_textureCoordinates[];
in vec3 tc_vertex[];

out vec3 te_normal[];
out vec3 te_bitangent[];
out vec3 te_tangent[];
out vec2 te_textureCoordinates[];
out vec3 te_vertex[];

uniform float vf_te_inner;
uniform float vf_te_outer;

uniform vec4 vf_l_color;
uniform vec3 vf_l_position;
uniform mat4 vf_m_depthBias;
uniform mat4 vf_m_model;
uniform mat4 vf_m_mvp;
uniform mat4 vf_m_projection;
uniform mat4 vf_m_view;
uniform sampler2D vf_t_diffuse;
uniform sampler2D vf_t_normal;
uniform sampler2DShadow vf_t_shadow;
uniform sampler2D vf_t_specular;

#define ID gl_InvocationID

float getTessLevelInner(float distance0, float distance1) {
    float avgDistance = (distance0 + distance1) / 2.0;
    return clamp((vf_te_inner - avgDistance), 1.0, vf_te_inner);
}

float getTessLevelOuter(float distance0, float distance1) {
    float avgDistance = (distance0 + distance1) / 2.0;
    return clamp((vf_te_outer - avgDistance), 1.0, vf_te_outer);
}

void main() {
    te_normal[gl_InvocationID] = tc_normal[gl_InvocationID];
    te_bitangent[gl_InvocationID] = tc_bitangent[gl_InvocationID];
    te_tangent[gl_InvocationID] = tc_tangent[gl_InvocationID];
    te_textureCoordinates[gl_InvocationID] = tc_textureCoordinates[gl_InvocationID];
    te_vertex[gl_InvocationID] = tc_vertex[gl_InvocationID];

    float eyeToVertexDistance0 = distance(vec3(0.0), vec4(vf_m_view * vec4(tc_vertex[0], 1.0)).xyz);
    float eyeToVertexDistance1 = distance(vec3(0.0), vec4(vf_m_view * vec4(tc_vertex[1], 1.0)).xyz);
    float eyeToVertexDistance2 = distance(vec3(0.0), vec4(vf_m_view * vec4(tc_vertex[2], 1.0)).xyz);

    gl_TessLevelOuter[0] = getTessLevelOuter(eyeToVertexDistance1, eyeToVertexDistance2);
    gl_TessLevelOuter[1] = getTessLevelOuter(eyeToVertexDistance2, eyeToVertexDistance0);
    gl_TessLevelOuter[2] = getTessLevelOuter(eyeToVertexDistance0, eyeToVertexDistance1);
    gl_TessLevelInner[0] = getTessLevelInner(eyeToVertexDistance2, eyeToVertexDistance0);
}

Tessellation Evaluation shader:

#version 410 core

layout (triangles, equal_spacing, cw) in;

in vec3 te_normal[];
in vec3 te_bitangent[];
in vec3 te_tangent[];
in vec2 te_textureCoordinates[];
in vec3 te_vertex[];

out vec3 g_normal;
out vec3 g_bitangent;
out vec4 g_patchDistance;
out vec3 g_tangent;
out vec2 g_textureCoordinates;
out vec3 g_vertex;

uniform float vf_te_inner;
uniform float vf_te_outer;

uniform vec4 vf_l_color;
uniform vec3 vf_l_position;
uniform mat4 vf_m_depthBias;
uniform mat4 vf_m_model;
uniform mat4 vf_m_mvp;
uniform mat3 vf_m_normal;
uniform mat4 vf_m_projection;
uniform mat4 vf_m_view;
uniform sampler2D vf_t_diffuse;
uniform sampler2D vf_t_displace;
uniform sampler2D vf_t_normal;
uniform sampler2DShadow vf_t_shadow;
uniform sampler2D vf_t_specular;

vec2 interpolate2D(vec2 v0, vec2 v1, vec2 v2) {
    return vec2(gl_TessCoord.x) * v0 + vec2(gl_TessCoord.y) * v1 + vec2(gl_TessCoord.z) * v2;
}

vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2) {
    return vec3(gl_TessCoord.x) * v0 + vec3(gl_TessCoord.y) * v1 + vec3(gl_TessCoord.z) * v2;
}

float amplify(float d, float scale, float offset) {
    d = scale * d + offset;
    d = clamp(d, 0, 1);
    d = 1 - exp2(-2*d*d);

    return d;
}

float getDisplacement(vec2 t0, vec2 t1, vec2 t2) {
    float displacement = 0.0;
    vec2 textureCoordinates = interpolate2D(t0, t1, t2);
    vec2 vector = ((t0 + t1 + t2) / 3.0);
    float sampleDistance = sqrt((vector.x * vector.x) + (vector.y * vector.y));
    sampleDistance /= ((vf_te_inner + vf_te_outer) / 2.0);

    displacement += texture(vf_t_displace, textureCoordinates).x;
    displacement += texture(vf_t_displace, textureCoordinates + vec2(-sampleDistance, -sampleDistance)).x;
    displacement += texture(vf_t_displace, textureCoordinates + vec2(-sampleDistance,  sampleDistance)).x;
    displacement += texture(vf_t_displace, textureCoordinates + vec2( sampleDistance,  sampleDistance)).x;
    displacement += texture(vf_t_displace, textureCoordinates + vec2( sampleDistance, -sampleDistance)).x;

    return (displacement / 5.0);
}

void main() {
    g_normal = normalize(interpolate3D(te_normal[0], te_normal[1], te_normal[2]));
    g_bitangent = normalize(interpolate3D(te_bitangent[0], te_bitangent[1], te_bitangent[2]));
    g_patchDistance = vec4(gl_TessCoord, (1.0 - gl_TessCoord.y));
    g_tangent = normalize(interpolate3D(te_tangent[0], te_tangent[1], te_tangent[2]));
    g_textureCoordinates = interpolate2D(te_textureCoordinates[0], te_textureCoordinates[1], te_textureCoordinates[2]);
    g_vertex = interpolate3D(te_vertex[0], te_vertex[1], te_vertex[2]);

    float displacement = getDisplacement(te_textureCoordinates[0], te_textureCoordinates[1], te_textureCoordinates[2]);
    float d2 = min(min(min(g_patchDistance.x, g_patchDistance.y), g_patchDistance.z), g_patchDistance.w);
    d2 = amplify(d2, 50, -0.5);
    g_vertex += g_normal * displacement * 0.1 * d2;

    gl_Position = vf_m_mvp * vec4(g_vertex, 1.0);
}

Geometry shader:

#version 410 core

layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

in vec3 g_normal[3];
in vec3 g_bitangent[3];
in vec4 g_patchDistance[3];
in vec3 g_tangent[3];
in vec2 g_textureCoordinates[3];
in vec3 g_vertex[3];

out vec3 f_tangent;
out vec3 f_bitangent;
out vec3 f_eyeDirection;
out vec3 f_lightDirection;
out vec3 f_normal;
out vec4 f_patchDistance;
out vec4 f_shadowCoordinates;
out vec2 f_textureCoordinates;
out vec3 f_vertex;

uniform vec4 vf_l_color;
uniform vec3 vf_l_position;
uniform mat4 vf_m_depthBias;
uniform mat4 vf_m_model;
uniform mat4 vf_m_mvp;
uniform mat3 vf_m_normal;
uniform mat4 vf_m_projection;
uniform mat4 vf_m_view;
uniform sampler2D vf_t_diffuse;
uniform sampler2D vf_t_normal;
uniform sampler2DShadow vf_t_shadow;
uniform sampler2D vf_t_specular;

void main() {
    int index = 0;

    while (index < 3) {
        vec3 vertexNormal_cameraspace = vf_m_normal * normalize(g_normal[index]);
        vec3 vertexTangent_cameraspace = vf_m_normal * normalize(f_tangent);
        vec3 vertexBitangent_cameraspace = vf_m_normal * normalize(f_bitangent);

        mat3 TBN = transpose(mat3(
            vertexTangent_cameraspace,
            vertexBitangent_cameraspace,
            vertexNormal_cameraspace
        ));

        vec3 eyeDirection = -(vf_m_view * vf_m_model * vec4(g_vertex[index], 1.0)).xyz;
        vec3 lightDirection = normalize(-(vf_m_view * vec4(vf_l_position, 1.0)).xyz);
        f_eyeDirection = TBN * eyeDirection;
        f_lightDirection = TBN * lightDirection;
        f_normal = normalize(g_normal[index]);
        f_patchDistance = g_patchDistance[index];
        f_shadowCoordinates = vf_m_depthBias * vec4(g_vertex[index], 1.0);
        f_textureCoordinates = g_textureCoordinates[index];
        f_vertex = (vf_m_model * vec4(g_vertex[index], 1.0)).xyz;

        gl_Position = gl_in[index].gl_Position;
        EmitVertex();

        index ++;
    }

    EndPrimitive();
}

Fragment shader:

#version 410 core

in vec3 f_bitangent;
in vec3 f_eyeDirection;
in vec3 f_lightDirection;
in vec3 f_normal;
in vec4 f_patchDistance;
in vec4 f_shadowCoordinates;
in vec3 f_tangent;
in vec2 f_textureCoordinates;
in vec3 f_vertex;

out vec4 fragColor;

uniform vec4 vf_l_color;
uniform vec3 vf_l_position;
uniform mat4 vf_m_depthBias;
uniform mat4 vf_m_model;
uniform mat4 vf_m_mvp;
uniform mat4 vf_m_projection;
uniform mat4 vf_m_view;
uniform sampler2D vf_t_diffuse;
uniform sampler2D vf_t_normal;
uniform sampler2DShadow vf_t_shadow;
uniform sampler2D vf_t_specular;

vec2 poissonDisk[16] = vec2[](
    vec2(-0.94201624, -0.39906216),
    vec2( 0.94558609, -0.76890725),
    vec2(-0.09418410, -0.92938870),
    vec2( 0.34495938,  0.29387760),
    vec2(-0.91588581,  0.45771432),
    vec2(-0.81544232, -0.87912464),
    vec2(-0.38277543,  0.27676845),
    vec2( 0.97484398,  0.75648379),
    vec2( 0.44323325, -0.97511554),
    vec2( 0.53742981, -0.47373420),
    vec2(-0.26496911, -0.41893023),
    vec2( 0.79197514,  0.19090188),
    vec2(-0.24188840,  0.99706507),
    vec2(-0.81409955,  0.91437590),
    vec2( 0.19984126,  0.78641367),
    vec2( 0.14383161, -0.14100790)
);

float random(vec3 seed, int i) {
    vec4 seed4 = vec4(seed,i);
    float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673));
    return fract(sin(dot_product) * 43758.5453);
}

float amplify(float d, float scale, float offset) {
    d = scale * d + offset;
    d = clamp(d, 0, 1);
    d = 1 - exp2(-2.0 * d * d);

    return d;
}

void main() {
    vec3 lightColor = vf_l_color.xyz;
    float lightPower = vf_l_color.w;

    vec3 materialDiffuseColor = texture(vf_t_diffuse, f_textureCoordinates).xyz;
    vec3 materialAmbientColor = vec3(0.1, 0.1, 0.1) * materialDiffuseColor;
    vec3 materialSpecularColor = texture(vf_t_specular, f_textureCoordinates).xyz;

    vec3 n = normalize(texture(vf_t_normal, f_textureCoordinates).rgb * 2.0 - 1.0);

    vec3 l = normalize(f_lightDirection);
    float cosTheta = clamp(dot(n, l), 0.0, 1.0);
    vec3 E = normalize(f_eyeDirection);
    vec3 R = reflect(-l, n);
    float cosAlpha = clamp(dot(E, R), 0.0, 1.0);

    float visibility = 1.0;
    float bias = 0.005 * tan(acos(cosTheta));
    bias = clamp(bias, 0.0, 0.01);

    for (int i = 0; i < 4; i ++) {
        float shading = (0.5 / 4.0);
        int index = i;

        visibility -= shading * (1.0 - texture(vf_t_shadow, vec3(f_shadowCoordinates.xy + poissonDisk[index] / 3000.0, (f_shadowCoordinates.z - bias) / f_shadowCoordinates.w)));
    }\n"

    fragColor.xyz =
    materialAmbientColor +
    visibility * materialDiffuseColor * lightColor * lightPower * cosTheta +
    visibility * materialSpecularColor * lightColor * lightPower * pow(cosAlpha, 5);

    fragColor.w = texture(vf_t_diffuse, f_textureCoordinates).w;
}

The following images should be enough to give you an idea of the problem.

Before moving the camera: Before moving

Moving the camera just a little.

Black spots beginning to appear

Moving it to the center of the scene.

Black spots almost completely covering the object

© Game Development or respective owner

Related posts about opengl

Related posts about rendering