模型(Model)类

实现一个完整的游戏引擎模型(Model)类是一个复杂的任务,涉及到图形API的抽象、模型数据的加载、渲染、动画等多个方面。下面是一个简化的模型类的实现示例,使用C++语言和OpenGL作为图形API。

1. 包含必要的头文件

#include <GL/glew.h>
#include <glm/glm.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

2. 定义模型类

class Model {
public:
    Model(const std::string& path);
    ~Model();

    void Draw();

private:
    void LoadModel(const std::string& path);
    void ProcessNode(aiNode* node, const aiScene* scene);
    Mesh ProcessMesh(aiMesh* mesh, const aiScene* scene);
    std::vector<Texture> LoadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName);

    std::vector<Mesh> meshes_;
    std::string directory_;
};

3. 实现模型类

Model::Model(const std::string& path) {
    LoadModel(path);
}

Model::~Model() {}

void Model::Draw() {
    for (const auto& mesh : meshes_) {
        mesh.Draw();
    }
}

void Model::LoadModel(const std::string& path) {
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);

    if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
        std::cerr << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl;
        return;
    }

    directory_ = path.substr(0, path.find_last_of('/'));

    ProcessNode(scene->mRootNode, scene);
}

void Model::ProcessNode(aiNode* node, const aiScene* scene) {
    for (unsigned int i = 0; i < node->mNumMeshes; i++) {
        aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
        meshes_.push_back(ProcessMesh(mesh, scene));
    }

    for (unsigned int i = 0; i < node->mNumChildren; i++) {
        ProcessNode(node->mChildren[i], scene);
    }
}

Mesh Model::ProcessMesh(aiMesh* mesh, const aiScene* scene) {
    std::vector<Vertex> vertices;
    std::vector<unsigned int> indices;
    std::vector<Texture> textures;

    for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
        Vertex vertex;

        glm::vec3 vector;
        vector.x = mesh->mVertices[i].x;
        vector.y = mesh->mVertices[i].y;
        vector.z = mesh->mVertices[i].z;
        vertex.Position = vector;

        if (mesh->mTextureCoords[0]) {
            glm::vec2 vec;
            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);
        }

        if (mesh->mNormals) {
            glm::vec3 normal;
            normal.x = mesh->mNormals[i].x;
            normal.y = mesh->mNormals[i].y;
            normal.z = mesh->mNormals[i].z;
            vertex.Normal = normal;
        }

        vertices.push_back(vertex);
    }

    for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
        aiFace face = mesh->mFaces[i];
        for (unsigned int j = 0; j < face.mNumIndices; j++) {
            indices.push_back(face.mIndices[j]);
        }
    }

    if (mesh->mMaterialIndex >= 0) {
        aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
        std::vector<Texture> diffuseMaps = LoadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
        textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());

        std::vector<Texture> specularMaps = LoadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
        textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
    }

    return Mesh(vertices, indices, textures);
}

std::vector<Texture> Model::LoadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName) {
    std::vector<Texture> textures;

    for (unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
        aiString str;
        mat->GetTexture(type, i, &str);
        Texture texture;
        texture.id = TextureFromFile(str.C_Str(), directory_);
        texture.type = typeName;
        texture.path = str;
        textures.push_back(texture);
    }

    return textures;
}

4. 定义网格类

class Mesh {
public:
    Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices, const std::vector<Texture>& textures);
    ~Mesh();

    void Draw();

private:
    void SetupMesh();

    std::vector<Vertex> vertices_;
    std::vector<unsigned int> indices_;
    std::vector<Texture> textures_;
    GLuint VAO_, VBO_, EBO_;
};

Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices, const std::vector<Texture>& textures)
    : vertices_(vertices), indices_(indices), textures_(textures) {
    SetupMesh();
}

Mesh::~Mesh() {
    glDeleteVertexArrays(1, &VAO_);
    glDeleteBuffers(1, &VBO_);
    glDeleteBuffers(1, &EBO_);
}

void Mesh::Draw() {
    GLuint diffuseNr = 1;
    GLuint specularNr = 1;

    for (unsigned int i = 0; i < textures_.size(); i++) {
        glActiveTexture(GL_TEXTURE0 + i);
        std::string number;
        std::string name = textures_[i].type;

        if (name == "texture_diffuse") {
            number = std::to_string(diffuseNr++);
        } else if (name == "texture_specular") {
            number = std::to_string(specularNr++);
        }

        glUniform1i(glGetUniformLocation(shaderProgram, (name + number).c_str()), i);
        glBindTexture(GL_TEXTURE_2D, textures_[i].id);
    }
    glActiveTexture(GL_TEXTURE0);

    glBindVertexArray(VAO_);
    glDrawElements(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

void Mesh::SetupMesh() {
    glGenVertexArrays(1, &VAO_);
    glGenBuffers(1, &VBO_);
    glGenBuffers(1, &EBO_);

    glBindVertexArray(VAO_);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_);
    glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex), &vertices_[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(unsigned int), &indices_[0], GL_STATIC_DRAW);

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

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

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

    glBindVertexArray(0);
}

