[OpenGL]颜色和基础光照

颜色

物体

#Shader Fragment
#version 330 core

out vec4 fragColor;

uniform vec3 u_LightColor;
uniform vec3 u_ObjectColor;

void main()
{
    fragColor = vec4(u_LightColor * u_ObjectColor, 1.0);
}
m_Shader[0]->SetUniform3f("u_LightColor", 1.0f, 1.0f, 1.0f);
m_Shader[0]->SetUniform3f("u_ObjectColor", 1.0f, 0.5f, 0.31f);

 

这里为物体和灯光设置了设置一个固定的颜色

灯光

fragColor = vec4(1.0f);

 

这里直接为灯光设置一个固定的白色

可以看到珊瑚红的物体与白色的灯光调制后依然是珊瑚红。

 

环境光:即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。

环境光
class Ambient : public SubTestBed
{
protected:
    ::BaseCamera* m_Camera;
    glm::mat4 m_Model = glm::identity<glm::mat4>();
    glm::vec3 m_LightPos = glm::vec3(1.2f, 1.0f, 2.0f);

    ImVec4 m_LightColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
    float m_AmbientStrenth = 1.0f;

    std::string m_CubeShader = "SandBox/09_Light/Ambient.shader";
public:
    virtual void Setup() override
    {
#pragma region vertices
        float vertices[] = {
            -0.5f, -0.5f, -0.5f,
             0.5f, -0.5f, -0.5f,
             0.5f,  0.5f, -0.5f,
             0.5f,  0.5f, -0.5f,
            -0.5f,  0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,

            -0.5f, -0.5f,  0.5f,
             0.5f, -0.5f,  0.5f,
             0.5f,  0.5f,  0.5f,
             0.5f,  0.5f,  0.5f,
            -0.5f,  0.5f,  0.5f,
            -0.5f, -0.5f,  0.5f,

            -0.5f,  0.5f,  0.5f,
            -0.5f,  0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,
            -0.5f, -0.5f,  0.5f,
            -0.5f,  0.5f,  0.5f,

             0.5f,  0.5f,  0.5f,
             0.5f,  0.5f, -0.5f,
             0.5f, -0.5f, -0.5f,
             0.5f, -0.5f, -0.5f,
             0.5f, -0.5f,  0.5f,
             0.5f,  0.5f,  0.5f,

            -0.5f, -0.5f, -0.5f,
             0.5f, -0.5f, -0.5f,
             0.5f, -0.5f,  0.5f,
             0.5f, -0.5f,  0.5f,
            -0.5f, -0.5f,  0.5f,
            -0.5f, -0.5f, -0.5f,

            -0.5f,  0.5f, -0.5f,
             0.5f,  0.5f, -0.5f,
             0.5f,  0.5f,  0.5f,
             0.5f,  0.5f,  0.5f,
            -0.5f,  0.5f,  0.5f,
            -0.5f,  0.5f, -0.5f
        };
#pragma endregion
        m_VA[0] = new VertexArray();
        m_VB[0] = new VertexBuffer(vertices, sizeof(vertices));
        VertexBufferLayout layout;
        layout.Push<float>(3);
        m_VA[0]->AddBuffer(*m_VB[0], layout);

        if (!m_TestScene)
        {
            TestScene::CameraData data;
            data.eye = glm::vec3(-1.2f, 3.6f, 2.5f);
            data.at = glm::vec3(1.5f, 0.3f, -1.6f);
            data.up = glm::vec3(0.0f, 1.0f, 0.0f);
            data.fov = 60.0f;
            data.nearClip = 0.1f;
            data.farClip = 100.0f;
            m_TestScene = new TestScene(TestScene::FIXED_CAMERA, data, TestScene::TT_DARK);
            m_Camera = (::FixedCamera*)m_TestScene->Camera();
        }

        m_Model = glm::identity<glm::mat4>();

        m_TestScene->Setup();
        m_Shader[0] = new Shader(m_CubeShader);
        m_Shader[0]->Bind();
        m_Shader[0]->SetUniformMat4f("u_Model", m_Model);

        // 画表示光源的箱子
        m_VA[1] = new VertexArray();
        m_VB[1] = new VertexBuffer(vertices, sizeof(vertices));
        layout.Clear();
        layout.Push<float>(3);
        m_VA[1]->AddBuffer(*m_VB[1], layout);
        m_Shader[1] = new Shader("SandBox/09_Light/Light.shader");
        m_Shader[1]->Bind();
        m_Model = glm::translate(m_Model, m_LightPos);
        m_Model = glm::scale(m_Model, glm::vec3(0.2f));
        m_Shader[1]->SetUniformMat4f("u_Model", m_Model);

        m_VB[0]->UnBind();
        m_VA[0]->UnBind();
        m_VB[1]->UnBind();
        m_VA[1]->UnBind();
    }

