美文网首页
LearnOpenGL 光照贴图

LearnOpenGL 光照贴图

作者: li_礼光 | 来源:发表于2020-10-05 01:48 被阅读0次

    漫反射贴图

    我们希望通过某种方式对每个原始像素独立设置diffuse颜色。有可以让我们基于物体原始像素的位置来获取颜色值的系统吗?

    这可能听起来极其相似,坦白来讲我们使用这样的系统已经有一段时间了。听起来很像在一个LearnOpenGL 纹理中谈论的纹理,它基本就是一个纹理。我们其实是使用同一个潜在原则下的不同名称:使用一张图片覆盖住物体,以便我们为每个原始像素索引独立颜色值。在光照场景中,通过纹理来呈现一个物体的diffuse颜色,这个做法被称做漫反射贴图(Diffuse texture)(因为3D建模师就是这么称呼这个做法的)。

    着色器中使用漫反射贴图和纹理教程介绍的一样。这次我们把纹理以sampler2D类型储存在Material结构体中。我们使用diffuse贴图替代早期定义的vec3类型的diffuse颜色。

    要记住的是sampler2D也叫做模糊类型,这意味着我们不能以某种类型对它实例化,只能用uniform定义它们。如果我们用结构体而不是uniform实例化(就像函数的参数那样),GLSL会抛出奇怪的错误;这同样也适用于其他模糊类型。


    这里跟纹理贴图的做法差不多, 跟LearnOpenGL 材质中的做法相似

    因为要用到纹理,所以要重新处理立方体的纹理坐标.

        //顶点数据              法线                  纹理坐标
       -0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   0.0f, 0.0f,
        0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   1.0f, 0.0f,
        0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   1.0f, 1.0f,
       -0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   0.0f, 1.0f,
       -0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   0.0f, 0.0f,
    
        ....
    
    修改顶点着色器
    layout (location = 2) in vec2 texCoords; //纹理数据源输入(2D)
    
    out vec2 TexCoords;//把片元着色器的纹理从这里输出
    ....
    main {
      ....
      TexCoords = texCoords;
    }
    

    修改片段着色器

    struct Material {
        sampler2D ambient;
        sampler2D diffuse;
        sampler2D specular;
        float shininess;//镜面反射散射因子(半径).
    };
    uniform Material material;//材质
    
     ...
    
    main {
        ...
        //环境颜色 = 光源颜色 × 环境光照强度 × 贴图
        vec3 ambient = lightColor * light.ambientStrength * vec3(texture(material.ambient, TexCoords));
    
        //漫反射颜色 = 光源颜色 × 漫反射因子(diffuseFactor) × 漫反射光照强度  × 贴图
        ...
        vec3 diffuse = lightColor * diffuseFactor * light.diffuseStrength * vec3(texture(material.diffuse, TexCoords));
    
    }
    
    

    LearnOpenGL 材质不同的是. 因为修改了材质结构体的类型属性. 所以本来

    vec3 diffuse = lightColor * material.ambient * diffuseFactor * light.diffuseStrength; 
    

    中的material.ambient替换为

    vec3(texture(material.ambient, TexCoords))
    




    Shader

    //顶点着色器程序
    static char *myLightMapsVertexShaderStr = SHADER(
        \#version 330 core\n
                                                 
        layout (location = 0) in vec3 position; //顶点数据源输入
        layout (location = 1) in vec3 normal; //法向量
        layout (location = 2) in vec2 texCoords; //纹理数据源输入(2D)
    
        uniform mat4 myProjection;//投影矩阵
        uniform mat4 myView;//观察矩阵
        uniform mat4 myModel;//模型矩阵
                                                 
        out vec3 Normal;//法线向量
        out vec3 FragPos;//片段位置
        out vec2 TexCoords;//把片元着色器的纹理从这里输出
    
    
        void main()
        {
            gl_Position = myProjection * myView * myModel * vec4(position, 1.0f);
            Normal = normal;
            FragPos = vec3(myModel * vec4(position, 1.0f) );
            TexCoords = texCoords;
        }
    );
    
    
    
    //片元着色器程序
    static char *myLightMapsFragmentShaderSrc = SHADER(
        \#version 330 core\n
        //材质
        /**
        要记住的是sampler2D也叫做模糊类型,这意味着我们不能以某种类型对它实例化,只能用uniform定义它们。
        如果我们用结构体而不是uniform实例化(就像函数的参数那样),GLSL会抛出奇怪的错误;这同样也适用于其他模糊类型。
        */
        struct Material {
            sampler2D diffuse;
            sampler2D specular;
            float shininess;//镜面反射散射因子(半径).
        };
        uniform Material material;//材质
    
        //光照强度
        struct Light {
            vec3 position;
            vec3 ambient;//环境光照
            vec3 diffuse;//漫反射光照
            vec3 specular;//镜面反射光照
        };
        uniform Light light;
    
        in vec3 Normal;
        in vec3 FragPos;
        in vec2 TexCoords;
    
        uniform vec3 lightColor;//光照颜色
        uniform vec3 lightPos;//光源位置
        uniform vec3 viewPos;//镜面反射
    
        out vec4 color;
                                                                   
        void main()
        {
            //环境光ambient
            //环境颜色 = 光源颜色 × 环境光照强度 × 贴图
            vec3 ambient = lightColor * light.ambient * vec3(texture(material.diffuse, TexCoords));
    
            //漫反射diffuse
            //DiffuseFactor = max(0, dot(N, L))
            //漫反射颜色 = 光源颜色 × 漫反射因子(diffuseFactor) × 漫反射光照强度 × 贴图
            vec3 norm = normalize(Normal);
            vec3 lightDir = normalize(lightPos - FragPos);
            float diffuseFactor = max(dot(norm, lightDir),0.0);
            vec3 diffuse = lightColor * diffuseFactor * light.diffuse * vec3(texture(material.diffuse, TexCoords));
        
            //镜面反射specular
            //R=reflect(L, N)
            //SpecularFactor = pow(max(dot(R,V),0.0), shininess)
            //镜面反射颜色 = 光源颜色 × 镜面反射因子(SpecularFactor) × 镜面光照强度 × 贴图
            vec3 viewDir = normalize(viewPos - FragPos);
            vec3 reflectDir = reflect(-lightDir , norm);
            float specularFactor = pow(max(dot(viewDir, reflectDir),0.0),material.shininess);
            vec3 specular = lightColor * specularFactor * light.specular * vec3(texture(material.specular, TexCoords));
    
            //最终片段颜色:环境颜色+漫反射颜色+镜面反射颜色
            vec3 result = ambient + diffuse + specular;
            color = vec4(result , 1.0f);
        }
    );
    
    

    顶点数据

    
    GLfloat myLightMapsVertices[] = {
        //顶点数据              法线                  纹理坐标
       -0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   0.0f, 0.0f,
        0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   1.0f, 0.0f,
        0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   1.0f, 1.0f,
       -0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   0.0f, 1.0f,
       -0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,   0.0f, 0.0f,
    
       -0.5f, -0.5f,  0.5f,   0.0f,  0.0f,  1.0f,   0.0f, 0.0f,
        0.5f, -0.5f,  0.5f,   0.0f,  0.0f,  1.0f,   1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,   0.0f,  0.0f,  1.0f,   1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,   0.0f,  0.0f,  1.0f,   1.0f, 1.0f,
       -0.5f,  0.5f,  0.5f,   0.0f,  0.0f,  1.0f,   0.0f, 1.0f,
       -0.5f, -0.5f,  0.5f,   0.0f,  0.0f,  1.0f,   0.0f, 0.0f,
    
       -0.5f,  0.5f,  0.5f,  -1.0f,  0.0f,  0.0f,   0.0f, 0.0f,
       -0.5f,  0.5f, -0.5f,  -1.0f,  0.0f,  0.0f,   1.0f, 0.0f,
       -0.5f, -0.5f, -0.5f,  -1.0f,  0.0f,  0.0f,   1.0f, 1.0f,
       -0.5f, -0.5f, -0.5f,  -1.0f,  0.0f,  0.0f,   1.0f, 1.0f,
       -0.5f, -0.5f,  0.5f,  -1.0f,  0.0f,  0.0f,   0.0f, 1.0f,
       -0.5f,  0.5f,  0.5f,  -1.0f,  0.0f,  0.0f,   0.0f, 0.0f,
    
        0.5f,  0.5f,  0.5f,   1.0f,  0.0f,  0.0f,   0.0f, 0.0f,
        0.5f,  0.5f, -0.5f,   1.0f,  0.0f,  0.0f,   1.0f, 0.0f,
        0.5f, -0.5f, -0.5f,   1.0f,  0.0f,  0.0f,   1.0f, 1.0f,
        0.5f, -0.5f, -0.5f,   1.0f,  0.0f,  0.0f,   1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,   1.0f,  0.0f,  0.0f,   0.0f, 1.0f,
        0.5f,  0.5f,  0.5f,   1.0f,  0.0f,  0.0f,   0.0f, 0.0f,
    
       -0.5f, -0.5f, -0.5f,   0.0f, -1.0f,  0.0f,   0.0f, 0.0f,
        0.5f, -0.5f, -0.5f,   0.0f, -1.0f,  0.0f,   1.0f, 0.0f,
        0.5f, -0.5f,  0.5f,   0.0f, -1.0f,  0.0f,   1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,   0.0f, -1.0f,  0.0f,   1.0f, 1.0f,
       -0.5f, -0.5f,  0.5f,   0.0f, -1.0f,  0.0f,   0.0f, 1.0f,
       -0.5f, -0.5f, -0.5f,   0.0f, -1.0f,  0.0f,   0.0f, 0.0f,
    
       -0.5f,  0.5f, -0.5f,   0.0f,  1.0f,  0.0f,   0.0f, 0.0f,
        0.5f,  0.5f, -0.5f,   0.0f,  1.0f,  0.0f,   1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,   0.0f,  1.0f,  0.0f,   1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,   0.0f,  1.0f,  0.0f,   1.0f, 1.0f,
       -0.5f,  0.5f,  0.5f,   0.0f,  1.0f,  0.0f,   0.0f, 1.0f,
       -0.5f,  0.5f, -0.5f,   0.0f,  1.0f,  0.0f,   0.0f, 0.0f,
    };
    

    程序

    #include <iostream>
    #include "MyLightMaps.hpp"
    #include "MyProgram.hpp"
    #include "MyLightMapsShader.h"
    #include "MyLightMapsVertices.h"
    #include "glm.hpp"
    #include "matrix_transform.hpp"
    #include "type_ptr.hpp"
    
    #define STB_IMAGE_IMPLEMENTATION
    #define STB_IMAGE_STATIC
    #include "stb_image.h"
    
    
    int runMyLightMapsCube() {
        int result = glfwInit();
        if (result == GL_FALSE) {
            printf("glfwInit 初始化失败");
            return -1;
        }
        
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
        GLFWwindow *window = glfwCreateWindow(600, 400, "My Opengl Window", NULL, NULL);
        if(!window) {
            printf("window 创建失败");
        }
        glfwMakeContextCurrent(window);
        gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
    
        //切换为纹理着色器程序
        MyProgram myProgram = MyProgram(myLightMapsVertexShaderStr, myLightMapsFragmentShaderSrc);
    
        ///
        GLuint VBO , VAO ;
        unsigned int squareIndicesCount = 0;
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glBindVertexArray(VAO);
    
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(myLightMapsVertices), myLightMapsVertices, GL_STATIC_DRAW);
        
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(0 * sizeof(GLfloat)));
        glEnableVertexAttribArray(0);
    
        //法线
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
        glEnableVertexAttribArray(1);
        
        //纹理
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
        glEnableVertexAttribArray(2);
    
        //解绑VAO
        glBindVertexArray(0);
        squareIndicesCount = sizeof(myLightMapsVertices)/(sizeof(myLightMapsVertices[0]) * 8);
    
        glEnable(GL_DEPTH_TEST);
        
        
        
    
        //加载纹理
        unsigned int diffuseMaps_texture;
        unsigned char *diffuseMaps_data;
        int diffuseMaps_width, diffuseMaps_height, diffuseMaps_nrChannels;
        glGenTextures(1, &diffuseMaps_texture);
        glBindTexture(GL_TEXTURE_2D, diffuseMaps_texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        diffuseMaps_data = stbi_load( "/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/Common/ImgSources/box.png" , &diffuseMaps_width, &diffuseMaps_height, &diffuseMaps_nrChannels, 0);
        if (diffuseMaps_data)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, diffuseMaps_width, diffuseMaps_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, diffuseMaps_data);
            glGenerateMipmap(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, 0);
    
        }
        else
        {
            std::cout << "Failed to load texture" << std::endl;
        }
        stbi_image_free(diffuseMaps_data);
        
        
        unsigned int specularMaps_texture;
        unsigned char *specularMaps_data;
        int specularMaps_width, specularMaps_height, specularMaps_nrChannels;
        glGenTextures(1, &specularMaps_texture);
        glBindTexture(GL_TEXTURE_2D, specularMaps_texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        specularMaps_data = stbi_load( "/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/Common/ImgSources/box_specular.png" , &specularMaps_width, &specularMaps_height, &specularMaps_nrChannels, 0);
        if (specularMaps_data)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, specularMaps_width, specularMaps_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, specularMaps_data);
            glGenerateMipmap(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, 0);
    
        }
        else
        {
            std::cout << "Failed to load texture" << std::endl;
        }
        stbi_image_free(specularMaps_data);
        
        
        //材质-光照贴图
        glUseProgram(myProgram.program);
    
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, diffuseMaps_texture);
        glUniform1i(glGetUniformLocation(myProgram.program, "material.diffuse"), 0);//环境贴图
        
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, specularMaps_texture);
        glUniform1i(glGetUniformLocation(myProgram.program, "material.specular"), 1);//环境贴图
        
        //进行绘制
        while(!glfwWindowShouldClose(window)){
            glfwPollEvents();
            
            glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            
            
            //================================================
            glm::mat4 model = glm::mat4(1.0f);
            glm::mat4 view = glm::mat4(1.0f);
            glm::mat4 projection = glm::mat4(1.0f);
            
            GLint myModelLoc = glGetUniformLocation(myProgram.program,"myModel");
            GLint myViewLoc = glGetUniformLocation(myProgram.program,"myView");
            GLint myProjectionLoc = glGetUniformLocation(myProgram.program,"myProjection");
            
            projection = glm::perspective(glm::radians(60.0f), 1.0f, 0.01f, 100.f);//投影矩阵
            glUniformMatrix4fv(myProjectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
            glUniformMatrix4fv(myModelLoc, 1, GL_FALSE, glm::value_ptr(model));
    
            // Material
            glm::vec3 MaterialEye   = glm::vec3(2.0f, 2.0f,  2.0f);
            glm::vec3 MaterialCenter = glm::vec3(0.0f, 0.0f, 0.0f);
            glm::vec3 MaterialUp    = glm::vec3(0.0f, 1.0f,  0.0f);
            
            glBindVertexArray(VAO);
            view = glm::lookAt(MaterialEye,       //摄像机位置
                               MaterialCenter,    //目标
                               MaterialUp);       //上向量
            
            //================================================
    
            
            
            
            //================================================
            //镜面反射半径
            GLint matShineLoc = glGetUniformLocation(myProgram.program, "material.shininess");
            glUniform1f(matShineLoc, 64.0f);
            
    
            //光照强度
            GLint lightAmbientLoc = glGetUniformLocation(myProgram.program, "light.ambient");
            GLint lightDiffuseLoc = glGetUniformLocation(myProgram.program, "light.diffuse");
            GLint lightSpecularLoc = glGetUniformLocation(myProgram.program, "light.specular");
    
            glUniform3f(lightAmbientLoc, 0.6f, 0.6f, 0.6f);
            glUniform3f(lightDiffuseLoc, 0.9f, 0.9f, 0.9f);
            glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f);
    
            //光源位置
            GLint myLightPosLoc = glGetUniformLocation(myProgram.program,"lightPos");
            glUniform3f(myLightPosLoc,1.0f,0.0f,4.0f); //
            
            //镜面反射
            GLint myViewPosLoc = glGetUniformLocation(myProgram.program,"viewPos");
            glUniform3f(myViewPosLoc,0.0,0.0f,3.0f); //
            
            //光照颜色
            GLint lightColorLoc = glGetUniformLocation(myProgram.program,"lightColor");
            glUniform3f(lightColorLoc,1.0f,1.0f,1.0f); //白光
                        
            glUniformMatrix4fv(myViewLoc, 1, GL_FALSE, glm::value_ptr(view));
            glDrawArrays(GL_TRIANGLES, 0, squareIndicesCount);
            glBindVertexArray(0);
    
            glfwSwapBuffers(window);
        }
    
        //程序销毁
        glfwTerminate();
        
        return 1;
    }
    
    

    效果

    光照贴图

    相关文章

      网友评论

          本文标题:LearnOpenGL 光照贴图

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