मैंने थिन मैट्रिक्स द्वारा कंकाल एनीमेशन पर लोकप्रिय ट्यूटोरियल और एक अन्य कोड नमूना का अनुसरण किया GitHub

मेश रेंडरर्स बिना किसी एनिमेशन के ढूंढते हैं। लेकिन जैसे ही एनिमेशन लागू होते हैं यह तिरछा हो जाता है।

अगर मैं पहचान मैट्रिक्स को बोनट्रांसफॉर्म के रूप में पास करता हूं, तो यह काम करता है। इसमें काम करता है क्योंकि यह अभी भी बिना किसी एनीमेशन के ठीक से प्रस्तुत करता है।

इसके अलावा मैंने देखा कि मैं जिस कोलाडा फ़ाइल का उपयोग करता हूं वह Z का उपयोग करता है और मैं ऊपर के रूप में Y का उपयोग करता हूं। लेकिन मैं यह सुनिश्चित करने के लिए बिना किसी बदलाव के सभी डेटा निर्यात करता हूं कि सभी ट्रांसफॉर्म और वर्टेक्स डेटा काम करते हैं। मैं बाद में इसे समायोजित करने की योजना बना रहा हूं क्योंकि मैं निर्यात करता हूं ताकि डेटा वाई का भी उपयोग कर सके।

यहाँ कंकाल एनिमेशन के लिए मेरा कोड है:

हैडर:

class SkeletalAnimation {
        
        typedef struct Bone{
            int id;
            std::string name;
            glm::mat4 offset;
            std::vector<Bone> children;
        } Bone;

        typedef struct  {
            std::vector<float> translationTimestamps;
            std::vector<float> rotationTimetamps;
            std::vector<float> scalingTimetamps;

            std::vector<glm::vec3> translations;
            std::vector<glm::quat> rotations;
            std::vector<glm::vec3> scalings;
        } BoneTransforms;

        typedef struct Animation {
            float duration;
            float ticksPerSecond;
            std::unordered_map<std::string, BoneTransforms> boneTransforms;
            Animation(float pDuration, float ticksPerSecond) :
                duration(pDuration),
                ticksPerSecond(ticksPerSecond),
                boneTransforms({})
            {}
            Animation() {}
        } Animation;

        typedef std::unordered_map<std::string, std::pair<int, glm::mat4>> BoneData;
        typedef std::unordered_map<std::string, Animation> AnimationMap;
        typedef std::vector<glm::mat4> Pose;

        typedef struct{
            unsigned int segment;
            float fracture;
        } Segment;

        typedef struct {
            Pose pose;
            BoneData boneData;
            unsigned int boneCount;
            std::string name;
            Bone skeleton;
        } MeshEntry;

        typedef std::unordered_map<std::string, MeshEntry> MeshBoneMap;

    private:

        const std::string mPath;
        SDL_Renderer* mRenderer;
        
        std::vector<MeshEntry> mMeshEntries;
        std::vector<SkeletalMesh*> mMeshes;
        std::vector<ImageTexture*> mTextures;
        std::vector<unsigned int> mMeshToTexture;

        std::string* mCurrentAnimation;
        std::vector<std::string> mAnimations;

        AnimationMap mAnimationMap;
        Segment mCurrentSegment;
        glm::mat4 mGlobalInverseTransform;
        MeshBoneMap mMeshBoneMap;

        static glm::mat4 sIdentityMatrix;

        void LoadNode(aiNode* pNode, const aiScene* pScene);
        void LoadSkeletalMesh(aiMesh* pMesh, const aiScene* pScene);
        bool LoadBones(Bone& pBone, aiNode* pNode, BoneData& pBoneData);
        void LoadAnimations(const aiScene* pScene);
        void LoadMaterials(const aiScene* pScene);
        void Animate(float pDeltaTime, Bone& pSkeleton, Pose& pPose, glm::mat4& pParentTransform);

        static inline glm::mat4 aiToGlmMat4(const aiMatrix4x4& pAiMat);
        static inline glm::vec3 aiToGlmVec3(const aiVector3D& pAiVec);
        static inline glm::quat aiToGlmQuat(const aiQuaternion& pAiVec);
        static inline void GetSegment(Segment* pSegment,const std::vector<float>& pTimestamps,const float pDeltaTime);

    public:
        SkeletalAnimation(const std::string pPath, SDL_Renderer* pRenderer);
        ~SkeletalAnimation();