5. 定义顶点结构体

struct Vertex {
    glm::vec3 Position;
    glm::vec3 Normal;
    glm::vec2 TexCoords;

    static void SetAttributes() {
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);

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

        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
    }
};

6. 定义纹理结构体

struct Texture {
    unsigned int id;
    std::string type;
    std::string path;
};

unsigned int TextureFromFile(const char* path, const std::string& directory) {
    std::string filename = std::string(path);
    filename = directory + "/" + filename;

    unsigned int textureID;
    glGenTextures(1, &textureID);

    int width, height, nrComponents;
    unsigned char* data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
    if (data) {
        GLenum format;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

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

        stbi_image_free(data);
    } else {
        std::cerr << "Texture failed to load at path: " << path << std::endl;
        stbi_image_free(data);
    }

    return textureID;
}

7. 示例:使用模型类

int main(int argc, char* argv[]) {
    // 初始化OpenGL上下文(省略)

    Model model("path/to/model.obj");

    // 渲染循环(省略)
    while (!glfwWindowShouldClose(window)) {
        // 清除颜色缓冲区和深度缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        model.Draw();

        // 交换缓冲区和处理事件
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源(省略)

    return 0;
}

8. 扩展模型类的功能

8.1 动画支持

为了支持模型动画,可以扩展模型类以包含骨骼动画、顶点动画等功能。

class Model {
public:
    // ... 其他成员函数 ...

    void UpdateAnimation(float deltaTime);

private:
    // ... 其他成员变量 ...
    std::vector<Animation> animations_;
};

void Model::UpdateAnimation(float deltaTime) {
    // 实现动画更新逻辑
}
8.2 性能优化

为了提高渲染效率,可以实现实例化渲染、LOD(Level of Detail)等技术。

class Model {
public:
    // ... 其他成员函数 ...

    void DrawInstanced(GLsizei instanceCount);

private:
    // ... 其他成员变量 ...
};

void Model::DrawInstanced(GLsizei instanceCount) {
    glDrawElementsInstanced(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_INT, 0, instanceCount);
}

通过这些扩展和优化,模型类可以更好地适应复杂的游戏引擎需求,提供更灵活和强大的功能。在实际的游戏引擎中,模型类可能还会包含更多的功能和优化,以满足高性能和高可靠性的需求。

由于篇幅和实际应用的限制,我们已经探讨了模型类的许多关键方面,包括模型数据的加载、渲染、动画、性能优化等。然而,如果需要进一步扩展模型类的功能,以下是一些可能的方向:

9. 高级材质系统

为了支持更复杂的材质效果,如PBR(Physically Based Rendering)、透明度、自发光等,可以扩展模型类以包含更高级的材质系统。

9.1 PBR材质支持
class Material {
public:
    // ... 其他成员函数 ...

    void SetPBRParameters(const glm::vec3& albedo, float metallic, float roughness, const glm::vec3& ao);

private:
    // ... 其他成员变量 ...
    glm::vec3 albedo_;
    float metallic_;
    float roughness_;
    glm::vec3 ao_;
};

void Material::SetPBRParameters(const glm::vec3& albedo, float metallic, float roughness, const glm::::vec3 ao) {
    albedo_ = albedo;
    metallic_ = metallic;
    roughness_ = roughness;
    ao_ = ao;
}

10. 骨骼动画系统

为了支持骨骼动画,可以实现一个骨骼动画系统,包含骨骼结构、动画数据、蒙皮权重等。

10.1 骨骼动画支持
class Animation {
public:
    // ... 其他成员函数 ...

    void Update(float deltaTime);

private:
    // ... 其他成员变量 ...
    std::vector<glm::mat4> boneTransforms_;
};

void Animation::Update(float deltaTime) {
    // 实现骨骼动画更新逻辑
}

11. 实例化渲染优化

为了提高渲染大量相同模型的效率,可以实现实例化渲染技术。

11.1 实例化渲染支持
class Model {
public:
    // ... 其他成员函数 ...

    void DrawInstanced(GLsizei instanceCount);

private:
    // ... 其他成员变量 ...
    GLuint instanceVBO_;
};

void Model::DrawInstanced(GLsizei instanceCount) {
    glBindBuffer(GL_ARRAY_BUFFER, instanceVBO_);
    glBufferData(GL_ARRAY_BUFFER, instanceCount * sizeof(glm::mat4), &instanceTransforms_[0], GL_STATIC_DRAW);

    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
    glEnableVertexAttribArray(4);
    glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4)));
    glEnableVertexAttribArray(5);
    glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4)));
    glEnableVertexAttribArray(6);
    glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4)));

    glVertexAttribDivisor(3, 1);
    glVertexAttribDivisor(4, 1);
    glVertexAttribDiviator(5, 1);
    glVertexAttribDivisor(6, 1);

    glDrawElementsInstanced(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_INT, 0, instanceCount);

    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);
    glDisableVertexAttribArray(5);
    glDisableVertexAttribArray(6);
}

