首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在OpenGL中使用大型号的高窗口分辨率会带来巨大的性能下降

在OpenGL中使用大型号的高窗口分辨率会带来巨大的性能下降
EN

Stack Overflow用户
提问于 2022-07-26 22:06:34
回答 1查看 56关注 0票数 -2

我目前正在绘制大约10个背包对象和一个巨大的海绵状模型与OpenGL (它有约400个网格和200万三角形),和7点灯光在我的场景。当窗口是800x600分辨率时,性能是好的(60 Fps),但是当我使窗口与我的屏幕大小(2560x1600)差不多时,性能会大幅下降到大约15-20 fps,特别是在查看sponza模型时(我使用的是Assimp)。代码结构如下(简化):

Mesh.cpp

代码语言:javascript
复制
class Mesh {
  // class that contains all vertex info (pos, normal, UV)
  void draw(const Shader& shader) const {
      // bind the textures + activate
      // bind the vao
      glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
  }
};

Model.cpp (唯一的任务是加载网格):

代码语言:javascript
复制
class Model {
  std::vector<Mesh> meshes;
  void draw(const Shader& shader) const {
     for (const auto& mesh: meshes) {
         mesh.draw(shader);
     }
  }
};

问题是,由于sponza模型有400个网格,这对应于400次绘图调用+ 10次背包绘图调用,这大约等于每帧410次绘图调用。我想,对每个网格进行抽签调用可能会导致性能下降。然而,我不知道如何解决这个问题。也许我可以将所有的顶点数据放到一个VBO中,并进行一次抽签调用,但我不太确定如何解决这个问题。另外,在sponza模型中有25种材料。

我正在使用learnopengl.com的Mesh和Model的实现,下面是完整的类:Model.cpp

代码语言:javascript
复制
class Model {
public:
    explicit Model(const std::string &path);
    ~Model();
    void draw(const Shader &shader);

private:
    void load_model(const std::string &path);
    void process_node(aiNode *node, const aiScene *scene);
    Mesh process_mesh(aiMesh *mesh, const aiScene *scene);
    std::vector<Texture> load_material_textures(aiMaterial *mat, aiTextureType type,
                                                Texture::TextureType tex_type);

    std::vector<Mesh> meshes;
    std::vector<Texture> textures_loaded;
    std::string directory;
};

#include <string>

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

Model::~Model() {
    for (const auto &mesh : meshes) {
        mesh.destroy();
    }
}

void Model::draw(const Shader &shader) {
    for (const auto &mesh : meshes)
        mesh.draw(shader);
}

void Model::load_model(const std::string &path) {
    Assimp::Importer importer;
    const aiScene *scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_JoinIdenticalVertices);
    if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
        std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl;
        return;
    }

    directory = path.substr(0, path.find_last_of("/"));
    std::cout << "load_model(" << path << ")" << std::endl;
    process_node(scene->mRootNode, scene);
    std::cout << meshes.size() << std::endl;
}

void Model::process_node(aiNode *node, const aiScene *scene) {
    // process each mesh located at the current node
    for (unsigned int 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]];
        meshes.push_back(process_mesh(mesh, scene));
    }
    // after we've processed all of the meshes (if any) we then recursively process each of the children nodes
    for (unsigned int i = 0; i < node->mNumChildren; i++) {
        process_node(node->mChildren[i], scene);
    }
}

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

    // fill in vertex data form the model info
    for (int i = 0; i < mesh->mNumVertices; i++) {
        Vertex vertex;
        glm::vec3 temp_vec;
        // get the position data
        temp_vec.x      = mesh->mVertices[i].x;
        temp_vec.y      = mesh->mVertices[i].y;
        temp_vec.z      = mesh->mVertices[i].z;
        vertex.position = temp_vec;
        // get the normal data
        temp_vec.x     = mesh->mNormals[i].x;
        temp_vec.y     = mesh->mNormals[i].y;
        temp_vec.z     = mesh->mNormals[i].z;
        vertex.normals = temp_vec;
        // get the uv data
        if (mesh->mTextureCoords[0]) {
            glm::vec2 uv_data;
            uv_data.x = mesh->mTextureCoords[0][i].x;
            uv_data.y = mesh->mTextureCoords[0][i].y;
            vertex.uv = uv_data;
        } else
            vertex.uv = glm::vec2(0.0f, 0.0f);
        vertices.push_back(vertex);
    }
    for (int i = 0; i < mesh->mNumFaces; i++) {
        aiFace face = mesh->mFaces[i];
        for (int j = 0; j < face.mNumIndices; j++)
            indices.push_back(face.mIndices[j]);
    }

    if (mesh->mMaterialIndex >= 0) {
        aiMaterial *mat                   = scene->mMaterials[mesh->mMaterialIndex];
        std::vector<Texture> diffuse_maps = load_material_textures(mat, aiTextureType_DIFFUSE, Texture::TextureType::DIFFUSE);
        textures.insert(textures.end(), diffuse_maps.begin(), diffuse_maps.end());
        std::vector<Texture> specular_maps = load_material_textures(mat, aiTextureType_SPECULAR, Texture::TextureType::SPECULAR);
        textures.insert(textures.end(), specular_maps.begin(), specular_maps.end());
        std::vector<Texture> emission_maps = load_material_textures(mat, aiTextureType_EMISSIVE, Texture::TextureType::EMISSION);
        textures.insert(textures.end(), emission_maps.begin(), emission_maps.end());
    }

    return Mesh(vertices, indices, textures);
}