    virtual void Clear() override
    {
        m_Renderer.Clear();
    }

    virtual void Update(float deltaTime) override
    {
        m_TestScene->Update(deltaTime);
    }

    virtual void Render() override
    {
        m_TestScene->Render();

        this->m_Renderer.Draw(m_VA[0], 36, m_Shader[0]);
        m_Shader[0]->SetUniformMat4f("u_Projection", m_Camera->GetProjectionMatrix());
        m_Shader[0]->SetUniformMat4f("u_View", m_Camera->GetViewMatrix());
        m_Shader[0]->SetUniform1f("u_AmbientStrenth", m_AmbientStrenth);
        m_Shader[0]->SetUniform3f("u_LightColor", m_LightColor.x, m_LightColor.y, m_LightColor.z);
        m_Shader[0]->SetUniform3f("u_ObjectColor", 1.0f, 0.5f, 0.31f);

        this->m_Renderer.Draw(m_VA[1], 36, m_Shader[1]);
        m_Shader[1]->SetUniformMat4f("u_Projection", m_Camera->GetProjectionMatrix());
        m_Shader[1]->SetUniformMat4f("u_View", m_Camera->GetViewMatrix());
        m_Shader[1]->SetUniform3f("u_LightColor", m_LightColor.x, m_LightColor.y, m_LightColor.z);
    }

    virtual void OnGUI() override
    {
        ImGui::Begin("LightTest");
        {
            ImGui::SliderFloat("AmbientStrenth", &m_AmbientStrenth, 0.0f, 1.0f);
            ImGui::ColorEdit3("Light Color", (float*)&m_LightColor);
        }
        ImGui::End();
    }
};

// 物体Shader

#Shader Vertex
#version 330 core
layout(location = 0) in vec4 a_position;

uniform mat4 u_Model;
uniform mat4 u_View;
uniform mat4 u_Projection;

void main()
{
    gl_Position = u_Projection * u_View * u_Model * vec4(a_position.x, a_position.y + 1.0, a_position.z, 1.0);
}

#Shader Fragment
#version 330 core

out vec4 fragColor;

uniform float u_AmbientStrenth;
uniform vec3 u_LightColor;
uniform vec3 u_ObjectColor;

void main()
{
    vec3 ambient = u_LightColor * u_AmbientStrenth;
    vec3 result = u_ObjectColor * ambient;
    fragColor = vec4(result, 1.0);
}

// 灯光Shader

// vertex Shader同上

#Shader Fragment
#version 330 core

out vec4 fragColor;

uniform vec3 u_LightColor;

void main()
{
    fragColor = vec4(u_LightColor, 1.0f);
}

 

漫反射
class Diffuse : public Ambient
{
public:
    Diffuse()
    {
        m_CubeShader = "SandBox/09_Light/Diffuse.shader";
    }

