Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

glTFでのモデルの描画

glTFでモデルの描画

joint情報を読み込み、静止モデルの描画をしてみた。

モデルの権利表記

配布元リポジトリ
https://github.com/TheThinMatrix/OpenGL-Animation

Unlicense license
https://unlicense.org/

glTFフォーマットの読み込み方

tiny glTFを用いてglTFのモデルを読み込んでいる。ライセンスはMITライセンス。
https://github.com/syoyo/tinygltf

使い方は以下のgit hubにあるコードを参考にした。ライセンスはApache 2.0。
https://github.com/techlabxe/vk_raytracing_book_1/blob/master/Common/include/util/VkrModel.h
https://github.com/techlabxe/vk_raytracing_book_1/tree/master/Common/src/util

glTFの構造については仕様書にまとめられている。
glTF™ 2.0 Specification

アニメーションの読み込みと描画に成功すれば、情報を改めてまとめ直したいと思っているが、とりあえずコードは以下のようなもの。

    using namespace tinygltf;
    std::vector<glm::uvec4> tmpJoint;
    std::vector<glm::vec4> tmpWeight;
    const uint8_t* jointSrc;
    const glm::vec4* weightSrc;
    for(auto& primitive : model.meshes[0].primitives){
        //each primitive
        Geometry geo = {};
        for(auto& attr : primitive.attributes) {
            std::string attName = attr.first;
            //positions
            if (std::regex_search(attName, std::regex("position", std::regex::icase))) {
                const auto &posAccr = model.accessors[attr.second];
                const auto &posBufView = model.bufferViews[posAccr.bufferView];
                size_t offsetByte = posAccr.byteOffset + posBufView.byteOffset;
                const auto *src = reinterpret_cast<const glm::vec3 *>(&(model.buffers[posBufView.buffer].data[offsetByte]));
                size_t vertexSize = posAccr.count;
                for (uint32_t i = 0; i < vertexSize; i++) {
                    geo.positions.emplace_back(src[i]);
                }
                //indices
                const auto &indexAccr = model.accessors[primitive.indices];
                const auto &indexBufView = model.bufferViews[indexAccr.bufferView];
                size_t indexOffsetByte = indexAccr.byteOffset + indexBufView.byteOffset;
                const auto *indexSrc = reinterpret_cast<const uint16_t *>(&(model.buffers[indexBufView.buffer].data[indexOffsetByte]));
                for (uint32_t i = 0; i < indexAccr.count; i++)
                    geo.indices.emplace_back((uint32_t) indexSrc[i]);
            }
            //texture coord
            if (std::regex_search(attName, std::regex("texcoord", std::regex::icase))) {
                const auto &tcAccr = model.accessors[attr.second];
                const auto &tcBufView = model.bufferViews[tcAccr.bufferView];
                size_t offsetByte = tcAccr.byteOffset + tcBufView.byteOffset;
                const auto *tcSrc = reinterpret_cast<const glm::vec2 *>(&model.buffers[tcBufView.buffer].data[offsetByte]);
                for (uint32_t i = 0; i < tcAccr.count; i++)
                    geo.texCoords.emplace_back(tcSrc[i]);
            }
            //joint information
            if(std::regex_search(attName, std::regex("joint", std::regex::icase))){
                const auto& jointAccr = model.accessors[attr.second];
                const auto& jointBufView = model.bufferViews[jointAccr.bufferView];
                size_t offsetByte = jointAccr.byteOffset + jointBufView.byteOffset;
                //in case of acc.componentType = TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE 
                jointSrc = reinterpret_cast<const uint8_t*>(&model.buffers[jointBufView.buffer].data[offsetByte]);
                for(uint32_t i = 0; i < jointAccr.count; i++){
                    uint32_t index = i * 4;
                    glm::uvec4 u(jointSrc[index], jointSrc[index + 1], jointSrc[index + 2], jointSrc[index + 3]);
                    tmpJoint.emplace_back(u);
                }
            }
            //weight information
            if(std::regex_search(attName, std::regex("weight", std::regex::icase))){
                const auto& weightAccr = model.accessors[attr.second];
                const auto& weightBufView = model.bufferViews[weightAccr.bufferView];
                size_t offsetByte = weightAccr.byteOffset + weightBufView.byteOffset;
                weightSrc = reinterpret_cast<const glm::vec4*>(&model.buffers[weightBufView.buffer].data[offsetByte]);
                for(uint32_t i = 0; i < weightAccr.count; i++)
                    tmpWeight.emplace_back(weightSrc[i]);
            }
        }
        mGeometries.emplace_back(geo);
    }

今後の作業

joint情報を読み込んで、compute shaderで頂点を計算するところまでできたので、次はanimationの情報を読み込んでモデルを動かせるようにしたい。
以前にcolladaで同じことをしたが、かなり難しく時間がかかったので覚悟はしているが、手元のスマホ(android)でモデルを動かせるようになりたい。