我正在使用Assimp在我的模型加载器中实现动画;用于渲染的C ++ / OpenGL。我一直在关注本教程:http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html。我只想说我没有完全遵循教程,因为有一些我不同意代码,所以我改编了它。请注意,我不会使用作者所使用的数学成分,所以我使用了glm。无论如何,问题在于有时我的程序运行,而在其他时候它不会运行。当我运行我的程序时,它会运行然后立即崩溃,而在其他时候它会像往常一样运行。
需要考虑的一些事项:
在添加动画/加载骨骼之前,模型加载器完全正常工作并加载模型而不会导致任何崩溃;
没有骨头的模型仍然可以正常加载;只有在加载骨骼的模型时才会出现问题。
请注意,正在渲染骨骼中的NOTHING。我甚至没有开始将骨骼分配给顶点属性;甚至没有对着色器进行修改。
一切都在一个线程上运行;还没有多线程......
所以,我自然而然地接受了实际加载骨骼的这段代码。我调试了应用程序,发现问题主要在于:
Mesh* processMesh(uint meshIndex, aiMesh *mesh)
{
vector<VertexBoneData> bones;
bones.resize(mesh->mNumVertices);
// .. getting other mesh data
if (pAnimate)
{
for (uint i = 0; i < mesh->mNumBones; i++)
{
uint boneIndex = 0;
string boneName(mesh->mBones[i]->mName.data);
auto it = pBoneMap.find(boneName);
if (it == pBoneMap.end())
{
boneIndex = pNumBones;
++pNumBones;
BoneInfo bi;
pBoneInfo.push_back(bi);
auto tempMat = mesh->mBones[i]->mOffsetMatrix;
pBoneInfo[boneIndex].boneOffset = to_glm_mat4(tempMat);
pBoneMap[boneName] = boneIndex;
}
else boneIndex = pBoneMap[boneName];
for (uint j = 0; j < mesh->mBones[i]->mNumWeights; j++)
{
uint vertexID = mesh->mBones[i]->mWeights[j].mVertexId;
float weit = mesh->mBones[i]->mWeights[j].mWeight;
bones.at(vertexID).addBoneData(boneIndex, weit);
}
}
}
}
在最后一行中,作者使用[]
运算符来访问元素,但我决定使用&#39; .at
进行范围检查。因此定义函数to_glm_mat4
:
glm::mat4 to_glm_mat4(const aiMatrix4x4 &m)
{
glm::mat4 to;
to[0][0] = m.a1; to[1][0] = m.a2;
to[2][0] = m.a3; to[3][0] = m.a4;
to[0][1] = m.b1; to[1][1] = m.b2;
to[2][1] = m.b3; to[3][1] = m.b4;
to[0][2] = m.c1; to[1][2] = m.c2;
to[2][2] = m.c3; to[3][2] = m.c4;
to[0][3] = m.d1; to[1][3] = m.d2;
to[2][3] = m.d3; to[3][3] = m.d4;
return to;
}
我还必须更改VertexBoneData,因为它使用了我认为有缺陷的原始数组:
struct VertexBoneData { 矢量boneIDs; 矢量权重;
VertexBoneData()
{
reset();
boneIDs.resize(NUM_BONES_PER_VERTEX);
weights.resize(NUM_BONES_PER_VERTEX);
}
void reset()
{
boneIDs.clear();
weights.clear();
}
void addBoneData(unsigned int boneID, float weight)
{
for (uint i = 0; i < boneIDs.size(); i++)
{
if (weights.at(i) == 0.0) // SEG FAULT HERE
{
boneIDs.at(i) = boneID;
weights.at(i) = weight;
return;
}
}
assert(0);
}
};
现在,我并不完全确定导致崩溃的原因,但最令我困惑的是有时程序运行(暗示代码不一定是罪魁祸首)。所以我决定做一个调试 - 粉碎,其中涉及我检查每个骨头(我跳过了一些;有很多骨头!)并发现在所有骨骼都被加载后我会得到这个非常奇怪的错误:
No source available for "drm_intel_bo_unreference() at 0x7fffec369ed9"
有时我会收到此错误:
Error in '/home/.../: corrupted double-linked list (not small): 0x00000 etc ***
有时我会从glm获得有关vec4实例化的seg错误;
有时......我的程序运行时没有崩溃!
公平地说,在我的笔记本电脑上实施动画可能会非常苛刻,所以可能是CPU / GPU问题,因为它无法在一次吞咽中处理如此多的数据,这导致了这一点崩溃。我的理论是,由于它无法处理那么多数据,因此数据永远不会分配给向量。
我没有使用任何多线程,但它已经在我脑海中浮现。我认为可能是CPU无法处理如此多的数据因此机会运行。如果我实现了线程,那么骨加载是在另一个线程上完成的;或者更好,使用互斥锁,因为我发现通过缓慢地调试应用程序程序运行,这是有道理的,因为每个任务被分解成块;这就是互斥技术本身所做的事情。
为了争论,并且没有嘲弄,我的技术规格:
Ubuntu 15.04 64-bit
Intel i5 dual-core
Intel HD 5500
Mesa 10.5.9 (OpenGL 3.3)
Programming on Eclipse Mars
我因此问,究竟是什么导致了这些intel_drm错误?
答案 0 :(得分:0)
我已经复制了这个问题,并发现在加载骨骼时缺少多线程可能会出现问题。我决定将加载骨骼勘误表移动到前面教程中规定的自己的功能中。我后来做的是:
if (pAnimate)
{
std::thread t1[&] {
loadBones(meshIndex, mesh, bones);
});
t1.join();
}
上面的lambda函数有[&]
表示我们将所有内容作为引用传递,以确保不创建副本。为了防止任何外力“触摸”loadBones(..)
函数中的数据,我在函数中安装了一个互斥量,如下所示:
void ModelLoader::loadBones(uint meshIndex, const aiMesh *mesh, std::vector<VertexBoneData> &bones)
{
std::mutex mut;
std::lock_guard<std::mutex> lock(mut);
// load bones
}
这只是一个快速而肮脏的修复。它可能不适用于所有人,并且无法保证程序将无故障运行。
以下是一些测试结果:
Sans threading & mutex: program runs 0 out of 3 times in a row
With threading; sans mutex: program runs 2 out of 3 times in a row
With threading & mutex: program runs 3 out of 3 times in a row
如果您使用的是Linux,请务必关联pthread
以及<thread>
和<mutex>
。欢迎提出关于线程优化的建议!