美文网首页
LearnOpenGL Assimp加载模型

LearnOpenGL Assimp加载模型

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

    重要说明 : 在中文版的模型教程的最后, 可以从这里找到带有顶点片段着色器的完整的源码。 不知道别人可以不可以完整的加载起来,并且跑起来, 这里的Demo例子在自己的验证里面是实现不了加载模型并且显示

    解决 : 我切到英文版本的Model教程中找到对应的的源代码参考.

    注意 : 百度了很多相关的Demo. 千篇一律, 都不完整, 很容易就在这一节放弃了整个学习了.

    上一节LearnOpenGL Assimp中通过brew的方式加载assimp的库. 在上一节的操作中, 只需要确保引入的库正常无报错就接着下面的内容.

    这里的实现代码封装方式引用源代码的方式. 因为Shader的封装和自己的MyProgram封装有点不一样. 里面的大致步骤都是一样的. 就是装载着色器程序的方式有些不一样, MyProgram是直接加载C字符串的方式. Shader是通过打开文件的形式. 这一章节就使用Shader的方式实现. 多参考不一样的做法吧.


    3D模型

    可以在这里下载turbosquid一些免费的3D模型, 格式有很多, 自己注册一个账号下载就好.

    自己下载了的练习模型, Obj格式 , 直接放在Xcode项目项目中, 也可以自己通过Xcode的Inspector窗口查看一些基本的属性内容.




    相关头文件
    camera
    shader
    model
    mesh


    顶点着色器

    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aNormal;
    layout (location = 2) in vec2 aTexCoords;
    out vec2 TexCoords;
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    void main()
    {
        TexCoords = aTexCoords;    
        gl_Position = projection * view * model * vec4(aPos, 1.0);
    }
    

    片元着色器

    #version 330 core
    out vec4 FragColor;
    in vec2 TexCoords;
    uniform sampler2D texture_diffuse1;
    void main()
    {    
        FragColor = texture(texture_diffuse1, TexCoords);
    }
    

    顶点着色器和片元着色器程序, 很简单, 跟LearnOpenGL 纹理之前编写的着色器一样


    程序

    #include "MyModelLoadingDemo.hpp"
    #include "glad.h"
    #include <GLFW/glfw3.h>
    
    #include "glm.hpp"
    #include "matrix_transform.hpp"
    #include "type_ptr.hpp"
    
    #include "shader.h"
    #include "camera.h"
    #include "model.h"
    #include <iostream>
    
    void framebuffer_size_callback(GLFWwindow* window, int width, int height);
    void mouse_M_callback(GLFWwindow* window, double xpos, double ypos);
    void scroll_S_callback(GLFWwindow* window, double xoffset, double yoffset);
    void processInput(GLFWwindow *window);
    
    // settings
    const unsigned int SCR_WIDTH = 800;
    const unsigned int SCR_HEIGHT = 600;
    
    // camera
    Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
    float lastX_X = SCR_WIDTH / 2.0f;
    float lastY_Y = SCR_HEIGHT / 2.0f;
    bool firstMouse_M = true;
    
    // timing
    float deltaTime_T = 0.0f;
    float lastFrame_F = 0.0f;
    
    int runMyModelLoadingDemo() {
    
        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);
        // glad: load all OpenGL function pointers
        // ---------------------------------------
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            std::cout << "Failed to initialize GLAD" << std::endl;
            return -1;
        }
            
        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
        glfwSetCursorPosCallback(window, mouse_M_callback);
        glfwSetScrollCallback(window, scroll_S_callback);
        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    
        // tell stb_image.h to flip loaded texture's on the y-axis (before loading model).
        stbi_set_flip_vertically_on_load(true);
    
        // configure global opengl state
        // -----------------------------
        glEnable(GL_DEPTH_TEST);
        
    
        // 加载着色器程序, Shader里面的方法是直接通过打开文件的形式, 与之前的
        // -------------------------
        Shader ourShader("/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/ModelLoading(模型加载)/myModelLoadingShader.vs", "/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/ModelLoading(模型加载)/myModelLoadingShader.fs");
    
        // 加载模型
        // -----------
        Model ourModel("/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/3DSources/drill.obj");
    
    
        while (!glfwWindowShouldClose(window))
        {
            // per-frame time logic
            // --------------------
            float currentFrame = glfwGetTime();
            deltaTime_T = currentFrame - lastFrame_F;
            lastFrame_F = currentFrame;
    
            processInput(window);
            glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
            // don't forget to enable shader before setting uniforms
            ourShader.use();
    
            //================================================
            // view/projection transformations
            glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 400.0f);
            glm::mat4 view = camera.GetViewMatrix();
            ourShader.setMat4("projection", projection);
            ourShader.setMat4("view", view);
    
            // render the loaded model
            glm::mat4 model = glm::mat4(1.0f);
            model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); // translate it down so it's at the center of the scene
            model = glm::scale(model, glm::vec3(0.01f, 0.01f, 0.01f));    // it's a bit too big for our scene, so scale it down
            ourShader.setMat4("model", model);
            ourModel.Draw(ourShader);
            //================================================
    
            glfwSwapBuffers(window);
            glfwPollEvents();
        }
    
        //程序销毁
        glfwTerminate();
        return 0;
    }
     
    void processInput(GLFWwindow *window)
    {
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);
    
        if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
            camera.ProcessKeyboard(FORWARD, deltaTime_T);
        if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
            camera.ProcessKeyboard(BACKWARD, deltaTime_T);
        if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
            camera.ProcessKeyboard(LEFT, deltaTime_T);
        if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
            camera.ProcessKeyboard(RIGHT, deltaTime_T);
    }
    
    void framebuffer_size_callback(GLFWwindow* window, int width, int height)
    {
        // make sure the viewport matches the new window dimensions; note that width and
        // height will be significantly larger than specified on retina displays.
        glViewport(0, 0, width, height);
    }
    
    void mouse_M_callback(GLFWwindow* window, double xpos, double ypos)
    {
        if (firstMouse_M)
        {
            lastX_X = xpos;
            lastY_Y = ypos;
            firstMouse_M = false;
        }
    
        float xoffset = xpos - lastX_X;
        float yoffset = lastY_Y - ypos;
    
        lastX_X = xpos;
        lastY_Y = ypos;
    
        camera.ProcessMouseMovement(xoffset, yoffset);
    }
    
    void scroll_S_callback(GLFWwindow* window, double xoffset, double yoffset)
    {
        camera.ProcessMouseScroll(yoffset);
    }
    

    主要地方, 加载你的顶点着色器和片元着色器程序.

    // 加载着色器程序, Shader里面的方法是直接通过打开文件的形式, 与之前的
    Shader ourShader("/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/ModelLoading(模型加载)/myModelLoadingShader.vs", "/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/ModelLoading(模型加载)/myModelLoadingShader.fs");
    
    // 加载模型
    Model ourModel("/Users/liliguang/Desktop/LearnOpengl/LearnOpenGl/LearnOpenGl/Demo/3DSources/drill.obj");
    


    代码实现效果 :

    这里的看起来什么都是黑的, 因为在片元着色器中, FragColor = texture(texture_diffuse1, TexCoords);. 我们是用纹理的方式去实现. 在程序中目前只加载了obj文件. 通过Xcode的Inspector来看是只有白色的一个3D模型.

    texture_diffuse1 是没有的, 相当于vec3(0.0f,0.0f,0.0f)吧.




    优化

    修改一下Shader程序, 把obj文件格式的3D模型当做一个素模. 就是没有任何纹理的素模. 那么我们给模型加上光照. 参照 : LearnOpenGL 基础光照

    熟悉的配方 : shader修改

    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aNormal;
    layout (location = 2) in vec2 aTexCoords;
    
    out vec2 TexCoords;
    out vec3 Normal;//法线向量
    out vec3 FragPos;//片段位置
    
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    
    void main()
    {
        TexCoords = aTexCoords;
        gl_Position = projection * view * model * vec4(aPos, 1.0);
        Normal = aNormal;
        FragPos = vec3(model * vec4(aPos, 1.0f) );
    }
    
    #version 330 core
    out vec4 FragColor;
    out vec4 color;
    
    in vec2 TexCoords;
    in vec3 Normal;
    in vec3 FragPos;
    
    uniform sampler2D texture_diffuse1;
    
    //光照
    struct Light {
        vec3 position;
        vec3 ambient;//环境光照
        vec3 diffuse;//漫反射光照
        vec3 specular;//镜面反射光照
    };
    uniform Light light;
    
    
    void main()
    {
        //环境光ambient
        //环境颜色 = 光源颜色 × 环境光照强度 × 贴图
        vec3 ambient = vec3(1.0f,1.0f,1.0f) * light.ambient ;
    
        //漫反射diffuse
        //DiffuseFactor = max(0, dot(N, L))
        //漫反射颜色 = 光源颜色 × 漫反射因子(diffuseFactor) × 漫反射光照强度 × 贴图
        vec3 norm = normalize(Normal);
        vec3 lightDir = normalize(vec3(0.0f,0.0f,3.0f) - FragPos);
        float diffuseFactor = max(dot(norm, lightDir),0.0);
        vec3 diffuse = vec3(1.0f,1.0f,1.0f) * diffuseFactor * light.diffuse ;
    
        //镜面反射specular
        //R=reflect(L, N)
        //SpecularFactor = pow(max(dot(R,V),0.0), shininess)
        //镜面反射颜色 = 光源颜色 × 镜面反射因子(SpecularFactor) × 镜面光照强度 × 贴图
        vec3 viewDir = normalize(vec3(0.0f,0.0f,3.0f) - FragPos);
        vec3 reflectDir = reflect(-lightDir , norm);
        float specularFactor = pow(max(dot(viewDir, reflectDir),0.0),64.0f);
        vec3 specular = vec3(1.0f,1.0f,1.0f) * specularFactor * light.specular ;
    
        //最终片段颜色:环境颜色+漫反射颜色+镜面反射颜色
        vec3 result = ambient + diffuse + specular;
        color = vec4(result , 1.0f);
    }
    

    因为在mesh中实现void Draw(Shader &shader) 渲染,
    对片元着色器的光照属性赋值

    GLint lightAmbientLoc = glGetUniformLocation(shader.ID, "light.ambient");
    GLint lightDiffuseLoc = glGetUniformLocation(shader.ID, "light.diffuse");
    GLint lightSpecularLoc = glGetUniformLocation(shader.ID, "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);
    

    优化效果




    完整的Demo可以参照Github : LearnOpengl, 自己也可以更换几个3D模型练习

    相关文章

      网友评论

          本文标题:LearnOpenGL Assimp加载模型

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