镜面反射不正确

时间:2016-02-03 10:52:40

标签: c++ qt opengl glsl light

我正在尝试为我的硕士学位(以及我的技能)制作一个小型3D引擎。我对镜面反射有问题。 (我很抱歉插图图片的链接,但我还没有足够的声誉)。我的GitHub上提供了所有来源:DWRenderer

Image of the problem

就在这里,我们正在拍摄物体,但相机在前面也是灯光。我们可以看到,对象背后有一个反映。

为了描述实际参数,所有计算都是在世界空间中进行的(通常......有了这个问题,我有点怀疑)。我把相机放在vec3(0,0,3)的位置进行测试,光线只是vec3(1.2,1,2)的一个点,用立方体表示。我在Ubuntu下使用Qt 5.4和OpenGL 4.1和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的实时间隔为16ms)用于初始化统一变量(着色器的摄像机位置是固定的,我可以转动我的立方体进行检查错误。灯光的位置在“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(),但问题几个小时后。我没有任何想法。

1 个答案:

答案 0 :(得分:1)

如果lightDir(从片段到光的方向)在norm方向(片段的法线向量),则只有漫反射光和镜面反射光。如果他们针对你,你可以做没有漫反射和镜面光。换句话说,如果不是任何漫射光(因为diff0.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);
}