    virtual void Setup() override
    {
#pragma region vertices
        float vertices[] = {
            -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
             0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
             0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
             0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
            -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
            -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

            -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
             0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
             0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
             0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
            -0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
            -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

            -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
            -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
            -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
            -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
            -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
            -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,

             0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
             0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
             0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
             0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
             0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
             0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,

            -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
             0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
             0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
             0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
            -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
            -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,

            -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
             0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
             0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
             0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
            -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
            -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f
        };
#pragma endregion
        m_VA[0] = new VertexArray();
        m_VB[0] = new VertexBuffer(vertices, sizeof(vertices));
        VertexBufferLayout layout;
        layout.Push<float>(3);
        layout.Push<float>(3);
        m_VA[0]->AddBuffer(*m_VB[0], layout);

        if (!m_TestScene)
        {
            TestScene::CameraData data;
            data.eye = glm::vec3(-1.2f, 3.6f, 2.5f);
            data.at = glm::vec3(1.5f, 0.3f, -1.6f);
            data.up = glm::vec3(0.0f, 1.0f, 0.0f);
            data.fov = 60.0f;
            data.nearClip = 0.1f;
            data.farClip = 100.0f;
            m_TestScene = new TestScene(TestScene::FIXED_CAMERA, data, TestScene::TT_DARK);
            m_Camera = (::FixedCamera*)m_TestScene->Camera();
        }

        m_Model = glm::identity<glm::mat4>();

        m_TestScene->Setup();
        m_Shader[0] = new Shader(m_CubeShader);
        m_Shader[0]->Bind();
        m_Shader[0]->SetUniformMat4f("u_Model", m_Model);
        m_Shader[0]->SetUniform3f("u_LightPos", m_LightPos.x, m_LightPos.y, m_LightPos.z);

        // 画表示光源的箱子
        m_VA[1] = new VertexArray();
        m_VB[1] = new VertexBuffer(vertices, sizeof(vertices));
        layout.Clear();
        layout.Push<float>(3);
        layout.Push<float>(3);
        m_VA[1]->AddBuffer(*m_VB[1], layout);
        m_Shader[1] = new Shader("SandBox/09_Light/Light.shader");

        m_VB[0]->UnBind();
        m_VA[0]->UnBind();
        m_VB[1]->UnBind();
        m_VA[1]->UnBind();
    }

    virtual void Render() override
    {
        Ambient::Render();

        m_Shader[0]->Bind();
        m_Shader[0]->SetUniform3f("u_LightPos", m_LightPos.x, m_LightPos.y, m_LightPos.z);

        m_Shader[1]->Bind();
        m_Model = glm::identity<glm::mat4>();
        m_Model = glm::translate(m_Model, m_LightPos);
        m_Model = glm::scale(m_Model, glm::vec3(0.2f));
        m_Shader[1]->SetUniformMat4f("u_Model", m_Model);
    }

    virtual void OnGUI() override
    {
        ImGui::Begin("LightTest");
        {
            ImGui::SliderFloat("AmbientStrenth", &m_AmbientStrenth, 0.0f, 1.0f);
            ImGui::ColorEdit3("Light Color", (float*)&m_LightColor);
            ImGui::SliderFloat3("Light Pos", (float*)&m_LightPos, -3.0f, 3.0f);
        }
        ImGui::End();
    }
};

// 物体Shader

#Shader Vertex
#version 330 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;

uniform mat4 u_Model;
uniform mat4 u_View;
uniform mat4 u_Projection;

out vec3 v3_Normal;
out vec3 v3_WorldPos;

void main()
{
    vec3 vertexPosition = a_position + vec3(0.0, 1.0, 0.0);
    gl_Position = u_Projection * u_View * u_Model * vec4(vertexPosition, 1.0);
    v3_WorldPos = vec3(u_Model * vec4(vertexPosition, 1.0));  // 将物体本地坐标转换到世界坐标
    // 要把法线转到世界坐标下,法线矩阵 = 模型矩阵左上角的逆矩阵的转置矩阵
    // 如果不这样操作,当模型进行不等比缩放的时候,光照就会出现问题。
    v3_Normal = mat3(transpose(inverse(u_Model))) * a_normal;
}


#Shader Fragment
#version 330 core

out vec4 fragColor;

in vec3 v3_Normal;
in vec3 v3_WorldPos;

uniform float u_AmbientStrenth;
uniform vec3 u_LightColor;
uniform vec3 u_ObjectColor;

uniform vec3 u_LightPos;

