2016-02-03 1 views
4

Я пытаюсь сделать небольшой 3D-движок для моей магистерской степени (и для своего мастерства). У меня проблема зеркального отражения. (Прошу прощения за ссылку на иллюстрацию, но пока у меня недостаточно репутации). Все источники доступны на моем GitHub: DWRendererНеверное зеркальное отражение

Image of the problem

Прямо здесь, мы опережать объект, но камера находится на передней панели также свет. Как мы видим, за объектом есть отражение.

Для описания реальных параметров все вычисления производятся в мировом пространстве (обычно ... с этой проблемой, я сомневаюсь). Я поставил камеру в положение vec3 (0, 0, 3) для теста, а свет - это просто точка в vec3 (1,2, 1, 2), представляемая кубом. Я использую Qt 5.4 и OpenGL 4.1 под Ubuntu с драйверами Nvidia.

Вот моя вершинный шейдер:

#version 410 core 

layout (location = 0) in vec3 position; 
layout (location = 1) in vec3 normal; 

out vec3 Normal; 
out vec3 FragPos; 

uniform mat4 model; 
uniform mat4 view; 
uniform mat4 projection; 
uniform mat3 normalMatrix; 

void main() 
{ 
    gl_Position = projection * view * model * vec4(position, 1.0f); 
    FragPos = vec3(model * vec4(position, 1.0f)); 
    Normal = normalMatrix * normal; 
} 

И мой пиксельный шейдер:

#version 410 core 

out vec4 color; 

in vec3 Normal; 
in vec3 FragPos; 

struct Material { 
    vec3 ambient; 
    vec3 diffuse; 
    vec3 specular; 
    float shininess; 
}; 

struct Light { 
    vec3 position; 

    vec3 ambient; 
    vec3 diffuse; 
    vec3 specular; 
}; 

uniform Material material; 
uniform Light light; 

uniform vec3 viewPos; 

void main() 
{ 
    // Vectors 
    vec3 norm = normalize(Normal); 
    vec3 lightDir = normalize(light.position - FragPos); 
    vec3 viewDir = normalize(viewPos - FragPos); 
    vec3 reflectDir = reflect(-lightDir, norm); 

    // Ambient 
    vec3 ambient = material.ambient * light.ambient; 

    // Diffuse 
    float diff = clamp(dot(lightDir, norm), 0.0, 1.0); 
    vec3 diffuse = diff * material.diffuse * light.diffuse; 

    // Specular - The bug seems only here 
    float spec = pow(clamp(dot(viewDir, reflectDir), 0.0, 1.0), material.shininess); 
    vec3 specular = spec * material.specular * light.specular; 

    vec3 result = (diffuse + specular + ambient); 
    color = vec4(result, 1.0f); 

    // For test vectors 
    //color = vec4(specular, 1.0f); 
} 

И код в игровом цикле (paintGL со временем с интервалом 16мс в режиме реального времени) для инициализации равномерной переменной (положение камеры для шейдера фиксировано, я могу обернуть свой куб для проверки ошибки. Положение света находится в «initializeGL» и зафиксировано тоже):

