Search code examples
c++sdkc++17gltf

Byte offset greater than Byte Length in BufferView


I'm trying to read data from scene.bin files using Microsoft::glTF SDK. TinyGLTF is not an option. When I try to read MeshPrimitive attribute called TEXCOORD_0 i get a situation where BufferView byteOffset is greater than byteLength. Therefore, I don't know how to properly read given data and my program crashes.

I tried reading data using IStreamReader which is a part of SDK, and is a must when reading bin files using this SDK. I calculate data offset by adding accessor.byteOffset + bufferView.byteOffset which is > byteLength.

struct BuffersAccessors {
    Microsoft::glTF::Accessor accessor;
    Microsoft::glTF::BufferView view;
    Microsoft::glTF::Buffer buffer;

    void operator=(BuffersAccessors accessors);
};

template<typename T> struct BufferInfo {
BuffersAccessors buffersAccessors;
    std::vector<T> bufferData;

    BufferInfo<T>();

    BufferInfo<T>(BuffersAccessors buffersAccessors, std::vector<T> bufferData);

    const void operator=(const BufferInfo<T> &info) {
        buffersAccessors = info.buffersAccessors;
        bufferData = info.bufferData;
    };
};

    template<typename T>
std::vector<T> readBufferData(Microsoft::glTF::Document document, BufferInfo<T> bufferInfo, std::filesystem::path path) {
    std::vector<T> stream;

    if (bufferInfo.buffersAccessors.buffer.uri.length() > 0 || bufferInfo.buffersAccessors.buffer.byteLength > 0) {
        Microsoft::glTF::Buffer buffer = bufferInfo.buffersAccessors.buffer;

        path += bufferInfo.buffersAccessors.buffer.uri;
        path = std::filesystem::absolute(path);
        buffer.uri = path.string();

        std::shared_ptr<StreamReader> streamReader = std::make_shared<StreamReader>(path);
        Microsoft::glTF::GLTFResourceReader reader(streamReader);

        stream = reader.ReadBinaryData<T>(buffer, bufferInfo.buffersAccessors.view);
    }

    return stream;
}

    template<typename T>
BufferInfo<T> getFullBufferData(Microsoft::glTF::Document document, std::string accessorKey, std::filesystem::path path) {
    BufferInfo<T> bufferInfo{};
    BuffersAccessors mainPart = getBufferAccessorFromDocument(document, accessorKey);

    bufferInfo.buffersAccessors = mainPart;
    std::vector<T> bufferData = vkglTF::readBufferData<T>(document, bufferInfo, path);
    const size_t bufferDataOffset = mainPart.accessor.byteOffset + mainPart.view.byteOffset;    //How to properly calculate offset?

    bufferData.erase(bufferData.begin(), bufferData.begin() + bufferDataOffset);

    bufferInfo.bufferData = bufferData;

    return bufferInfo;
}

I expect data in formats like uint8 and uint16 but my program crashes when trying to do bufferData.erase(..).

Edit: This happens while reading WEIGHTS_0 too.


Solution

  • I think the most likely error with your code is the mixing of byte offsets and vector element indices. Have you tried dividing bufferDataOffset by sizeof(T)?

    Second, if you only want to read an accessor's data then try using the ReadBinaryData overload that accepts an Accessor parameter instead. That way the glTF SDK will handle all of the offset calculations for you.

    There is no documentation but the deserialize sample demonstrates the basic code structure recommended when using the glTF SDK.