        void LoadAnimation();
        void GetAllAnimations(std::vector<std::string>* pAnimations);
        float GetAnimationDuration();
        void SetAnimationTime(float pTime);
        void SetAnimation(std::string pAnimation);
        void RenderAnimation(float pDeltaTime, SkeletalAnimationShader* pSkeletalAnimationShader);
        void RenderStill(SkeletalAnimationShader* pSkeletalAnimationShader);
        void ClearModel();
    };

स्रोत:

glm::mat4 SkeletalAnimation::sIdentityMatrix = glm::mat4();
    
        SkeletalAnimation::SkeletalAnimation(const std::string pPath, SDL_Renderer* pRenderer) :
            mPath(pPath),
            mRenderer(pRenderer),
            mCurrentAnimation(new std::string()),
            mAnimations({}),
            mAnimationMap({}),
            mMeshBoneMap({})
        {}

        SkeletalAnimation::~SkeletalAnimation() {
        
        }

        void SkeletalAnimation::LoadAnimation() {
            Assimp::Importer _importer;
            const aiScene* _scene = _importer.ReadFile(mPath, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_JoinIdenticalVertices);

            if (!_scene) {
                SDL_Log("Assimp Error Loading Animation at path: %s \n Error: %s .", mPath.c_str(), _importer.GetErrorString());
                return;
            }

            
            mGlobalInverseTransform = glm::inverse(aiToGlmMat4(_scene->mRootNode->mTransformation));

            LoadNode(_scene->mRootNode, _scene);
            
            LoadAnimations(_scene);
            
            LoadMaterials(_scene);
            
        }

        void SkeletalAnimation::LoadNode(aiNode* pNode, const aiScene* pScene) {
            for (size_t i = 0; i < pNode->mNumMeshes; i++) {
                LoadSkeletalMesh(pScene->mMeshes[pNode->mMeshes[i]], pScene);
            }

            for (size_t i = 0; i < pNode->mNumChildren; i++) {
                LoadNode(pNode->mChildren[i], pScene);
            }
        }

        void SkeletalAnimation::LoadSkeletalMesh(aiMesh* pMesh, const aiScene* pScene) {

            MeshEntry _meshEntry;
            _meshEntry.boneCount = pMesh->mNumBones;
            _meshEntry.name = std::string(pMesh->mName.C_Str());
            _meshEntry.pose = {};
            _meshEntry.pose.resize(pMesh->mNumBones, sIdentityMatrix);
            _meshEntry.boneData = {};
            SkeletalMeshData _meshData;

            for (size_t i = 0; i < pMesh->mNumVertices; i++) {
                _meshData.vertices.insert(_meshData.vertices.end(),
                    {
                        pMesh->mVertices[i].x,
                        pMesh->mVertices[i].y , //Swaped Y and Z since Blender uses Z as up and I use Y as up.
                        pMesh->mVertices[i].z });

                if (pMesh->mTextureCoords[0]) {
                    _meshData.uvs.insert(_meshData.uvs.end(),
                        {
                            pMesh->mTextureCoords[0][i].x,
                            pMesh->mTextureCoords[0][i].y
                        });
                }
                else {
                    _meshData.uvs.insert(_meshData.uvs.end(),
                        {
                            0.0f,
                            0.0f
                        });
                }
                _meshData.normals.insert(_meshData.normals.end(),
                    {
                        pMesh->mNormals[i].x,
                        pMesh->mNormals[i].y ,
                        pMesh->mNormals[i].z });

                _meshData.boneIDs.insert(_meshData.boneIDs.end(), {
                    0,
                    0,
                    0,
                    0});

                _meshData.weights.insert(_meshData.weights.end(), {
                    0.0f,
                    0.0f,
                    0.0f,
                    0.0f});

            }

            for (size_t i = 0; i < pMesh->mNumFaces; i++) {
                aiFace _face = pMesh->mFaces[i];
                for (size_t j = 0; j < _face.mNumIndices; j++) {
                    _meshData.indices.push_back(_face.mIndices[j]);
                }
            }
            
            for (size_t i = 0; i < pMesh->mNumBones; i++) {
                aiBone* _bone = pMesh->mBones[i];
                glm::mat4 _offset = aiToGlmMat4(_bone->mOffsetMatrix);
                _meshEntry.boneData[_bone->mName.C_Str()] = std::make_pair(i , _offset);

                for (size_t j = 0; j < _bone->mNumWeights; j++) {
                    aiVertexWeight _weight = _bone->mWeights[j];
                    unsigned int _vertexID = _weight.mVertexId * 4;

                    for (size_t k = 0; k < 4; k++) {
                        if (_meshData.weights[_vertexID + k] == 0.0f) {
                            _meshData.weights[_vertexID + k] = _weight.mWeight;
                            _meshData.boneIDs[_vertexID + k] = i;
                            break;
                        }
                    }
                }

                
            }

            for (size_t i = 0; i < _meshData.weights.size(); i+=4) {
                float _totalWeight = 
                    _meshData.weights[i]    + 
                    _meshData.weights[i+1]  + 
                    _meshData.weights[i+2]  +
                    _meshData.weights[i+3];
                if (_totalWeight > 0.0f) {
                    _meshData.weights[i] /= _totalWeight;
                    _meshData.weights[i+1] /= _totalWeight;
                    _meshData.weights[i+2] /= _totalWeight;
                    _meshData.weights[i+3] /= _totalWeight;
                }
            }

            SkeletalMesh* _newMesh = new SkeletalMesh();
            _newMesh->BuildMesh(_meshData);
            mMeshes.push_back(_newMesh);
            mMeshToTexture.push_back(pMesh->mMaterialIndex);

            LoadBones(_meshEntry.skeleton, pScene->mRootNode, _meshEntry.boneData);
            mMeshEntries.push_back(_meshEntry);
        }

        bool SkeletalAnimation::LoadBones(Bone& pBone ,aiNode* pNode, BoneData& pBoneData) {
            if (pBoneData.find(pNode->mName.C_Str()) != pBoneData.end()) {
                pBone.name = pNode->mName.C_Str();
                pBone.id = pBoneData[pBone.name].first;
                pBone.offset = pBoneData[pBone.name].second;

                for (size_t i = 0; i < pNode->mNumChildren; i++) {
                    Bone _child;
                    LoadBones(_child, pNode->mChildren[i], pBoneData);
                    pBone.children.push_back(_child);
                }
                return true;
            }
            else { 
                for (size_t i = 0; i < pNode->mNumChildren; i++) {
                    if (LoadBones(pBone, pNode->mChildren[i], pBoneData)) {
                        return true;
                    }

                }
            }
            return false;
        }

        void SkeletalAnimation::LoadAnimations(const aiScene* pScene) {
            for (size_t i = 0; i < pScene->mNumAnimations; i++) {
                
                Animation _currentInternalAnimation(0.0f, 1.0f);
                aiAnimation* _currentAiAnimation = pScene->mAnimations[i];

                mAnimations.push_back(std::string(_currentAiAnimation->mName.C_Str()));
                if (i == 0) {
                    *mCurrentAnimation = mAnimations[0];
                }

                if (_currentAiAnimation->mTicksPerSecond != 0.0f) {
                    _currentInternalAnimation.ticksPerSecond = _currentAiAnimation->mTicksPerSecond;
                }
                else {
                    _currentInternalAnimation.ticksPerSecond = 1;
                }

                _currentInternalAnimation.duration = _currentAiAnimation->mDuration * _currentAiAnimation->mTicksPerSecond;
                _currentInternalAnimation.boneTransforms = {};

                BoneTransforms _transforms;

                for (size_t j = 0; j < _currentAiAnimation->mNumChannels; j++) {

                    aiNodeAnim* _channel = _currentAiAnimation->mChannels[j];

                    for (size_t k = 0; k < _channel->mNumPositionKeys; k++) {

                        _transforms.translations.push_back(aiToGlmVec3(_channel->mPositionKeys[k].mValue));
                        _transforms.translationTimestamps.push_back(_channel->mPositionKeys[k].mTime); 
                    }
                    for (size_t k = 0; k < _channel->mNumRotationKeys; k++) {
                        _transforms.rotations.push_back(aiToGlmQuat(_channel->mRotationKeys[k].mValue));
                        _transforms.rotationTimetamps.push_back(_channel->mRotationKeys[k].mTime);

                    }
                    for (size_t k = 0; k < _channel->mNumScalingKeys; k++) {
                        _transforms.scalings.push_back(aiToGlmVec3(_channel->mScalingKeys[k].mValue));
                        _transforms.scalingTimetamps.push_back(_channel->mScalingKeys[k].mTime);
                    }

                    _currentInternalAnimation.boneTransforms[_channel->mNodeName.C_Str()] = _transforms;
                }
                mAnimationMap[_currentAiAnimation->mName.C_Str()] = _currentInternalAnimation;
            }
        }

        void SkeletalAnimation::LoadMaterials(const aiScene* pScene) {
            mTextures.resize(pScene->mNumMaterials);
            for (size_t i = 0; i < pScene->mNumMaterials; i++) {
                aiMaterial* _material = pScene->mMaterials[i];
                mTextures[i] = nullptr;

                if (_material->GetTextureCount(aiTextureType_DIFFUSE)) {
                    aiString _path;
                    if (_material->GetTexture(aiTextureType_DIFFUSE, 0, &_path) == AI_SUCCESS) {
                        int _idx = std::string(_path.data).rfind("\\");
                        std::string _fileName = std::string(_path.data).substr(_idx + 1);
                        std::string _texturePath = std::string("assets/") + _fileName;
                        SDL_Log("Model Loading Texture at path: %s .", _texturePath.c_str());
                        mTextures[i] = new ImageTexture(_texturePath, mRenderer);
                        mTextures[i]->Load();

                        if (!mTextures[i]->IsLoaded()) {
                            delete mTextures[i];
                            mTextures[i] = nullptr;
                            SDL_Log("Model Error Loading Texture at path: %s .", _texturePath.c_str());
                        }

                    }
                }
            }

        }

        float SkeletalAnimation::GetAnimationDuration() {
            return mAnimationMap[*mCurrentAnimation].duration;
        }

        void SkeletalAnimation::SetAnimationTime(float pTime) {
            for (size_t i = 0; i < mMeshes.size(); i++) {
                MeshEntry& _entry = mMeshEntries[i];
                Animate(pTime, _entry.skeleton, _entry.pose, sIdentityMatrix);
            }
        }

        void SkeletalAnimation::Animate(float pDeltaTime, Bone& pSkeleton, Pose& pPose, glm::mat4& pParentTransform) {
            Animation& _currentAnimation = mAnimationMap[*mCurrentAnimation];
            
            BoneTransforms& _boneTransforms = _currentAnimation.boneTransforms[pSkeleton.name];
            pDeltaTime = fmod(pDeltaTime, _currentAnimation.duration);
            
            //Calculate translations
            GetSegment(&mCurrentSegment, _boneTransforms.translationTimestamps, pDeltaTime);

            glm::vec3 _translation = glm::mix(
                _boneTransforms.translations[mCurrentSegment.segment - 1], 
                _boneTransforms.translations[mCurrentSegment.segment], 
                mCurrentSegment.fracture);

            //Calculate rotations
            GetSegment(&mCurrentSegment, _boneTransforms.rotationTimetamps, pDeltaTime);

            glm::quat _rotation = glm::slerp(
                _boneTransforms.rotations[mCurrentSegment.segment - 1], 
                _boneTransforms.rotations[mCurrentSegment.segment], 
                mCurrentSegment.fracture);

            //Calculate scalings
            GetSegment(&mCurrentSegment, _boneTransforms.scalingTimetamps, pDeltaTime);

            glm::vec3 _scaling = glm::mix(
                _boneTransforms.scalings[mCurrentSegment.segment - 1],
                _boneTransforms.scalings[mCurrentSegment.segment],
                mCurrentSegment.fracture);

            glm::mat4 _translationMatrix = glm::translate(glm::mat4(1.0f), _translation);
            glm::mat4 _rotationMatrix = glm::toMat4(_rotation);
            glm::mat4 _scalingMatrix = glm::scale(glm::mat4(1.0f), _scaling); glm::mat4(1.0f);
            
            glm::mat4 _localTransform = _translationMatrix * _rotationMatrix * _scalingMatrix;
            glm::mat4 _globalTransform = pParentTransform * _localTransform;

            pPose[pSkeleton.id] = mGlobalInverseTransform * _globalTransform * pSkeleton.offset;

            for (Bone& _child : pSkeleton.children) {
                Animate(pDeltaTime, _child, pPose, _globalTransform);
            }
        }

        void SkeletalAnimation::GetAllAnimations(std::vector<std::string>* pAnimations) {
            pAnimations->clear();
            *pAnimations = mAnimations;
        }

        void SkeletalAnimation::SetAnimation(std::string pAnimation) {
            assert(std::find(mAnimations.begin(), mAnimations.end(), pAnimation) != mAnimations.end(), "Animation does not exist.");
            *mCurrentAnimation = pAnimation;
        }

        void SkeletalAnimation::RenderAnimation(float pDeltaTime, SkeletalAnimationShader* pSkeletalAnimationShader) {

            for (size_t i = 0; i < mMeshes.size(); i++) {
                unsigned int _materialIndex = mMeshToTexture[i];

                if (_materialIndex < mTextures.size() && mTextures[_materialIndex]) {
                    mTextures[_materialIndex]->Enable();
                }

                MeshEntry& _entry = mMeshEntries[i];
                Animate(pDeltaTime, _entry.skeleton, _entry.pose, sIdentityMatrix);
                pSkeletalAnimationShader->SetBoneTransforms(_entry.boneCount, _entry.pose);
                mMeshes[i]->Render();
            }
        }

        void SkeletalAnimation::RenderStill(SkeletalAnimationShader* pSkeletalAnimationShader) {
            for (size_t i = 0; i < mMeshes.size(); i++) {
                unsigned int _materialIndex = mMeshToTexture[i];

                if (_materialIndex < mTextures.size() && mTextures[_materialIndex]) {
                    mTextures[_materialIndex]->Enable();
                }

                MeshEntry& _entry = mMeshEntries[i];
                pSkeletalAnimationShader->SetBoneTransforms(_entry.boneCount, _entry.pose);
                mMeshes[i]->Render();
            }
        }

        void SkeletalAnimation::ClearModel() {
            for (size_t i = 0; i < mMeshes.size(); i++) {
                if (mMeshes[i]) {
                    delete mMeshes[i];
                    mMeshes[i] = nullptr;
                }
            }

            for (size_t i = 0; i < mTextures.size(); i++) {
                if (mTextures[i]) {
                    delete mTextures[i];
                    mTextures[i] = nullptr;
                }
            }
        }

        void SkeletalAnimation::GetSegment(Segment* pSegment,const std::vector<float>& pTimestamps, const float pDeltaTime) {
            unsigned int _segment = 1;
            while (pDeltaTime > pTimestamps[_segment]) {
                _segment++;
            }
            float _start = pTimestamps[_segment - 1];
            float _end = pTimestamps[_segment];
            float _fracture = (pDeltaTime - _start) / (_end - _start);
            pSegment->segment = _segment;
            pSegment->fracture = _fracture;
        }

        glm::mat4 SkeletalAnimation::aiToGlmMat4(const aiMatrix4x4& pAiMat) {
            glm::mat4 _glmMat;
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    _glmMat[x][y] = pAiMat[y][x];
                }
            }
            return _glmMat;
        }

        glm::vec3 SkeletalAnimation::aiToGlmVec3(const aiVector3D& pAiVec) {
            return glm::vec3(pAiVec.x, pAiVec.y, pAiVec.z); //Swapped Y and Z to correct Blender ups.
        }

        glm::quat SkeletalAnimation::aiToGlmQuat(const aiQuaternion& pAiQuat) {
            return glm::quat(pAiQuat.w, pAiQuat.x, pAiQuat.y, pAiQuat.z);
        }

