您当前的位置: 首页 > 

鱼儿-1226

暂无认证

  • 0浏览

    0关注

    1100博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

OpenGL之——assimp加载模型

鱼儿-1226 发布时间:2020-07-21 11:00:17 ,浏览量:0

主要代码:

 

main.cpp

 

// Std. Includes

#include

#include

// GLEW

#define GLEW_STATIC

#include

 

// GLFW

#include

 

// GL includes

#include "Shader.h"

#include "Camera.h"

#include "Mesh.h"

#include "Model.h"

 

// GLM Mathemtics

#include

#include

#include

 

#include

// Other Libs

#include

 

#pragma comment(lib,"glew32s.lib")

#pragma comment(lib,"glfw3.lib")

#pragma comment(lib,"SOIL.lib")

// Properties

GLuint screenWidth = 800, screenHeight = 600;

 

// Function prototypes

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);

void mouse_callback(GLFWwindow* window, double xpos, double ypos);

void Do_Movement();

 

// Camera

Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));

bool keys[1024];

GLfloat lastX = 400, lastY = 300;

bool firstMouse = true;

 

GLfloat deltaTime = 0.0f;

GLfloat lastFrame = 0.0f;

 

// The MAIN function, from here we start our application and run our Game loop

int main()

{

// Init GLFW

glfwInit();

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

 

GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed

glfwMakeContextCurrent(window);

 

// Set the required callback functions

glfwSetKeyCallback(window, key_callback);

glfwSetCursorPosCallback(window, mouse_callback);

glfwSetScrollCallback(window, scroll_callback);

 

// Options

glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

 

// Initialize GLEW to setup the OpenGL Function pointers

glewExperimental = GL_TRUE;

glewInit();

 

// Define the viewport dimensions

glViewport(0, 0, screenWidth, screenHeight);

 

// Setup some OpenGL options

glEnable(GL_DEPTH_TEST);

 

// Setup and compile our shaders

Shader shader("load_model.vs", "load_model.frag");

 

// Load models

Model ourModel((GLchar*)("nanosuit/nanosuit.obj"));

 

// Draw in wireframe

//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

 

// Game loop

while (!glfwWindowShouldClose(window))

{

// Set frame time

GLfloat currentFrame = glfwGetTime();

deltaTime = currentFrame - lastFrame;

lastFrame = currentFrame;

 

// Check and call events

glfwPollEvents();

Do_Movement();

 

// Clear the colorbuffer

glClearColor(0.05f, 0.05f, 0.05f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

shader.Use();   //

WorldUp = glm::vec3(upX, upY, upZ);

this->Yaw = yaw;

this->Pitch = pitch;

this->updateCameraVectors();

}

 

// Returns the view matrix calculated using Eular Angles and the LookAt Matrix

glm::mat4 GetViewMatrix()

{

return glm::lookAt(this->Position, this->Position + this->Front, this->Up);

}

 

// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)

void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime)

{

GLfloat velocity = this->MovementSpeed * deltaTime;

if (direction == FORWARD)

this->Position += this->Front * velocity;

if (direction == BACKWARD)

this->Position -= this->Front * velocity;

if (direction == LEFT)

this->Position -= this->Right * velocity;

if (direction == RIGHT)

this->Position += this->Right * velocity;

}

 

// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.

void ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true)

{

xoffset *= this->MouseSensitivity;

yoffset *= this->MouseSensitivity;

 

this->Yaw += xoffset;

this->Pitch += yoffset;

 

// Make sure that when pitch is out of bounds, screen doesn't get flipped

if (constrainPitch)

{

if (this->Pitch > 89.0f)

this->Pitch = 89.0f;

if (this->Pitch < -89.0f)

this->Pitch = -89.0f;

}

 

// Update Front, Right and Up Vectors using the updated Eular angles

this->updateCameraVectors();

}

 

// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis

void ProcessMouseScroll(GLfloat yoffset)

{

if (this->Zoom >= 1.0f && this->Zoom Zoom -= yoffset;

if (this->Zoom Zoom = 1.0f;

if (this->Zoom >= 45.0f)

this->Zoom = 45.0f;

}

 

private:

// Calculates the front vector from the Camera's (updated) Eular Angles

void updateCameraVectors()

{

// Calculate the new Front vector

glm::vec3 front;

front.x = cos(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch));

front.y = sin(glm::radians(this->Pitch));

front.z = sin(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch));

this->Front = glm::normalize(front);

// Also re-calculate the Right and Up vector

this->Right = glm::normalize(glm::cross(this->Front, this->WorldUp));  // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.

this->Up = glm::normalize(glm::cross(this->Right, this->Front));

}

};

