能否帮忙解决一个QT平台的OpenGL问题?

描述:
这个问题查了一周了. 自己解决不掉, 周围也没有编程的朋友.

环境描述:
QT4.11
编译器 MSVC2017
32bit-Debug
使用了库Assimp, stb_image, glm
(没错, 这么熟悉的库, 在学习learnopengl网站上的内容)

问题:

在继承了QOpenGLWidgetGLManager类中的initializeGL()函数里new Model是可以在GLManager中的paintGL()中画出来的.

但是为了实现打开对话框选择模型进行加载, 当把 new Model 移动到initializeGL()外面去就不能再在paintGL()中画出来了.

我觉得GLManager, Model, Mesh 这三个类是比较重要的, 下面给出这三个类的部分函数代码, 如果你觉得问题不在这里, 请评论给我, 我会贴出别的更多的代码.

下面给出代码:
GLManager:

class GLManager : public QOpenGLWidget{
public: 
  GLManager(){flag=1;}
  Model* ourModel;
  int flag;
  //我有一个函数来调用setModel把路径传进来
  void setModel(const char* path){
    ourModel = new Model(core, path); flag=0;
  }
  virtual  void  initializeGL(){
    core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();

    //载入shader
    ResourceManager::loadShader("model",  "D:/1.model\_loading.vs",  "D:/1.model\_loading.fs");
    /*
    如果不在setModel调用, 在这里写死路径调用是能显示模型的!
    ourModel = new Model(core, "D:/cube.obj"); 
    */
    //camera
    camera = new Camera(glm::vec3(0.0f, 0.0f, 3.0f));
  }
  virtual  void  paintGL(){
    ResourceManager::getShader("model").use();
    glm::mat4 projection = glm::perspective(glm::radians(camera->Zoom),  (float)width()/(float)height(),  0.1f,  1000.0f);
    glm::mat4  view = camera->GetViewMatrix(); ResourceManager::getShader("model").setMatrix4f("projection",  projection);
    ResourceManager::getShader("model").setMatrix4f("view",  view);
    

    glm::mat4  model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); 
    model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f)); 
    ResourceManager::getShader("model").setMatrix4f("model",  model);
    
    if(this->flag==0)
      ourModel->Draw(ResourceManager::getShader("model"));
  }
}

Model:

  Model::Model(QOpenGLFunctions_3_3_Core* core,  const char *path)
  {
    this->core = core;
    loadModel(path);  //从路径载入模型
  }
  void Model::loadModel(string path)
  {
    // read file via ASSIMP
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
    // check for errors
    if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
    {
        qDebug() << "ERROR::AS  SIMP:: " << importer.GetErrorString() << endl;
        return;
    }
    // retrieve the directory path of the filepath
    directory = path.substr(0, path.find_last_of('/'));

    // 递归处理 ASSIMP's 根节点
    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)
{
    // data to fill
            vector<Vertex> vertices;
            vector<unsigned int> indices;
            vector<Texture> textures;

            // walk through each of the mesh's vertices
            qDebug()<<"该物体共计有mesh"<<mesh->mNumVertices;
            for(unsigned int 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;
                qDebug()<<"该物体的Positions: ("<<vector.x<<vector.y<<vector.z<<")";
                // normals
                vector.x = mesh->mNormals[i].x;
                vector.y = mesh->mNormals[i].y;
                vector.z = mesh->mNormals[i].z;
                vertex.Normal = vector;
                qDebug()<<"该物体的Normal: ("<<vector.x<<vector.y<<vector.z<<")";
                // 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;
                    qDebug()<<"该物体的TexCoords: ("<<vec.x<<vec.y<<")";
                }
                else
                    vertex.TexCoords = glm::vec2(0.0f, 0.0f);
                // tangent
                vector.x = mesh->mTangents[i].x;
                vector.y = mesh->mTangents[i].y;
                vector.z = mesh->mTangents[i].z;
                vertex.Tangent = vector;
                qDebug()<<"该物体的tangent: ("<<vector.x<<vector.y<<vector.z<<")";
                // bitangent
                vector.x = mesh->mBitangents[i].x;
                vector.y = mesh->mBitangents[i].y;
                vector.z = mesh->mBitangents[i].z;
                vertex.Bitangent = vector;
                qDebug()<<"该物体的bitangent: ("<<vector.x<<vector.y<<vector.z<<")";
                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(unsigned int 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(unsigned int j = 0; j < face.mNumIndices; j++)
                    indices.push_back(face.mIndices[j]);
            }
            // process materials
            aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];

            // 1. diffuse maps
            vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
            textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
            // 2. specular maps
            vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
            textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
            // 3. normal maps
            std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
            textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
            // 4. height maps
            std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
            textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());

            // return a mesh object created from the extracted mesh data
            return Mesh(core, vertices, indices, textures);
}

