镜面反射不正确

Zet*_*zer 5 c++ opengl qt glsl light

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

问题的图像

在这里,我们正对着物体,但相机和灯光都在前面。正如我们所看到的,物体后面有一个反射。

为了描述实际参数,所有计算都是在世界空间中进行的(通常......对于这个问题,我有疑问)。我将相机放在位置 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;
}
Run Code Online (Sandbox Code Playgroud)

还有我的片段着色器:

#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);
}
Run Code Online (Sandbox Code Playgroud)

游戏循环中的代码(实时绘制GL,时间间隔为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);
Run Code Online (Sandbox Code Playgroud)

我尝试对视图空间进行计算,但它不起作用。我尝试修改/规范化/使用 max() 而不是钳制(),但在问题上几个小时后。我没有任何想法。

Rab*_*d76 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);
}
Run Code Online (Sandbox Code Playgroud)