多光源(定向光、点光源、聚光灯)

 

  前篇学习了单个的光源,现在在一个场景中放置多个不同的光源,包括一个定向光源、4个点光源、一个聚光灯。

  

  GLSL代码如下(片段着色器):

#version 430 core
out vec4 color;

in VS_OUT{
    vec3 FragPos;
    vec3 Normal;
    vec2 TexCoords;
}vs_in;

struct Material{
    sampler2D diffuse;
    sampler2D specular;
    float shininess;
};

struct DirLight{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;

    vec3 direction;
};

struct PointLight{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;

    float constant;
    float linear;
    float quadratic;
    
    vec3 position;
};

struct SpotLight{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;

    float constant;
    float linear;
    float quadratic;
    
    vec3 position;
    vec3 direction;
    float cutOff;
    float outerCutOff;
};
#define NR_POINT_LIGHTS 4
uniform Material material;
uniform DirLight dirLight;
uniform PointLight pointLights[NR_POINT_LIGHTS];
uniform SpotLight spotLight;
uniform vec3 viewPos;

vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
    vec3 lightDir=normalize(-light.direction);

    vec3 ambient=light.ambient * vec3(texture(material.diffuse, vs_in.TexCoords));
    
    float diff=max(dot(normal,lightDir),0.0f);
    vec3 diffuse=light.diffuse * diff * vec3(texture(material.diffuse, vs_in.TexCoords));
    
    vec3 reflectDir=reflect(-lightDir,normal);
    float spec=pow(max(dot(viewDir,reflectDir),0.0f),material.shininess);
    vec3 specular=light.specular * spec * vec3(texture(material.specular, vs_in.TexCoords));

    return (ambient+diffuse+specular);
}

vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
    vec3 lightDir = normalize(light.position - fragPos);
    // 漫反射着色
    float diff = max(dot(normal, lightDir), 0.0);
    // 镜面光着色
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    // 衰减
    float distance    = length(light.position - fragPos);
    float attenuation = 1.0 / (light.constant + light.linear * distance + 
                 light.quadratic * (distance * distance));    
    // 合并结果
    vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, vs_in.TexCoords));
    vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, vs_in.TexCoords));
    vec3 specular = light.specular * spec * vec3(texture(material.specular, vs_in.TexCoords));
    ambient  *= attenuation;
    diffuse  *= attenuation;
    specular *= attenuation;
    return (ambient + diffuse + specular);
}

vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
    vec3 lightDir = normalize(light.position - fragPos);
    // 漫反射着色
    float diff = max(dot(normal, lightDir), 0.0);
    // 镜面光着色
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    // 衰减
    float distance    = length(light.position - fragPos);
    float attenuation = 1.0 / (light.constant + light.linear * distance + 
                 light.quadratic * (distance * distance));    
    // 合并结果
    vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, vs_in.TexCoords));
    vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, vs_in.TexCoords));
    vec3 specular = light.specular * spec * vec3(texture(material.specular, vs_in.TexCoords));
    //ambient  *= attenuation;
    //diffuse  *= attenuation;
    //specular *= attenuation;

    float theta=dot(lightDir,normalize(-light.direction));
    float epsilon=light.cutOff-light.outerCutOff;
    float intensity=clamp((theta-light.outerCutOff)/epsilon,0.0,1.0);

    ambient*=intensity;
    diffuse*=intensity;
    specular*=intensity;
    return (ambient + diffuse + specular);
}


void main()
{
    vec3 norm=normalize(vs_in.Normal);
    vec3 viewDir=normalize(viewPos-vs_in.FragPos);

    //定向光
    vec3 result=CalcDirLight(dirLight, norm, viewDir);
    //点光源
    for(int i=0;i<NR_POINT_LIGHTS;i++){
        result+=CalcPointLight(pointLights[i], norm, vs_in.FragPos, viewDir);
    }
    //聚光灯
    result+=CalcSpotLight(spotLight, norm, vs_in.FragPos, viewDir);

    color=vec4(result,1.0f);
}

  

  渲染代码如下:

void SceneRendering::CubeRendering() {
    //update uniform buffer
    cube->setViewMat(phc->getViewMatrix());
    cube->setProjectionMat(phc->getProjectionMatrix());
    shader_multiLights->use();

    shader_multiLights->setInt("material.diffuse", 0);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, container);
    shader_multiLights->setInt("material.specular", 1);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, container_specular);
    shader_multiLights->setFloat("material.shininess", 500);
    shader_multiLights->setVec3("viewPos", phc->getPos());

    glm::vec3 pointLightPositions[] = {
        glm::vec3(0.7f,  0.2f,  2.0f),
        glm::vec3(2.3f, -3.3f, -4.0f),
        glm::vec3(-4.0f,  2.0f, -12.0f),
        glm::vec3(0.0f,  0.0f, -3.0f)
    };
    glm::vec3 pointLightColors[] = {
        glm::vec3(1.0f, 0.6f, 0.0f),
        glm::vec3(1.0f, 0.0f, 0.0f),
        glm::vec3(0.0f, 1.0, 0.0),
        glm::vec3(0.2f, 0.2f, 1.0f)
    };
    // Directional light
    shader_multiLights->setVec3("dirLight.direction", -0.2f, -1.0f, -0.3f);
    shader_multiLights->setVec3("dirLight.ambient", 0.3f, 0.24f, 0.14f);
    shader_multiLights->setVec3("dirLight.diffuse", 0.7f, 0.42f, 0.26f);
    shader_multiLights->setVec3("dirLight.specular", 0.5f, 0.5f, 0.5f);
    // Point light 1
    shader_multiLights->setVec3("pointLights[0].position", pointLightPositions[0].x, pointLightPositions[0].y, pointLightPositions[0].z);
    shader_multiLights->setVec3("pointLights[0].ambient", pointLightColors[0].x * 0.1, pointLightColors[0].y * 0.1, pointLightColors[0].z * 0.1);
    shader_multiLights->setVec3("pointLights[0].diffuse", pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z);
    shader_multiLights->setVec3("pointLights[0].specular", pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z);
    shader_multiLights->setFloat("pointLights[0].constant", 1.0f);
    shader_multiLights->setFloat("pointLights[0].linear", 0.09f);
    shader_multiLights->setFloat("pointLights[0].quadratic", 0.032f);
    // Point light 2
    shader_multiLights->setVec3("pointLights[1].position", pointLightPositions[1].x, pointLightPositions[1].y, pointLightPositions[1].z);
    shader_multiLights->setVec3("pointLights[1].ambient", pointLightColors[1].x * 0.1, pointLightColors[1].y * 0.1, pointLightColors[1].z * 0.1);
    shader_multiLights->setVec3("pointLights[1].diffuse", pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z);
    shader_multiLights->setVec3("pointLights[1].specular", pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z);
    shader_multiLights->setFloat("pointLights[1].constant", 1.0f);
    shader_multiLights->setFloat("pointLights[1].linear", 0.09f);
    shader_multiLights->setFloat("pointLights[1].quadratic", 0.032f);
    // Point light 3
    shader_multiLights->setVec3("pointLights[2].position", pointLightPositions[2].x, pointLightPositions[2].y, pointLightPositions[2].z);
    shader_multiLights->setVec3("pointLights[2].ambient", pointLightColors[2].x * 0.1, pointLightColors[2].y * 0.1, pointLightColors[2].z * 0.1);
    shader_multiLights->setVec3("pointLights[2].diffuse", pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z);
    shader_multiLights->setVec3("pointLights[2].specular", pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z);
    shader_multiLights->setFloat("pointLights[2].constant", 1.0f);
    shader_multiLights->setFloat("pointLights[2].linear", 0.09f);
    shader_multiLights->setFloat("pointLights[2].quadratic", 0.032f);
    // Point light 4
    shader_multiLights->setVec3("pointLights[3].position", pointLightPositions[3].x, pointLightPositions[3].y, pointLightPositions[3].z);
    shader_multiLights->setVec3("pointLights[3].ambient", pointLightColors[3].x * 0.1, pointLightColors[3].y * 0.1, pointLightColors[3].z * 0.1);
    shader_multiLights->setVec3("pointLights[3].diffuse", pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z);
    shader_multiLights->setVec3("pointLights[3].specular", pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z);
    shader_multiLights->setFloat("pointLights[3].constant", 1.0f);
    shader_multiLights->setFloat("pointLights[3].linear", 0.9f);
    shader_multiLights->setFloat("pointLights[3].quadratic", 0.032f);
    // Spot light
    shader_multiLights->setVec3("spotLight.position", phc->getPos());
    shader_multiLights->setVec3("spotLight.direction", phc->GetForwardVec());
    shader_multiLights->setVec3("spotLight.ambient", 0.0f, 0.0f, 0.0f);
    shader_multiLights->setVec3("spotLight.diffuse", 1.0f, 1.0f, 0.0f);
    shader_multiLights->setVec3("spotLight.specular", 1.0f, 1.0f, 0.0f);
    shader_multiLights->setFloat("spotLight.constant", 1.0f);
    shader_multiLights->setFloat("spotLight.linear", 0.9f);
    shader_multiLights->setFloat("spotLight.quadratic", 0.032f);
    shader_multiLights->setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f)));
    shader_multiLights->setFloat("spotLight.outerCutOff", glm::cos(glm::radians(14.5f)));


    // draw cubes
    for (unsigned int i = 0; i < 10; i++)
    {
        glm::mat4 model;
        model = glm::scale(model, glm::vec3(5));
        model = glm::translate(model, cube->cubePositions[i]);
        float angle = 20.0f * i;
        model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
        shader_multiLights->setMat4("model", model);
        cube->DrawCube();
    }
}

  

  效果图:

  1、定向光+点光源

  

  2、定向光+点光源+聚光灯(软影)

  

  

  

posted @ 2019-10-05 19:16  茶飘香~  阅读(...)  评论(...编辑  收藏