描述:
这个问题查了一周了. 自己解决不掉, 周围也没有编程的朋友.
环境描述:
QT4.11
编译器 MSVC2017
32bit-Debug
使用了库Assimp, stb_image, glm
(没错, 这么熟悉的库, 在学习learnopengl网站上的内容)
问题:
在继承了QOpenGLWidget
的GLManager
类中的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);
}
修改model的时候调一下makecurrent和donecurrent试试?