LearnOpenGL Assimp加載模型

重要說(shuō)明 : 在中文版的模型教程的最后, 可以從這里找到帶有頂點(diǎn)片段著色器的完整的源碼。 不知道別人可以不可以完整的加載起來(lái),并且跑起來(lái), 這里的Demo例子在自己的驗(yàn)證里面是實(shí)現(xiàn)不了加載模型并且顯示

解決 : 我切到英文版本的Model教程中找到對(duì)應(yīng)的的源代碼參考.

注意 : 百度了很多相關(guān)的Demo. 千篇一律, 都不完整, 很容易就在這一節(jié)放棄了整個(gè)學(xué)習(xí)了.

上一節(jié)LearnOpenGL Assimp中通過(guò)brew的方式加載assimp的庫(kù). 在上一節(jié)的操作中, 只需要確保引入的庫(kù)正常無(wú)報(bào)錯(cuò)就接著下面的內(nèi)容.

這里的實(shí)現(xiàn)代碼封裝方式引用源代碼的方式. 因?yàn)镾hader的封裝和自己的MyProgram封裝有點(diǎn)不一樣. 里面的大致步驟都是一樣的. 就是裝載著色器程序的方式有些不一樣, MyProgram是直接加載C字符串的方式. Shader是通過(guò)打開(kāi)文件的形式. 這一章節(jié)就使用Shader的方式實(shí)現(xiàn). 多參考不一樣的做法吧.


3D模型

可以在這里下載turbosquid一些免費(fèi)的3D模型, 格式有很多, 自己注冊(cè)一個(gè)賬號(hào)下載就好.

自己下載了的練習(xí)模型, Obj格式 , 直接放在Xcode項(xiàng)目項(xiàng)目中, 也可以自己通過(guò)Xcode的Inspector窗口查看一些基本的屬性內(nèi)容.




相關(guān)頭文件
camera
shader
model
mesh


頂點(diǎn)著色器

#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);
}

頂點(diǎn)著色器和片元著色器程序, 很簡(jiǎn)單, 跟LearnOpenGL 紋理之前編寫(xiě)的著色器一樣


程序

#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 創(chuàng)建失敗");
    }
    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里面的方法是直接通過(guò)打開(kāi)文件的形式, 與之前的
    // -------------------------
    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);
}

主要地方, 加載你的頂點(diǎn)著色器和片元著色器程序.

// 加載著色器程序, Shader里面的方法是直接通過(guò)打開(kāi)文件的形式, 與之前的
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");


代碼實(shí)現(xiàn)效果 :

這里的看起來(lái)什么都是黑的, 因?yàn)樵谄髦? FragColor = texture(texture_diffuse1, TexCoords);. 我們是用紋理的方式去實(shí)現(xiàn). 在程序中目前只加載了obj文件. 通過(guò)Xcode的Inspector來(lái)看是只有白色的一個(gè)3D模型.

texture_diffuse1 是沒(méi)有的, 相當(dāng)于vec3(0.0f,0.0f,0.0f)吧.




優(yōu)化

修改一下Shader程序, 把obj文件格式的3D模型當(dāng)做一個(gè)素模. 就是沒(méi)有任何紋理的素模. 那么我們給模型加上光照. 參照 : LearnOpenGL 基礎(chǔ)光照

熟悉的配方 : 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;//環(huán)境光照
    vec3 diffuse;//漫反射光照
    vec3 specular;//鏡面反射光照
};
uniform Light light;


void main()
{
    //環(huán)境光ambient
    //環(huán)境顏色 = 光源顏色 × 環(huán)境光照強(qiáng)度 × 貼圖
    vec3 ambient = vec3(1.0f,1.0f,1.0f) * light.ambient ;

    //漫反射diffuse
    //DiffuseFactor = max(0, dot(N, L))
    //漫反射顏色 = 光源顏色 × 漫反射因子(diffuseFactor) × 漫反射光照強(qiáng)度 × 貼圖
    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) × 鏡面光照強(qiáng)度 × 貼圖
    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 ;

    //最終片段顏色:環(huán)境顏色+漫反射顏色+鏡面反射顏色
    vec3 result = ambient + diffuse + specular;
    color = vec4(result , 1.0f);
}

因?yàn)樵?a target="_blank">mesh中實(shí)現(xiàn)void Draw(Shader &shader) 渲染,
對(duì)片元著色器的光照屬性賦值

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);

優(yōu)化效果




完整的Demo可以參照Github : LearnOpengl, 自己也可以更換幾個(gè)3D模型練習(xí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容