Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Sphere lighting wrong results

I have a simple per-pixel-lighting shader, but the sphere I want to draw looks a bit like per-vertex shading. I investigated this since yesterday, but didn’t find any issues. The normals of a sphere are the same as the normalized vertex positions, or am I wrong?

Vertex shader:


#version 330 core

uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;

in vec3 Position;
in vec3 Normal;

out vec3 VertexEyePosition;
out vec3 NormalEyePosition;

void main()
{
    gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.0f);
    VertexEyePosition = vec3(ModelViewMatrix * vec4(Position, 1.0f));
    NormalEyePosition = NormalMatrix * normalize(Normal);
}

Fragment shader:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel


#version 330 core

uniform vec4 EyeLightPosition;

in vec3 VertexEyePosition;
in vec3 NormalEyePosition;

out vec4 FinalColor;

void main()
{
    vec3 L = normalize(vec3(EyeLightPosition) - VertexEyePosition);
    vec3 N = NormalEyePosition;
    vec3 R = reflect(-L, N);
    vec3 V = normalize(-VertexEyePosition);

    vec3 Ambient = 0.1 * vec3(1.0, 0.0, 0.0);
    vec3 Diffuse = 0.8 * vec3(1.0, 0.0, 0.0) * max(0.0, dot(N, L));
    vec3 Specular = vec3(1.0) * pow(max(0.0, dot(R, V)), 8.0);

    FinalColor = vec4(Ambient + Diffuse + Specular, 1.0);
}

For a cube or plane the shader works fine.

Sphere generation:

void SphereMesh::GenerateGeometry()
{
    vertices.clear();
    uv_coords.clear();
    normals.clear();
    faces.clear();

    vertices.reserve((segments + 1) * (rings + 1));
    uv_coords.reserve((segments + 1) * (rings + 1));

    // Generate vertices and UV coordinates;
    for (unsigned int ring = 0; ring <= rings; ring++)
    {
        const float ring_sin = glm::sin(static_cast<float>(ring) / rings * glm::pi<float>() - 0.5f * glm::pi<float>());
        const float ring_cos = glm::cos(static_cast<float>(ring) / rings * glm::pi<float>() - 0.5f * glm::pi<float>());

        for (unsigned int segment = 0; segment <= segments; segment++)
        {
            if (((ring == 0) || (ring == rings)) && (segment == segments)) continue;

            const float segment_sin = glm::sin(static_cast<float>(segment) / segments * 2.0f * glm::pi<float>());
            const float segment_cos = glm::cos(static_cast<float>(segment) / segments * 2.0f * glm::pi<float>());

            const float x = radius * ring_cos * segment_sin;
            const float y = radius * ring_sin;
            const float z = radius * ring_cos * segment_cos;

            const float u = ((ring == 0) || (ring == rings)) && (segment == segments) ?
                    static_cast<float>(segment) / (segments - 1) + 0.5f * static_cast<float>(segment) / (segments - 1):
                    static_cast<float>(segment) / segments;
            const float v = static_cast<float>(ring) / rings;

            vertices.emplace_back(x, y, z);
            uv_coords.emplace_back(u, v);
            normals.emplace_back(glm::normalize(glm::vec3(x, y, z)));
        }
    }

    // Generate faces
    for (unsigned int ring = 0; ring < rings; ring++)
    {
        for (unsigned int segment = 0; segment < segments; segment++)
        {
            if (ring == 0)  // Lower cap
            {
                Face face;
                face.a = segment;
                face.b = segments + segment + 1;
                face.c = segments + segment;
                faces.push_back(face);
            }
            else if (ring < rings - 1) // Body
            {
                const unsigned int v1 = segments + ((ring - 1) * (segments + 1)) + segment;
                const unsigned int v2 = segments + ((ring - 1) * (segments + 1)) + segment + 1;
                const unsigned int v3 = segments + ((ring - 1 + 1) * (segments + 1)) + segment;
                const unsigned int v4 = segments + ((ring - 1 + 1) * (segments + 1)) + segment + 1;
                Face face1, face2;
                face1.a = v1;
                face1.b = v2;
                face1.c = v3;
                face2.a = v3;
                face2.b = v2;
                face2.c = v4;
                faces.push_back(face1);
                faces.push_back(face2);
            }
            else // Upper cap
            {
                Face face;
                face.a = segments + ((ring - 1) * (segments + 1)) + segment;
                face.b = segments + ((ring - 1) * (segments + 1)) + segment + 1;
                face.c = segments + ((ring - 1 + 1) * (segments + 1)) + segment;
                faces.push_back(face);
            }
        }
    }
}

Result:

enter image description here

>Solution :

NormalEyePosition must also be normalized in the fragment shader When interpolating vectors, the length of the vector is not maintained.

vec3 N = NormalEyePosition;

vec3 N = normalize(NormalEyePosition);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading