生成intel_drm错误的动画

时间:2015-09-08 12:32:09

标签: c++ opengl animation assimp

我正在使用Assimp在我的模型加载器中实现动画;用于渲染的C ++ / OpenGL。我一直在关注本教程:http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html。我只想说我没有完全遵循教程,因为有一些我不同意代码,所以我改编了它。请注意,我不会使用作​​者所使用的数学成分,所以我使用了glm。无论如何,问题在于有时我的程序运行,而在其他时候它不会运行。当我运行我的程序时,它会运行然后立即崩溃,而在其他时候它会像往常一样运行。

需要考虑的一些事项:

  1. 在添加动画/加载骨骼之前,模型加载器完全正常工作并加载模型而不会导致任何崩溃;

  2. 没有骨头的模型仍然可以正常加载;只有在加载骨骼的模型时才会出现问题。

  3. 请注意,正在渲染骨骼中的NOTHING。我甚至没有开始将骨骼分配给顶点属性;甚至没有对着色器进行修改。

  4. 一切都在一个线程上运行;还没有多线程......

  5. 所以,我自然而然地接受了实际加载骨骼的这段代码。我调试了应用程序,发现问题主要在于:

    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错误?

1 个答案:

答案 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>。欢迎提出关于线程优化的建议!