मैं क्या गलत कर रहा हूं यह देखने के लिए मैंने अपनी कोड लाइन को कई बार लाइन से पढ़ा लेकिन मैं कुछ भी नहीं सोच सकता। मुझे नहीं लगता कि मेरा शेडर मुद्दा है, लेकिन यहां वर्टेक्स शेडर है:

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 uv;
layout (location = 2) in vec3 normal;
layout (location = 3) in ivec4 boneIds; 
layout (location = 4) in vec4 boneWeights; 

out vec2 textureUV;
out vec3 lightNormal;
out vec4 worldPosition;

uniform mat4 model;
uniform mat4 projectionView;
uniform mat4 boneTransforms[50];

void main()
{
    mat4 boneTransform  =  mat4(0.0f);
    for(int i = 0; i < 4; i++){
        boneTransform  += boneTransforms[boneIds[i]] * boneWeights[i];
    }
    worldPosition = boneTransform * vec4(position, 1.0f);
    worldPosition = model * worldPosition;
    gl_Position = projectionView * worldPosition;
    textureUV = uv;
    lightNormal = mat3(transpose(inverse(model * boneTransform))) * normal;
}

परिणाम: Skewed image

0
user3193075 11 मार्च 2021, 06:12

1 उत्तर

सबसे बढ़िया उत्तर

मैं यह समझ गया। BoneTransforms को लूप के भीतर ले जाने की आवश्यकता है। एक ही उदाहरण प्रत्येक लूप चक्र को ओवर-राइट किया जा रहा था।

1
user3193075 12 मार्च 2021, 01:36