Model.h

 

#pragma once

// Std. Includes

#include

#include

#include

#include

#include

#include

using namespace std;

// GL Includes

#include // Contains all the necessery OpenGL includes

#include

#include

#include

#include

#include

#include

#include

#pragma comment(lib,"assimpd.lib")

#include "Mesh.h"

 

GLint TextureFromFile(const char* path, string directory);

 

class Model

{

public:

/*  Functions   */

// Constructor, expects a filepath to a 3D model.

Model(GLchar* path)

{

this->loadModel(path);

}

 

// Draws the model, and thus all its meshes

void Draw(Shader shader)

{

for (GLuint i = 0; i < this->meshes.size(); i++)

this->meshes[i].Draw(shader);

}

 

private:

/*  Model Data  */

vector meshes;

string directory;

vector textures_loaded; // Stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once.

 

/*  Functions   */

// Loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector.

void loadModel(string path)

{

// Read file via ASSIMP

Assimp::Importer importer;

const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);

// Check for errors

if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero

{

cout mRootNode, scene);

}

 

// Processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any).

void processNode(aiNode* node, const aiScene* scene)

{

// Process each mesh located at the current node

for (GLuint i = 0; i < node->mNumMeshes; i++)

{

// The node object only contains indices to index the actual objects in the scene. 

// The scene contains all the data, node is just to keep stuff organized (like relations between nodes).

aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];

this->meshes.push_back(this->processMesh(mesh, scene));

}

// After we've processed all of the meshes (if any) we then recursively process each of the children nodes

for (GLuint i = 0; i < node->mNumChildren; i++)

{

this->processNode(node->mChildren[i], scene);

}

 

}

 

Mesh processMesh(aiMesh* mesh, const aiScene* scene)

{

// Data to fill

vector vertices;

vector indices;

vector textures;

 

// Walk through each of the mesh's vertices

for (GLuint i = 0; i < mesh->mNumVertices; i++)

{

Vertex vertex;

glm::vec3 vector; // We declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.

// Positions

vector.x = mesh->mVertices[i].x;

vector.y = mesh->mVertices[i].y;

vector.z = mesh->mVertices[i].z;

vertex.Position = vector;

// Normals

vector.x = mesh->mNormals[i].x;

vector.y = mesh->mNormals[i].y;

vector.z = mesh->mNormals[i].z;

vertex.Normal = vector;

// Texture Coordinates

if (mesh->mTextureCoords[0]) // Does the mesh contain texture coordinates?

{

glm::vec2 vec;

// A vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't 

// use models where a vertex can have multiple texture coordinates so we always take the first set (0).

vec.x = mesh->mTextureCoords[0][i].x;

vec.y = mesh->mTextureCoords[0][i].y;

vertex.TexCoords = vec;

}

else

vertex.TexCoords = glm::vec2(0.0f, 0.0f);

vertices.push_back(vertex);

}

// Now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.

for (GLuint i = 0; i < mesh->mNumFaces; i++)

{

aiFace face = mesh->mFaces[i];

// Retrieve all indices of the face and store them in the indices vector

for (GLuint j = 0; j < face.mNumIndices; j++)

indices.push_back(face.mIndices[j]);

}

// Process materials

if (mesh->mMaterialIndex >= 0)

{

aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];

// We assume a convention for sampler names in the shaders. Each diffuse texture should be named

// as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. 

// Same applies to other texture as the following list summarizes:

// Diffuse: texture_diffuseN

// Specular: texture_specularN

// Normal: texture_normalN

 

// 1. Diffuse maps

vector diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");

textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());

// 2. Specular maps

vector specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");

textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());

}

 

// Return a mesh object created from the extracted mesh data

return Mesh(vertices, indices, textures);

}

 

// Checks all material textures of a given type and loads the textures if they're not loaded yet.

// The required info is returned as a Texture struct.

vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName)

{

vector textures;

for (GLuint i = 0; i < mat->GetTextureCount(type); i++)

{

aiString str;

mat->GetTexture(type, i, &str);

// Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture

GLboolean skip = false;

for (GLuint j = 0; j < textures_loaded.size(); j++)

{

if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0)

{

textures.push_back(textures_loaded[j]);

skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)

break;

}

}

if (!skip)