unsigned int Model::TextureFromFile(const char *path, const string &directory, bool gamma)
{
    string filename = string(path);
    filename = directory + '/' + filename;

    unsigned int textureID;
    core->glGenTextures(1, &textureID);

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

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

        core->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        core->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        core->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        core->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        qDebug() << "Texture SUCCESS!";
    }
    else
    {
        qDebug() << "Texture failed to load at path: " << path << endl;
    }

    return textureID;
}

Mesh:

struct Vertex {
    glm::vec3 Position;   //位置向量
    glm::vec3 Normal;     //法向量
    glm::vec2 TexCoords;  //纹理坐标向量
    glm::vec3 Tangent;    //
    glm::vec3 Bitangent;  //
};

struct Texture {
    unsigned int id;    //纹理id
    std::string type;   //纹理类型
    std::string path;  // 我们储存纹理的路径用于与其它纹理进行比较
};




Mesh::Mesh(QOpenGLFunctions_3_3_Core* core, std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<Texture> textures)
{
    this->core = core;
    this->vertices = vertices;
    this->indices = indices;
    this->textures = textures;
    setupMesh();
}

void Mesh::Draw(Shader shader)
{
    // bind appropriate textures
    unsigned int diffuseNr  = 1;
    unsigned int specularNr = 1;
    unsigned int normalNr   = 1;
    unsigned int heightNr   = 1;
    for(unsigned int i = 0; i < textures.size(); i++)
    {
        core->glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
        // retrieve texture number (the N in diffuse_textureN)
        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++); // transfer unsigned int to stream
        else if(name == "texture_normal")
            number = std::to_string(normalNr++); // transfer unsigned int to stream
        else if(name == "texture_height")
            number = std::to_string(heightNr++); // transfer unsigned int to stream

        // now set the sampler to the correct texture unit
        core->glUniform1i(shader.uniformLocation((name + number).c_str()), i);
        // and finally bind the texture
        core->glBindTexture(GL_TEXTURE_2D, textures[i].id);
    }

    // draw mesh
    core->glBindVertexArray(VAO);
    core->glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
    core->glBindVertexArray(0);

    // always good practice to set everything back to defaults once configured.
    core->glActiveTexture(GL_TEXTURE0);
}

void Mesh::setupMesh()
{
    //创建 缓冲/数组
    core->glGenVertexArrays(1, &VAO);
    core->glGenBuffers(1, &VBO);
    core->glGenBuffers(1, &EBO);

    core->glBindVertexArray(VAO);
    //把数据载入顶点缓冲中
    core->glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //内存数据连续, 所以只写了vertices的首地址
    core->glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);


    core->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    core->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

    // 顶点位置
    core->glEnableVertexAttribArray(0);
    core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    // 顶点法线
    core->glEnableVertexAttribArray(1);
    core->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
    // 顶点纹理坐标
    core->glEnableVertexAttribArray(2);
    core->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
    // vertex tangent
    core->glEnableVertexAttribArray(3);
    core->glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
    // vertex bitangent
    core->glEnableVertexAttribArray(4);
    core->glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));
    // 取消绑定
    core->glBindVertexArray(0);
}
阅读 2.8k
1 个回答

修改model的时候调一下makecurrent和donecurrent试试?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题