// Draw cube 
    m_cubeShader->useShaderProgram(); 
    GLint lightPosLoc = glGetUniformLocation(m_cubeShader->getId(), "light.position"); 
    GLint viewPosLoc = glGetUniformLocation(m_cubeShader->getId(), "viewPos"); 
    GLint matAmbientLoc = glGetUniformLocation(m_cubeShader->getId(), "material.ambient"); 
    GLint matDiffuseLoc = glGetUniformLocation(m_cubeShader->getId(), "material.diffuse"); 
    GLint matSpecularLoc = glGetUniformLocation(m_cubeShader->getId(), "material.specular"); 
    GLint matShineLoc = glGetUniformLocation(m_cubeShader->getId(), "material.shininess"); 
    GLint lightAmbientLoc = glGetUniformLocation(m_cubeShader->getId(), "light.ambient"); 
    GLint lightDiffuseLoc = glGetUniformLocation(m_cubeShader->getId(), "light.diffuse"); 
    GLint lightSpecularLoc = glGetUniformLocation(m_cubeShader->getId(), "light.specular"); 
    glUniform3f(lightAmbientLoc, 0.2f, 0.2f, 0.2f); 
    glUniform3f(lightDiffuseLoc, 0.5f, 0.5f, 0.5f); 
    glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f); 
    glUniform3f(matAmbientLoc, 1.0f, 0.5f, 0.31f); 
    glUniform3f(matDiffuseLoc, 1.0f, 0.5f, 0.31f); 
    glUniform3f(matSpecularLoc, 0.5f, 0.5f, 0.5f); 
    glUniform1f(matShineLoc, 32.0f); 
    glUniform3f(viewPosLoc, 0.0f, 0.0f, 3.0f); // For testing a bug - Unresolved 
    //glUniform3f(viewPosLoc, m_camera->getPosition().x, m_camera->getPosition().y, m_camera->getPosition().z); 
    glUniform3f(lightPosLoc, m_lightPos.x, m_lightPos.y, m_lightPos.z); 

    glm::mat4 model; 
    glm::mat4 view; 
    glm::mat4 projection; 
    glm::mat3 normalMatrix; 
    normalMatrix = glm::mat3(glm::transpose(glm::inverse(model))); 
    view = m_camera->getViewMatrix(); 
    projection = glm::perspective(glm::radians(m_camera->getFov()), (GLfloat)m_screenWidth/(GLfloat)m_screenHeight, 0.1f, 100.0f); 
    GLint normalMatrixLoc = glGetUniformLocation(m_cubeShader->getId(), "normalMatrix"); 
    GLint modelLoc = glGetUniformLocation(m_cubeShader->getId(), "model"); 
    GLint viewLoc = glGetUniformLocation(m_cubeShader->getId(), "view"); 
    GLint projectionLoc = glGetUniformLocation(m_cubeShader->getId(), "projection"); 
    glUniformMatrix3fv(normalMatrixLoc, 1, GL_FALSE, glm::value_ptr(normalMatrix)); 
    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); 
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); 
    glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); 

    glBindVertexArray(m_cubeVAO); 
    glDrawArrays(GL_TRIANGLES, 0, 36); 
    glBindVertexArray(0); 

    // Draw light 
    m_lightShader->useShaderProgram(); 

    model = glm::mat4(); 
    model = glm::translate(model, m_lightPos); 
    model = glm::scale(model, glm::vec3(0.2f)); 
    modelLoc = glGetUniformLocation(m_lightShader->getId(), "model"); 
    viewLoc = glGetUniformLocation(m_lightShader->getId(), "view"); 
    projectionLoc = glGetUniformLocation(m_lightShader->getId(), "projection"); 
    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); 
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); 
    glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); 

    glBindVertexArray(m_lightVAO); 
    glDrawArrays(GL_TRIANGLES, 0, 36); 
    glBindVertexArray(0); 

Я попытался выполнить вычисления в пространстве просмотра, но это не сработает. Я попытался изменить/нормализовать/использовать max() вместо clamp(), но через несколько часов по этой проблеме. У меня нет никаких идей.

+0

где ваш объект определен, где он центрирован? – Guiroux

+0

Он определяет в функции initializeGL (вершины и нормаль) и использует VAO и VBO. Он сосредоточен на происхождении (0,0,0). В источниках на github это файл renderer.cpp – Zethzer

+0

У меня нет фразы «есть отражение за объектом», что вы называете? поскольку свет и зритель являются одной и той же стороной объекта (как положительные позиции по сравнению с нулевым положением для куба на оси z), как вы можете видеть «за»? – Guiroux

ответ

1

У вас есть только рассеянный и зеркальный свет, если lightDir (направление от фрагмента к свету) находится в направлении norm (нормальный вектор фрагмента). Если они направлены против вас, вы можете обойтись без диффузного и зеркального света. Другими словами, если это не какой-либо диффузный свет (потому что diff - 0.0), то и никакого зеркального света тоже нет. Адаптируйте свой код следующим образом:

void main() 
{ 
    // Vectors 
    vec3 norm = normalize(Normal); 
    vec3 lightDir = normalize(light.position - FragPos); 
    vec3 viewDir = normalize(viewPos - FragPos); 
    vec3 reflectDir = reflect(-lightDir, norm); 

    // Ambient 
    vec3 ambient = material.ambient * light.ambient; 

    vec3 result = ambient; 
    float dotNvLd = dot(norm, lightDir); 
    if (dotNvLd > 0.0) // test if normal vector not directed against vector to light position 
    { 
     // Diffuse 
     float diff = min(dotNvLd, 1.0); 
     vec3 diffuse = diff * material.diffuse * light.diffuse; 

     // Specular - The bug seems only here 
     float spec = pow(clamp(dot(viewDir, reflectDir), 0.0, 1.0), material.shininess); 
     vec3 specular = spec * material.specular * light.specular; 

     result = (diffuse + specular + ambient); 
    } 

    color = vec4(result, 1.0f); 

    // For test vectors 
    //color = vec4(specular, 1.0f); 
} 
+0

Спасибо за ваш ответ, но я не понимаю, почему – Zethzer

+0

@Zethzer Если 'lightDir' направлен в соответствии с« нормой », фрагмент освещен на обратной стороне, так что вы не может видеть свет на лицевой стороне. – Rabbid76

Смежные вопросы