美文网首页
OpenGL学习10——材质

OpenGL学习10——材质

作者: 蓬篙人 | 来源:发表于2021-06-24 06:24 被阅读0次
    • 现实世界中,不同材质的物体对光的反应是不一样的,如钢材质比起木材质会更亮。在OpenGL中,想模拟不同物体的类型,我们需要给不同的渲染表面指定不同的材质(material)属性
    • 要描述渲染表面的材质,我们可以为光照的3个分量(环境光、扩散光和镜面光)分别定义一个材质颜色,并添加一个亮度值来控制这3个颜色,这就构成了我们需要的物体的材质属性。
    // Material结构存储表面的材质属性
    struct Material{
        vec3 ambient;
        vec3 diffuse;
        vec3 specular;
        float shininess;
    };
    
    uniform Material material;
    
    1. `ambient`材质矢量:定义表面在环境光下的反射的颜色,一般就是表面的颜色。
    2. `diffuse`材质矢量:定义表面在扩散光下的反射的颜色。一般设置为表面想要的颜色。
    3. `specular`材质矢量:设置镜面光斑在表面上的颜色。
    4. `shininess`:影响镜面光斑的扩散/直径。
    
    • 使用上述四个分量定义的物体材质,我们可以模拟现实世界中对应的材料。下面是一些材质属性的光照效果:(图片取自书中
      不同材质光照效果

    1. 设置材质

    • 根据上面定义的材质结构,我们修改片元着色器中的光源计算:
    void main()
    {
        // ambient
        vec3 ambient = lightColor * material.ambient;
        // diffuse
        vec3 norm = normalize(Normal);
        vec3 lightDir = normalize(lightPos - FragPos);
        float diff = max(dot(norm, lightDir), 0.0);
        vec3 diffuse = lightColor * (diff * material.diffuse);
        // specular
        vec3 viewDir = normalize(viewPos - FragPos);
        vec3 reflectDir = reflect(-lightDir, norm);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
        vec3 specular = lightColor * (spec * material.specular);
    
        vec3 result = ambient + diffuse + specular;
        FragColor = vec4(result, 1.0);
    }
    
    • 在程序中设置材质属性:
    objectShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);
    objectShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
    objectShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
    objectShader.setFloat("material.shininess", 32.0f);
    
    • 注意:GLSL中的结构其实只是充当uniform变量的命名空间。
    • 渲染效果


      材质渲染效果

    2. 光属性

    • 上面的渲染效果,让我们感觉太明亮了,那是因为我们没对光的强度做任何处理。如果我们的光颜色是vec3(1.0),那么我们光源计算的代码看起来是这样的:
    vec3 ambient = vec3(1.0) * material.ambient;
    vec3 diffuse = vec3(1.0) * (diff * material.diffuse);
    vec3 specular = vec3(1.0) * (spec * material.specular);
    
    • 要对光的强度做处理,我们可以像上一章基本光照那样,给各个光分量设定一个强度值(strength value),来控制光不同分量的影响。
    • 下面我们也像对待物体材质那样,创建一个结构来描述光的属性,从而实现对光不同分量的控制。下面我们在片元着色器中添加光属性的结构:
    struct Light{
        vec3 position;
        vec3 ambient;
        vec3 diffuse;
        vec3 specular;
    };
    
    uniform Light light;
    
    • 根据光属性重新计算各个分量的值:
    // ambient
    vec3 ambient = light.ambient * material.ambient;
    // diffuse
    vec3 diffuse = light.diffuse * (diff * material.diffuse);
    // specular
    vec3 specular = light.specular * (spec * material.specular);
    
    • 一般情况下,我们将环境光的强度设置得低一点,避免环境光对场景造成过大影响。扩散光则一般设置为我们需要的光源的颜色。而镜面光则保持为vec3(1.0)。下面我们在代码中设置光属性的值:
    objectShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f);
    objectShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f);  // 偏暗
    objectShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
    
    • 渲染效果


      光属性渲染效果

    3. 不同的光颜色

    • 看看前面我们光颜色值的设置可以知道,我们只是在灰(含白)到黑之间选择光的颜色,这样的光并不会影响物体实际的颜色,只会影响物体显示的强度。下面我们让光的颜色随时间变化,看看立方体渲染出来的效果。下面是环境光和扩散光的设置代码(镜面光保持不变):
    // 光的颜色
    glm::vec3 lightColor;
    lightColor.x = sin(glfwGetTime() * 2.0f);
    lightColor.y = sin(glfwGetTime() * 0.7f);
    lightColor.z = sin(glfwGetTime() * 1.3f);
    // 扩散光分量
    glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
    // 环境光分量
    glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f);
    // 设置到片元着色器中
    objectShader.setVec3("light.ambient", ambientColor);
    objectShader.setVec3("light.diffuse", diffuseColor);
    
    • 下面是随时间变化的一些渲染效果


      光颜色渲染1
    光颜色渲染2 光颜色渲染3

    相关文章

      网友评论

          本文标题:OpenGL学习10——材质

          本文链接:https://www.haomeiwen.com/subject/gcxwyltx.html