std::vector<Texture> Model::load_material_textures(aiMaterial *mat, aiTextureType type, Texture::TextureType tex_type) {
    std::vector<Texture> textures;
    for (int i = 0; i < mat->GetTextureCount(type); i++) {
        aiString str;
        mat->GetTexture(type, i, &str);
        bool skip = false;
        for (int j = 0; j < textures_loaded.size(); j++) {
            if (std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0) {
                textures.push_back(textures_loaded[j]);
                skip = true;
                break;
            }
        }
        if (!skip) {
            Texture tex = ResourceManager::load_ogl_texture_from_path(directory + "/" + str.C_Str(), tex_type);
            tex.path    = str.C_Str();
            textures.push_back(tex);
            textures_loaded.push_back(tex);
        }
    }
    return textures;
}

Mesh.cpp

代码语言:javascript
复制
struct Vertex {
    glm::vec3 position;
    glm::vec3 normals;
    glm::vec2 uv;
};

class Mesh {
public:
    std::vector<Vertex> vertices;
    std::vector<ui32> indices;
    std::vector<Texture> textures;

    Mesh(const std::vector<Vertex> &vertices, const std::vector<ui32> &indices, const std::vector<Texture> &textures);
    ~Mesh();
    void draw(const Shader &shader) const;
    void destroy() const;

private:
    ui32 vao, vbo, ebo;
    void setup_mesh();
};

Mesh::Mesh(const std::vector<Vertex> &vertices, const std::vector<ui32> &indices, const std::vector<Texture> &textures) : vertices(vertices), indices(indices), textures(textures) {
    setup_mesh();
}

Mesh::~Mesh() {}

void Mesh::setup_mesh() {
    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);

    // vertex positions
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr);
    // vertex normals
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *) offsetof(Vertex, normals));
    // vertex texture coords
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *) offsetof(Vertex, uv));

    glBindVertexArray(0);
}

void Mesh::draw(const Shader &shader) const {
    ui32 no_diffuse  = 1;
    ui32 no_specular = 1;
    ui32 no_emission = 1;

    for (int i = 0; i < textures.size(); i++) {
        glActiveTexture(GL_TEXTURE0 + i);
        std::string n, base_name;
        base_name = textures[i].type;
        if (std::strcmp(base_name.c_str(), "texture_diffuse") == 0)
            n = std::to_string(no_diffuse++);
        else if (std::strcmp(base_name.c_str(), "texture_specular") == 0)
            n = std::to_string(no_specular++);// transfer unsigned int to string
        else if (std::strcmp(base_name.c_str(), "texture_emission") == 0)
            n = std::to_string(no_emission++);// transfer unsigned int to string
        shader.setInt("material." + base_name + n, i);
        glBindTexture(GL_TEXTURE_2D, textures[i].id);
    }

    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
    glActiveTexture(GL_TEXTURE0);
}

void Mesh::destroy() const {
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ebo);
    for (const auto &texture : textures)
        glDeleteTextures(1, &texture.id);
}

更多信息:渲染是简单的香草正演渲染。

EN

回答 1

Stack Overflow用户

发布于 2022-07-27 01:20:37

400网格和200万三角形

400个不同的网格?如果是的话,那就简化你的模型,这太荒谬了。如果不是,那就使用实例。400张平局电话也同样荒谬。

然而,当我制作屏幕大小的窗口(2560x1600)时,性能大大下降到大约15-20 fps。

虽然程序的总体架构几乎无法挽救,但这句话表明,至少有一部分问题是,您遇到了图形卡的填充速率限制(至少忽略了它所做的大量时间,因为您忙于遍历随机对象,一个接一个地绘制它们)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73130234

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档