我在ASSIMP网格加载中遇到了一个奇怪的问题。这就是问题,我有一个复杂的模型obj文件来显示一个字符,该模型有4个子网格,在我的代码中,我封装了网格类以获取相关数据(顶点,索引,法线...),当我将4个网格绘制在一起时(在for圈中),我总是得到错误的结果:
但是如果我一次只加载一个网格(硬编码我的assimp加载类来做到这一点),并且只绘制一个网格,那么我就可以正确绘制网格(但是仅当我加载复杂模型obj时才会出现此问题文件,而不是立方体或平面,我可以加载多个立方体和平面obj文件并将它们绘制在一起):
这是我的ASSIMP加载类代码,我不知道我的问题在哪里,请帮助我:
#include "AssetImport.h"
#include "Mesh.h"
#include "Model.h"
#include "ModelMgr.h"
#include "TextureMgr.h"
#include <string>
using namespace Assimp;
AssetImport::AssetImport()
{
}
AssetImport::~AssetImport()
{
}
int AssetImport::LoadModel(const char *path)
{
Importer import;
const aiScene *scene = import.ReadFile(path, aiProcess_Triangulate
| aiProcess_FlipUVs
| aiProcess_CalcTangentSpace
| aiProcess_GenNormals);
if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
return -1;
}
m_prePath = path;
auto index = m_prePath.lastIndexOf("/");
if (-1 != index) {
m_prePath = m_prePath.left(index + 1);
}
HandleChildNode(scene, scene->mRootNode);
return 0;
}
int AssetImport::HandleChildNode(const aiScene *scene, aiNode *node)
{
unsigned int numChild = node->mNumChildren;
for (unsigned int a = 0; a < 1; ++a)
{
**auto child = node->mChildren[3];// here is the hard code**
if (child->mNumChildren > 0) {
HandleChildNode(scene, child);
}
if (0) {
continue;
}
// create a new model for a child
Model *mod = ModelMgr::Instance().CreateNewModel();
mod->SetModelName(child->mName.C_Str());
auto numMeshes = child->mNumMeshes;
for (unsigned int i = 0; i < numMeshes; ++i)
{
// create new sub mesh, then you can add it to one model
Mesh *m = new Mesh;
auto mesh = scene->mMeshes[child->mMeshes[i]];
//handle the mesh's materials
auto mat = scene->mMaterials[mesh->mMaterialIndex];
HandleMeshMaterial(mat, m);
// add vertex info
for (unsigned int j = 0; j < mesh->mNumVertices; ++j)
{
auto vert = mesh->mVertices[j];
Mesh::VertInfo info;
info.pos = QVector3D(mesh->mVertices[j].x, mesh->mVertices[j].y, mesh->mVertices[j].z);
info.color = QVector4D(0.8f, 0.8f, 0.8f, 1);
info.normal = QVector3D(mesh->mNormals[j].x, mesh->mNormals[j].y, mesh->mNormals[j].z);
if (nullptr != mesh->mTangents)
{
info.tangent = QVector4D(mesh->mTangents[j].x, mesh->mTangents[j].y, mesh->mTangents[j].z, 0);
}
if (nullptr != mesh->mBitangents)
{
info.bitangent = QVector4D(mesh->mBitangents[j].x, mesh->mBitangents[j].y, mesh->mBitangents[j].z, 0);
}
if (nullptr != mesh->mTextureCoords[0])
{
info.uv1 = QVector2D(mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y);
}
m->AddVertInfo(info);
}
// add index info
for (unsigned int j = 0; j < mesh->mNumFaces; ++j)
{
auto face = mesh->mFaces[j];
for (unsigned int k = 0; k < face.mNumIndices; ++k)
{
m->AddIndex(face.mIndices[k]);
}
}
m->BindBuffer();
mod->AddMesh(m);
}
}
return 0;
}
int AssetImport::HandleMeshMaterial(aiMaterial *mat, Mesh *mesh)
{
auto diffuseTexCount = mat->GetTextureCount(aiTextureType_DIFFUSE);
auto specularTexCount = mat->GetTextureCount(aiTextureType_SPECULAR);
for (unsigned int i = 0; i < diffuseTexCount; ++i)
{
aiString path;
mat->GetTexture(aiTextureType_DIFFUSE, i, &path);
QString strPath = path.C_Str();
strPath.replace("/", "\\");
auto index = strPath.lastIndexOf("\\");
if (-1 != index) {
strPath = strPath.right(strPath.length() - index - 1);
strPath.prepend(m_prePath);
}
auto texID = TextureMgr::Instance().LoadTexture(strPath.toLocal8Bit());
mesh->SetDiffuseTexID(texID);
}
for (unsigned int i = 0; i < specularTexCount; ++i)
{
aiString strPath;
mat->GetTexture(aiTextureType_SPECULAR, i, &strPath);
}
return 0;
}
这是我的网格物体类(带有绘制功能):
#include "Mesh.h"
#include "TextureMgr.h"
#include "ShaderHelper.h"
#include "PreDef.h"
#include "QMatrix4x4"
Mesh::Mesh()
:m_vao(0), m_vbo(0), m_vaeo(0), m_instanceBufferId(0), m_tbo1(0)
, m_drawType(Triangle)
, m_skyboxTexID(0), m_projTexID(0), m_normalmapTexID(0)
, m_diffuseTex1ID(0)
{
initializeOpenGLFunctions();
m_normalmapTexID = TextureMgr::Instance().LoadTexture("./models/brickwall_normal.jpg");
}
Mesh::~Mesh()
{
}
void Mesh::AddVertex(QVector3D vert)
{
m_vertices.push_back(vert.x());
m_vertices.push_back(vert.y());
m_vertices.push_back(vert.z());
}
const float* Mesh::GetVertices() const
{
return m_vertices.data();
}
int Mesh::GetVerticesMemSize() const
{
return m_vertices.size() * sizeof(float);
}
int Mesh::GetVerticesNum() const
{
return m_vertices.size() / 3;
}
void Mesh::AddColor(QVector4D color)
{
m_colors.push_back(color.x());
m_colors.push_back(color.y());
m_colors.push_back(color.z());
m_colors.push_back(color.w());
}
const float* Mesh::GetColors() const
{
return m_colors.data();
}
int Mesh::GetColorsMemSize() const
{
return m_colors.size() * sizeof(float);
}
void Mesh::AddNormal(QVector3D normal)
{
m_normals.append(normal.x());
m_normals.append(normal.y());
m_normals.append(normal.z());
}
const float* Mesh::GetNormals() const
{
return m_normals.data();
}
int Mesh::GetNormalsMemSize() const
{
return m_normals.size() * sizeof(float);
}
int Mesh::GetNormalsNum() const
{
return m_normals.size() / 3;
}
void Mesh::AddTangent(QVector4D tangent)
{
m_tangents.append(tangent.x());
m_tangents.append(tangent.y());
m_tangents.append(tangent.z());
m_tangents.append(tangent.w());
}
const float* Mesh::GetTangents() const
{
return m_tangents.data();
}
int Mesh::GetTangentsMemSize() const
{
return m_tangents.size() * sizeof(float);
}
int Mesh::GetTangentsNum() const
{
return m_tangents.size() / 4;
}
void Mesh::AddBitangent(QVector4D binormal)
{
m_binormals.append(binormal.x());
m_binormals.append(binormal.y());
m_binormals.append(binormal.z());
m_binormals.append(binormal.w());
}
const float* Mesh::GetBitangents() const
{
return m_binormals.data();
}
int Mesh::GetBitangentsMemSize() const
{
return m_binormals.size() * sizeof(float);
}
int Mesh::GetBitangentsNum() const
{
return m_binormals.size() / 4;
}
void Mesh::AddUv1(QVector2D uv)
{
m_uvs1.append(uv.x());
m_uvs1.append(uv.y());
}
const float* Mesh::GetUvs1() const
{
return m_uvs1.data();
}
int Mesh::GetUvs1MemSize() const
{
return m_uvs1.size() * sizeof(float);
}
int Mesh::GetUvs1Num() const
{
return m_uvs1.size() / 2;
}
void Mesh::AddVertInfo(const VertInfo &info)
{
m_vertInfoVec.push_back(info);
AddVertex(info.pos);
AddColor(info.color);
AddNormal(info.normal);
AddTangent(info.tangent);
AddBitangent(info.bitangent);
AddUv1(info.uv1);
}
void Mesh::BindBuffer()
{
// init the shaders first
ShaderHelper::Instance();
BindVertexRelevantBuffer();
}
void Mesh::BindVertexRelevantBuffer()
{
const GLuint *vertex_indices = GetIndices();
const GLfloat *vertex_positions = GetVertices();
const GLfloat *vertex_uvs = GetUvs1();
const GLfloat *vertex_tangents = GetTangents();
const GLfloat *vertex_bitangents = GetBitangents();
const GLfloat *vertex_normals = GetNormals();
// set element array(index array) buffer
glGenBuffers(1, &m_vaeo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vaeo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndicesMemSize(), vertex_indices, GL_STATIC_DRAW);
// set vertex array object
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glVertexArrayElementBuffer(m_vao, m_vaeo);
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize()
+ GetTangentsMemSize() + GetBitangentsMemSize() + GetNormalsMemSize() /*+ 16 * sizeof(GLfloat) * 10*/, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, GetVerticesMemSize(), vertex_positions);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize(), GetUvs1MemSize(), vertex_uvs);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize(), GetTangentsMemSize(), vertex_tangents);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize(),
GetBitangentsMemSize(), vertex_bitangents);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize()
+ GetTangentsMemSize() + GetBitangentsMemSize(),
GetNormalsMemSize(), vertex_normals);
GLint positionLoc = 0;
GLint uvLoc = 1;
GLint tangentLoc = 2;
GLint bitangentLoc = 3;
GLint normalLoc = 4;
GLint modelMatLoc = -1;
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, (0));
glEnableVertexAttribArray(positionLoc);
glVertexAttribPointer(uvLoc, 2, GL_FLOAT, GL_FALSE, 0, (void*)(GetVerticesMemSize()));
glEnableVertexAttribArray(uvLoc);
glVertexAttribPointer(tangentLoc, 3, GL_FLOAT, GL_FALSE, 0, (void*)(GetVerticesMemSize() + GetUvs1MemSize()));
glEnableVertexAttribArray(tangentLoc);
glVertexAttribPointer(bitangentLoc, 3, GL_FLOAT, GL_FALSE, 0,
(void*)(GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize()));
glEnableVertexAttribArray(bitangentLoc);
glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0,
(void*)(GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize() + GetBitangentsMemSize()));
glEnableVertexAttribArray(normalLoc);
// multi instances model matrix
if (-1 != modelMatLoc) {
// generate the new buffer for instances
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &m_instanceBufferId);
glBindBuffer(GL_ARRAY_BUFFER, m_instanceBufferId);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16 * 10, nullptr, GL_STATIC_DRAW);
// m_instanceBufferId = m_vbo;
// mat4 type take space of 4 vec4, so we should circle 4 times
for (int i = 0; i < 4; ++i)
{
glVertexAttribPointer(modelMatLoc + i, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 16,
(void*)(/*GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize() + GetBitangentsMemSize() + GetNormalsMemSize() +*/ sizeof(GLfloat) * 4 * i));
glEnableVertexAttribArray(modelMatLoc + i);
// implement the multi instances
glVertexAttribDivisor(modelMatLoc + i, 1);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// sampler buffer bind
glGenBuffers(1, &m_tbo1);
glBindBuffer(GL_TEXTURE_BUFFER, m_tbo1);
glBufferData(GL_TEXTURE_BUFFER, sizeof(GLfloat) * 16 * 10, nullptr, GL_STATIC_DRAW);
GLuint tex1;
glCreateTextures(GL_TEXTURE_BUFFER, 1, &tex1);
glTextureBuffer(tex1, GL_RGBA32F, m_tbo1);
glBindTextureUnit(0, m_tbo1);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
}
GLuint Mesh::GetVao()
{
return m_vao;
}
void Mesh::AddIndex(unsigned int index)
{
m_indices.push_back(index);
}
void Mesh::AddIndexVec(QVector<unsigned int> &indexVec)
{
m_indices = indexVec;
}
const unsigned int* Mesh::GetIndices() const
{
return m_indices.data();
}
int Mesh::GetIndicesMemSize() const
{
return m_indices.size() * sizeof(unsigned int);
}
int Mesh::GetIndicesNum() const
{
return m_indices.size();
}
GLuint Mesh::GetMultiInstanceModelMatrixOffset() const
{
return (GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize()
+ GetBitangentsMemSize() + GetNormalsMemSize());
}
GLuint Mesh::GetInstancesBufferId() const
{
return m_instanceBufferId;
}
void Mesh::SetDiffuseTexID(GLuint id)
{
m_diffuseTex1ID = id;
}
void Mesh::AddSpecularTexture(GLuint id)
{
m_specularTex1ID = id;
}
GLuint Mesh::GetTextureBuffer1() const
{
return m_tbo1;
}
void Mesh::InitSkybox()
{
m_skyboxTexID = TextureMgr::Instance().LoadTexture("skybox");
}
void Mesh::InitProjTex()
{
m_projTexID = TextureMgr::Instance().LoadTexture("./textures/proj.jpg");
}
void Mesh::SetDrawType(eDrawType type)
{
m_drawType = type;
}
void Mesh::Draw(QMatrix4x4 matVP, QMatrix4x4 matModel, QVector3D camPos, QMatrix4x4 matProj, QMatrix4x4 matView,
QMatrix4x4 matOrtho)
{
if (0 != m_diffuseTex1ID)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_diffuseTex1ID);
}
if (0 != m_normalmapTexID)
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_normalmapTexID);
}
if (0 != m_skyboxTexID) {
glBindTexture(GL_TEXTURE_CUBE_MAP, m_skyboxTexID);
matModel.translate(camPos);
matModel.scale(10000);
glCullFace(GL_FRONT);
glDepthMask(0);
ShaderHelper::Instance().SetShaderType(ShaderHelper::Skybox);
}
else if (0 != m_projTexID) {
glActiveTexture(GL_TEXTURE10);
glBindTexture(GL_TEXTURE_2D, m_projTexID);
ShaderHelper::Instance().SetShaderType(ShaderHelper::Decal);
}
glBindVertexArray(GetVao());
matVP = matVP * matModel;
ShaderHelper::Instance().SetMVPMatrix(matVP);
ShaderHelper::Instance().SetWorldMatrix(matModel);
ShaderHelper::Instance().SetCamWorldPos(camPos);
ShaderHelper::Instance().SetProjMat(matProj);
ShaderHelper::Instance().SetViewMat(matView);
ShaderHelper::Instance().SetOrthoMat(matOrtho);
// Draw element(with indices)
if (Triangle == m_drawType)
{
glDrawElements(GL_TRIANGLES, GetIndicesNum(), GL_UNSIGNED_INT, 0);
}
else if (Point == m_drawType)
{
glDrawArrays(GL_POINTS, 0, GetVerticesNum());
}
if (0 != m_skyboxTexID) {
glCullFace(GL_BACK);
glDepthMask(1);
}
glBindVertexArray(0);
}
这里是主要绘制功能:
void OpenWidget::paintGL()
{
static int i = 0;
if (0 == i){
++i;
CreateOffScreenFrameBufferTexture();
}
glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return;
}
paintClearAndReset();
QMatrix4x4 matVP = m_cam->GetVPMatrix();
QMatrix4x4 matProj = m_cam->GetProjectionMatrix();
QMatrix4x4 matOrtho = m_cam->GetOrthographicMatrix();
QMatrix4x4 matView = m_cam->GetViewMatrix();
QVector3D camPos = m_cam->GetCamPos().toVector3D();
auto modelNum = ModelMgr::Instance().GetModelNum();
for (unsigned int i = 0; i < modelNum; ++i)
{
Model *mod = ModelMgr::Instance().GetModel(i);
SwitchShader(ShaderHelper::Default);
QMatrix4x4 matModel = mod->GetWorldMat();
mod->Draw(matVP, matModel, camPos, matProj, matView, matOrtho);
if (modelNum - 1 == i) {
Model *pBox = ModelMgr::Instance().FindModelByName("Box001");
// SwitchShader(ShaderHelper::PlaneClip);
// glFrontFace(GL_CW);
// glEnable(GL_CLIP_PLANE0);
// glStencilMask(0xff);
// glStencilFunc(GL_ALWAYS, 1, 0xff);
// glColorMask(0, 0, 0, 0);
//
// pBox->Draw(matVP, pBox->GetWorldMat(), camPos);
// glFrontFace(GL_CCW);
// glDisable(GL_CLIP_PLANE0);
// glColorMask(1, 1, 1, 1);
//
// glStencilMask(0);
// glStencilFunc(GL_EQUAL, 1, 0xff);
// SwitchShader(ShaderHelper::PureColor);
// pBox->Draw(matVP, pBox->GetWorldMat(), camPos);
}
}
//-----------------------------------------------
// test the frame buffer
DrawOffScreenTexture();
}
最后,我发现问题出在哪里,我暂时放弃了这个问题,但是今天,我的skybox(cubemap)遇到了另一个问题,我只能在绘制队列的最后绘制正确的skybox,否则,多维数据集贴图只能显示一张脸,因此,对我而言不再是捷径了,我决定解决此问题,经过许多小时的调试, >: // set element array(index array) buffer
glGenBuffers(1, &m_vaeo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vaeo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndicesMemSize(), vertex_indices, GL_STATIC_DRAW);
// set vertex array object
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glVertexArrayElementBuffer(m_vao, m_vaeo);
您应该始终先创建并绑定VAO:
// set vertex array object
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
// set element array(index array) buffer
glGenBuffers(1, &m_vaeo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vaeo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndicesMemSize(), vertex_indices, GL_STATIC_DRAW);
glVertexArrayElementBuffer(m_vao, m_vaeo);
但是,毕竟,我认为它是如此隐式,因为在创建元素缓冲区后,您可以将元素绑定到vao,似乎在生成元素缓冲区时,与vao无关,我可以做什么,请下次再小心。