{   // If texture hasn't been loaded already, load it

Texture texture;

texture.id = TextureFromFile(str.C_Str(), this->directory);

texture.type = typeName;

texture.path = str.C_Str();

textures.push_back(texture);

this->textures_loaded.push_back(texture);  // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.

}

}

return textures;

}

};

 

 

 

 

GLint TextureFromFile(const char* path, string directory)

{

//Generate texture ID and load texture data 

string filename = string(path);

filename = directory + '/' + filename;

GLuint textureID;

glGenTextures(1, &textureID);

int width, height;

unsigned char* image = SOIL_load_image(filename.c_str(), &width, &height, 0, SOIL_LOAD_RGB);

// Assign texture to ID

glBindTexture(GL_TEXTURE_2D, textureID);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

glGenerateMipmap(GL_TEXTURE_2D);

 

// Parameters

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

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glBindTexture(GL_TEXTURE_2D, 0);

SOIL_free_image_data(image);

return textureID;

}

Mesh.h

 

#pragma once

// Std. Includes

#include "Shader.h"

#include

#include

#include

#include

#include

using namespace std;

// GL Includes

#include // Contains all the necessery OpenGL includes

#include

#include

 

struct Vertex {

// Position

glm::vec3 Position;

// Normal

glm::vec3 Normal;

// TexCoords

glm::vec2 TexCoords;

};

 

struct Texture {

GLuint id;

string type;

string path;

};

 

class Mesh {

public:

/*  Mesh Data  */

vector vertices;

vector indices;

vector textures;

 

/*  Functions  */

// Constructor

Mesh(vector vertices, vector indices, vector textures)

{

this->vertices = vertices;

this->indices = indices;

this->textures = textures;

 

// Now that we have all the required data, set the vertex buffers and its attribute pointers.

this->setupMesh();

}

 

// Render the mesh

void Draw(Shader shader)

{

// Bind appropriate textures

GLuint diffuseNr = 1;

GLuint specularNr = 1;

for (GLuint i = 0; i < this->textures.size(); i++)

{

glActiveTexture(GL_TEXTURE0 + i); // Active proper texture unit before binding

// Retrieve texture number (the N in diffuse_textureN)

stringstream ss;

string number;

string name = this->textures[i].type;

if (name == "texture_diffuse")

ss VAO);

glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);

glBindVertexArray(0);

 

// Always good practice to set everything back to defaults once configured.

for (GLuint i = 0; i < this->textures.size(); i++)

{

glActiveTexture(GL_TEXTURE0 + i);

glBindTexture(GL_TEXTURE_2D, 0);

}

}

 

private:

/*  Render data  */

GLuint VAO, VBO, EBO;

 

/*  Functions    */

// Initializes all the buffer objects/arrays

void setupMesh()

{

// Create buffers/arrays

glGenVertexArrays(1, &this->VAO);

glGenBuffers(1, &this->VBO);

glGenBuffers(1, &this->EBO);

 

glBindVertexArray(this->VAO);

// Load data into vertex buffers

glBindBuffer(GL_ARRAY_BUFFER, this->VBO);

// A great thing about structs is that their memory layout is sequential for all its items.

// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which

// again translates to 3/2 floats which translates to a byte array.

glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex), &this->vertices[0], GL_STATIC_DRAW);

 

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);

glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW);

 

// Set the vertex attribute pointers

// Vertex Positions

glEnableVertexAttribArray(0);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);

// Vertex Normals

glEnableVertexAttribArray(1);

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));

// Vertex Texture Coords

glEnableVertexAttribArray(2);

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoords));

 

glBindVertexArray(0);

}

};

 

 

load_model.vs

 

#version 330 core

layout(location = 0) in vec3 position;

layout(location = 1) in vec3 normal;

layout(location = 2) in vec2 texCoords;

 

out vec2 TexCoords;

 

uniform mat4 model;

uniform mat4 view;

uniform mat4 projection;

 

void main()

{

gl_Position = projection * view * model * vec4(position, 1.0f);

TexCoords = texCoords;

}

load_model.frag

 

#version 330 core

 

in vec2 TexCoords;

 

out vec4 color;

 

uniform sampler2D texture_diffuse1;

 

void main()

{

color = vec4(texture(texture_diffuse1, TexCoords));

}

效果:

 

 

 

 obj文件已上传至我的资源,需要的可以下载

关注
打赏
1604459285
查看更多评论
立即登录/注册

微信扫码登录

0.0485s