void main()
{
    // 计算环境光
    vec3 ambient = u_LightColor * u_AmbientStrenth;

    // 计算漫反射 结果色彩 = 光线色彩 * cosθ   θ = 顶点法线和光照方向的夹角
    vec3 N = normalize(v3_Normal);  // 单位化顶点法线
    vec3 lightDir = normalize(u_LightPos - v3_WorldPos);  // 计算顶点法线和光照方向的夹角
    vec3 diffuse = u_LightColor * max(dot(N, lightDir), 0.0);

    vec3 result = (ambient + diffuse) * u_ObjectColor;
    fragColor = vec4(result, 1.0);
}

 

镜面反射/高光反射
class Specular : public Diffuse
{
    float m_SpecularStrength = 0.5f;
public:
    Specular()
    {
        m_CubeShader = "SandBox/09_Light/Specular.shader";
    }

    virtual void Setup() override
    {
        Diffuse::Setup();
        TestScene::CameraData data;
        data.eye = glm::vec3(-1.2f, 3.6f, 2.5f);
        data.at = glm::vec3(1.5f, 0.3f, -1.6f);
        data.up = glm::vec3(0.0f, 1.0f, 0.0f);
        data.fov = 60.0f;
        data.nearClip = 0.1f;
        data.farClip = 100.0f;

        m_TestScene = new TestScene(TestScene::FREE_CAMERA, data, TestScene::TT_DARK);
        m_TestScene->Setup();
        m_Camera = (::FreeCamera*)m_TestScene->Camera();
    }

    virtual void Update(float dt) override
    {
        m_TestScene->Update(dt);
    }

    virtual void Render() override
    {
        Diffuse::Render();
        m_Shader[0]->Bind();
        m_Shader[0]->SetUniform3f("u_ViewPos", m_Camera->GetEye().x, m_Camera->GetEye().y, m_Camera->GetEye().z);
        m_Shader[0]->SetUniform1f("u_SpecularStrength", m_SpecularStrength);
    }

    virtual void OnGUI() override
    {
        ImGui::Begin("LightTest");
        {
            ImGui::SliderFloat("AmbientStrenth", &m_AmbientStrenth, 0.0f, 1.0f);
            ImGui::SliderFloat("SpecularStrength", &m_SpecularStrength, 0.0f, 1.0f);
            ImGui::ColorEdit3("Light Color", (float*)&m_LightColor);
            ImGui::SliderFloat3("Light Pos", (float*)&m_LightPos, -3.0f, 3.0f);
        }
        ImGui::End();
    }
};
// vertex shader同上
#Shader Fragment
#version 330 core

out vec4 fragColor;

in vec3 v3_Normal;
in vec3 v3_WorldPos;

uniform float u_AmbientStrenth;
uniform vec3 u_LightColor;
uniform vec3 u_ObjectColor;

uniform vec3 u_LightPos;
uniform vec3 u_ViewPos;

uniform float u_SpecularStrength;

void main()
{
    // 计算环境光
    vec3 ambient = u_LightColor * u_AmbientStrenth;

    // 计算漫反射 结果色彩 = 光线色彩 * cosθ   θ = 顶点法线和光照方向的夹角
    vec3 N = normalize(v3_Normal);  // 单位化顶点法线
    vec3 lightDir = normalize(u_LightPos - v3_WorldPos);  // 计算顶点法线和光照方向的夹角
    vec3 diffuse = u_LightColor * max(dot(N, lightDir), 0.0);

    // 计算镜面反射 结果色彩 = 光线色彩 * (cosθ) ^ g
    vec3 viewDir = normalize(u_ViewPos - v3_WorldPos);   // 计算观察方向
    vec3 reflectDir = reflect(-lightDir, N); // 计算反射光线
    float spec = pow(max(dot(reflectDir, viewDir), 0.0), 32); // (cosθ) ^ g
    vec3 specular = u_LightColor * spec * u_SpecularStrength;

    vec3 result = (ambient + diffuse + specular) * u_ObjectColor;
    fragColor = vec4(result, 1.0);
}

镜面反射

 