12. 动态LOD(Level of Detail)支持

为了提高渲染效率,可以实现动态LOD技术,根据视点距离动态调整模型的细节级别。

12.1 动态LOD支持
class Model {
public:
    // ... 其他成员函数 ...

    void UpdateLOD(const glm::vec3& cameraPosition);

private:
    // ... 其他成员变量 ...
    std::vector<Mesh> lodMeshes_;
};

void Model::UpdateLOD(const glm::vec3& cameraPosition) {
    // 实现动态LOD更新逻辑
}

通过这些高级功能的扩展,模型类可以更好地适应复杂的游戏引擎需求,提供更强大的功能和更高的性能。然而,需要注意的是,每个功能的实现都需要仔细考虑其对性能、稳定性和可维护性的影响,以确保最终的实现既高效又可靠。

由于篇幅和实际应用的限制,我们已经探讨了模型类的许多关键方面,包括模型数据的加载、渲染、动画、性能优化等。然而,如果需要进一步扩展模型类的功能,以下是一些可能的方向:

13. 高级光照和阴影

为了支持更真实的光照效果,可以实现全局光照、实时阴影等技术。

13.1 实时阴影支持
class Model {
public:
    // ... 其他成员函数 ...

    void RenderShadows(const glm::mat4& lightSpaceMatrix);

private:
    // ... 其他成员变量 ...
    GLuint shadowMapFBO_;
};

void Model::RenderShadows(const glm::mat4& lightSpaceMatrix) {
    glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO_);
    glClear(GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
    glCullFace(GL_FRONT);
    shaderProgram.use();
    shaderProgram.setMat4("lightSpaceMatrix", lightSpaceMatrix);
    Draw();
    glCullFace(GL_BACK);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

14. 高级纹理技术

为了支持更复杂的纹理效果,可以实现纹理数组、纹理立方体贴图等技术。

14.1 纹理数组支持
class TextureArray {
public:
    // ... 其他成员函数 ...

    void AddTexture(const std::string& path);

private:
    // ... 其他成员变量 ...
    GLuint textureID_;
    std::vector<unsigned int> textureIDs_;
};

void TextureArray::AddTexture(const std::region("C++")std::string& path) {
    unsigned int textureID = TextureFromFile(path.c_str(), directory_);
    textureIDs_.push_back(textureID);
}

void TextureArray::Bind(unsigned int unit) const {
    glActiveTexture(GL_TEXTURE0 + unit);
    glBindTexture(GL_TEXTURE_2D_ARRAY, textureID_);
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width_, height_, textureIDs_.size(), GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}

15. 高级几何处理

为了支持更复杂的几何处理,可以实现法线贴图、位移贴图等技术。

15.1 法线贴图支持
class Material {
public:
    // ... 其他成员函数 ...

    void SetNormalMap(const std::string& path);

private:
    // ... 其他成员变量 ...
    GLuint normalMapID_;
};

void Material::SetNormalMap(const std::string& path) {
    normalMapID_ = TextureFromFile(path.c_str(), directory_);
}

16. 高级渲染技术

为了支持更高级的渲染技术,可以实现延迟渲染、屏幕空间效果等技术。

16.1 延迟渲染支持
class Renderer {
public:
    // ... 其他成员函数 ...

    void RenderDeferred(const std::vector<Model>& models);

private:
    // ... 其他成员变量 ...
    GLuint gBuffer_;
    GLuint gPosition_, gNormal_, gAlbedoSpec_;
};

void Renderer::RenderDeferred(const std::vector<Model>& models) {
    glBindFramebuffer(GL_FRAMEBUFFER, gBuffer_);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);

    for (const auto& model : models) {
        model.Draw();
    }

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

通过这些高级功能的扩展,模型类可以更好地适应复杂的游戏引擎需求,提供更强大的功能和更高的性能。然而,需要注意的是,每个功能的实现都需要仔细考虑其对性能、稳定性和可维护性的影响,以确保最终的实现既高效又可靠。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值