LearnOpenGL Assimp加载模型

2020-10-16  本文已影响0人  li_礼光

重要说明 : 在中文版的模型教程的最后, 可以从这里找到带有顶点片段着色器的完整的源码。 不知道别人可以不可以完整的加载起来,并且跑起来, 这里的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模型练习

上一篇下一篇

猜你喜欢

热点阅读