练习题3: 在观察空间(而不是世界空间)中计算冯氏光照
// vert  需要把顶点坐标,顶点法线和灯光位置都转换到观察空间
v3_WorldPos = vec3(u_View * u_Model * vec4(vertexPosition, 1.0)); // 把本地坐标转换到观察空间坐标,这里worldPos取名有点不准确
v3_Normal = mat3(transpose(inverse(u_View * u_Model))) * a_normal; // 也要把顶点法线转到观察空间
v3_LightPos = vec3(u_View * vec4(u_LightPos, 1.0)); // 把灯光的世界坐标转换到观察空间坐标

// frag
#Shader Fragment
#version 330 core

out vec4 fragColor;

in vec3 v3_Normal;
in vec3 v3_WorldPos;
in vec3 v3_LightPos;

uniform float u_AmbientStrenth;
uniform vec3 u_LightColor;
uniform vec3 u_ObjectColor;


uniform float u_SpecularStrength;

void main()
{
    vec3 ambient = u_LightColor * u_AmbientStrenth;

    vec3 N = normalize(v3_Normal);
    vec3 lightDir = normalize(v3_LightPos - v3_WorldPos);
    vec3 diffuse = u_LightColor * max(dot(N, lightDir), 0.0);

    vec3 viewDir = normalize(-v3_WorldPos); // 因为在观察空间下 viewPos 始终为(0,0,0)
    vec3 reflectDir = reflect(-lightDir, N);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = u_LightColor * spec * u_SpecularStrength;

    vec3 result = (ambient + diffuse + specular) * u_ObjectColor;
    fragColor = vec4(result, 1.0);
}

观察空间计算光照

可以看到效果几乎和在世界空间中计算差不多,在观察空间计算光照的好处就是无需通过uniform给着色器传递viewPos了,因为在观察空间中 viewPos始终为 零向量

 

练习题4: 尝试实现一个Gouraud着色(而不是冯氏着色)
#Shader Vertex
#version 330 core
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec3 a_normal;

uniform mat4 u_Model;
uniform mat4 u_View;
uniform mat4 u_Projection;
uniform vec3 u_LightPos;

uniform float u_AmbientStrenth;
uniform vec3 u_LightColor;

uniform vec3 u_ViewPos;
uniform float u_SpecularStrength;

out vec3 v3_LightingColor;

void main()
{
    vec3 vertexPosition = a_position + vec3(0.0, 1.0, 0.0);
    gl_Position = u_Projection * u_View * u_Model * vec4(vertexPosition, 1.0);
    vec3 v3_WorldPos = vec3(u_Model * vec4(vertexPosition, 1.0));  // 顶点是世界坐标
    vec3 v3_Normal = mat3(transpose(inverse(u_Model))) * a_normal;  //顶点法线是世界坐标
    // 灯光本身就是世界坐标


    // 计算环境光
    vec3 ambient = u_LightColor * u_AmbientStrenth;

    // 计算漫反射 结果色彩 = 光线色彩 * cosθ   θ = 顶点法线和光照方向的夹角
    vec3 N = normalize(v3_Normal);  // 单位化顶点法线
    vec3 lightDir = normalize(u_LightPos - v3_WorldPos);  // 计算顶点法线和光照方向的夹角
    vec3 diffuse = u_LightColor * max(dot(N, lightDir), 0.0);

    // 计算镜面反射 结果色彩 = 光线色彩 * (cosθ) ^ g
    vec3 viewDir = normalize(u_ViewPos - v3_WorldPos);   // 计算观察方向
    vec3 reflectDir = reflect(-lightDir, N); // 计算反射光线
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); // (cosθ) ^ g
    vec3 specular = u_LightColor * spec * u_SpecularStrength;

    v3_LightingColor = ambient + diffuse + specular;
}


#Shader Fragment
#version 330 core

out vec4 fragColor;

uniform vec3 u_ObjectColor;

in vec3 v3_LightingColor;

void main()
{
    fragColor = vec4(v3_LightingColor * u_ObjectColor, 1.0);
}

GourandShading

可以看到 Gourand着色,在三角形的交接处有明显的边界。因为光照的颜色都在顶点着色器计算,片元中的其它颜色都是通过片元着色器差值计算出来的。

 

 

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像