Освещение OpenGL Phong: зеркальная подсветка неправильная - PullRequest
1 голос
/ 12 апреля 2020

Кажется, странная проблема с моим шейдером освещения Phong в OpenGL. Зеркальное выделение появляется на изнанке объекта.

Проблема под рукой:

No highlight closest to the light

Highlight on the opposite side

Как вы можете видеть, зеркальное выделение появляется на противоположной стороне куба (а также появляется в углах перпендикулярных краев куба, с точки зрения источника света. Оно должно появляться только на сторона, ближайшая к свету.

Вершины куба:

float cubeVertices[] = {
    // positions          // normals           // texture coords
    -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
    -1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
     1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
     1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
     1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
    -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
    -1.0f, -1.0f,  1.0f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
     1.0f, -1.0f,  1.0f,  0.0f,  0.0f, 1.0f,   1.0f, 0.0f,
     1.0f,  1.0f,  1.0f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
     1.0f,  1.0f,  1.0f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
    -1.0f,  1.0f,  1.0f,  0.0f,  0.0f, 1.0f,   0.0f, 1.0f,
    -1.0f, -1.0f,  1.0f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
    -1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
    -1.0f,  1.0f, -1.0f, -1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
    -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -1.0f, -1.0f,  1.0f, -1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
    -1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
     1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
     1.0f, -1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
     1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
     1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
     1.0f,  1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
     1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
    -1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
     1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,  1.0f, 1.0f,
     1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
     1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
    -1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f,
    -1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
    -1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
    -1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
     1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
     1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
     1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
    -1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f
};

Вершинный шейдер:

#version 330 core

layout (location = 0) in vec3 vPos;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec2 vTexCoords;

out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    FragPos = vec3(model * vec4(vPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * vNormal;  
    TexCoords = vTexCoords;

    gl_Position = projection * view * vec4(FragPos, 1.0);
}

Фрагментный шейдер:

#version 330 core

out vec4 FragColor; 

in vec3 FragPos;  
in vec3 Normal;  
in vec2 TexCoords;

uniform vec3 viewPos;
uniform sampler2D diffuseMap;

struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

uniform Light lights[8];
uniform int numLights;

vec3 calculateAmbient(vec3 fragPos, vec3 materialAmbient)
{
    vec3 ambient = vec3(0.0);

    for (int i = 0; i < numLights && i < 8; i++)
    {
        ambient += lights[i].ambient * materialAmbient;
    }

    return ambient * 0.5;
}

vec3 calculateDiffuse(vec3 fragPos, vec3 normal, vec3 materialDiffuse)
{
    vec3 diffuse = vec3(0.0);

    for (int i = 0; i < numLights && i < 8; i++)
    {
        vec3 lightDir = normalize(lights[i].position - fragPos);
        float diff = max(dot(normal, lightDir), 0.0);
        diffuse += lights[i].diffuse * (diff * materialDiffuse);
    }

    return diffuse;
}

vec3 calculateSpecular(vec3 fragPos, vec3 normal, vec3 viewDir, vec3 materialSpecular, float shininess)
{
    vec3 specular = vec3(0.0);

    for (int i = 0; i < numLights && i < 8; i++)
    {
        vec3 lightDir = normalize(lights[i].position - fragPos);
        vec3 reflectDir = reflect(-lightDir, normal);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
        specular += lights[i].specular * (spec * materialSpecular);
    }

    return specular;
}

void main()
{
    vec4 tex = texture(diffuseMap, TexCoords);

    vec3 norm = normalize(Normal);
    vec3 viewDir = normalize(viewPos - FragPos);

    vec3 ambient = calculateAmbient(FragPos, material.ambient);
    vec3 diffuse = calculateDiffuse(FragPos, norm, material.diffuse);
    vec3 specular = calculateSpecular(FragPos, norm, viewDir, material.specular, material.shininess);

    vec3 result = (ambient + diffuse + specular) * tex.rgb;
    FragColor = vec4(result, 1.0);
} 

1 Ответ

2 голосов
/ 12 апреля 2020

Зеркальное выделение появляется также на гранях, обращенных к источнику света с обратной стороны, потому что relfect фактически вычисляет:

refelct(I, N) = I - 2.0 * dot(N, I) * N

На оборотных гранях точки нормальных векторов от источника света, но refelct(I, N) == refelct(I, -N), потому что:

I - 2.0 * dot(N, I) * N == I - 2.0 * dot(-N, I) * -N

В модели отражения Фонг зеркальное освещение добавляется только, если рассеянный свет> 0. например :

for (int i = 0; i < numLights && i < 8; i++)
{
    vec3 lightDir = normalize(lights[i].position - fragPos);
    float NdotL = dot(normal, lightDir);
    if (NdotL > 0.0)
    {
        vec3 reflectDir = reflect(-lightDir, normal);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
        specular += lights[i].specular * (spec * materialSpecular);
    }
}
...