diff --git a/include/spike/gltf.hpp b/include/spike/gltf.hpp index 59c6234..8929858 100644 --- a/include/spike/gltf.hpp +++ b/include/spike/gltf.hpp @@ -96,7 +96,6 @@ struct SavedIndices { struct GLTFModel : GLTF { std::optional transform; - bool quantizeMesh = false; SavedIndices GLTF_EXTERN SaveIndices(const void *data, size_t numIndices, size_t indexSize = 2); @@ -143,6 +142,17 @@ struct GLTFModel : GLTF { return Stream(indexStream); } + GLTFStream &GetVt16() { + if (vt16Stream < 0) { + auto &str = NewStream("vtStride16", 16); + str.target = gltf::BufferView::TargetType::ArrayBuffer; + vt16Stream = str.slot; + return str; + } + + return Stream(vt16Stream); + } + GLTFStream &GetVt12() { if (vt12Stream < 0) { auto &str = NewStream("vtStride12", 12); @@ -176,9 +186,30 @@ struct GLTFModel : GLTF { return Stream(vt4Stream); } + void FinishAndSave(BinWritterRef wr, const std::string &docPath) { + if (useMeshQuantize) { + if (!quantizeFake) { + extensionsRequired.emplace_back("KHR_mesh_quantization"); + } + extensionsUsed.emplace_back("KHR_mesh_quantization"); + } + + GLTF::FinishAndSave(wr, docPath); + } + + void QuantizeMesh(bool fake) { + quantizeMesh = true; + quantizeFake = fake; + } + + bool quantizeMesh = false; + bool useMeshQuantize = false; + private: + bool quantizeFake = false; int32 ibmStream = -1; int32 indexStream = -1; + int32 vt16Stream = -1; int32 vt12Stream = -1; int32 vt8Stream = -1; int32 vt4Stream = -1; diff --git a/src/gltf/gltf.cpp b/src/gltf/gltf.cpp index f29c655..c3d781c 100644 --- a/src/gltf/gltf.cpp +++ b/src/gltf/gltf.cpp @@ -378,6 +378,7 @@ SavedIndices GLTFModel::SaveIndices(const void *data, size_t numIndices, size_t WritePositions16s(GLTFModel &main, uni::FormatCodec::fvec &basePosition) { + main.useMeshQuantize = true; auto &stream = main.GetVt8(); auto [acc, index] = main.NewAccessor(stream, 4); acc.count = basePosition.size(); @@ -404,6 +405,7 @@ size_t WritePositions16s(GLTFModel &main, size_t WritePositions16u(GLTFModel &main, uni::FormatCodec::fvec &basePosition) { + main.useMeshQuantize = true; auto &stream = main.GetVt8(); auto [acc, index] = main.NewAccessor(stream, 4); acc.count = basePosition.size(); @@ -467,10 +469,10 @@ size_t WriteNormals32(GLTFModel &main, uni::FormatCodec::fvec &normals) { } size_t WriteTangents32(GLTFModel &main, uni::FormatCodec::fvec &tangents) { - auto &stream = main.GetVt12(); + auto &stream = main.GetVt16(); auto [acc, index] = main.NewAccessor(stream, 4); acc.count = tangents.size(); - acc.type = gltf::Accessor::Type::Vec3; + acc.type = gltf::Accessor::Type::Vec4; acc.componentType = gltf::Accessor::ComponentType::Float; for (auto &v : tangents) { @@ -484,6 +486,7 @@ size_t WriteTangents32(GLTFModel &main, uni::FormatCodec::fvec &tangents) { } size_t WriteNormals16(GLTFModel &main, uni::FormatCodec::fvec &normals) { + main.useMeshQuantize = true; auto &stream = main.GetVt8(); auto [acc, index] = main.NewAccessor(stream, 4); acc.count = normals.size(); @@ -504,6 +507,7 @@ size_t WriteNormals16(GLTFModel &main, uni::FormatCodec::fvec &normals) { } size_t WriteNormals8(GLTFModel &main, uni::FormatCodec::fvec &normals) { + main.useMeshQuantize = true; auto &stream = main.GetVt4(); auto [acc, index] = main.NewAccessor(stream, 4); acc.count = normals.size(); @@ -524,6 +528,7 @@ size_t WriteNormals8(GLTFModel &main, uni::FormatCodec::fvec &normals) { } size_t WriteTexcoord16s(GLTFModel &main, uni::FormatCodec::fvec &coords) { + main.useMeshQuantize = true; auto &stream = main.GetVt4(); auto [acc, index] = main.NewAccessor(stream, 4); acc.count = coords.size(); @@ -657,12 +662,17 @@ size_t SaveTangents(GLTFModel &main, const char *data, size_t numVertices, return WriteTangents32(main, tangents); } - switch (attribute.type) { - case uni::DataType::R8G8B8A8: - return WriteNormals8(main, tangents); - default: - return WriteNormals16(main, tangents); - } + size_t accIndex = [&] { + switch (attribute.type) { + case uni::DataType::R8G8B8A8: + return WriteNormals8(main, tangents); + default: + return WriteNormals16(main, tangents); + } + }(); + + main.accessors.at(accIndex).type = gltf::Accessor::Type::Vec4; + return accIndex; } size_t SaveTexcoords(GLTFModel &main, const char *data, size_t numVertices, @@ -670,19 +680,19 @@ size_t SaveTexcoords(GLTFModel &main, const char *data, size_t numVertices, uni::FormatCodec::fvec coords = SampleAttribute(data, numVertices, attribute, stride); - if (!main.quantizeMesh || - (attribute.customCodec && !attribute.customCodec->IsNormalized())) { + if (attribute.customCodec && !attribute.customCodec->IsNormalized()) { return WriteTexcoord32(main, coords); } - switch (attribute.format) { - case uni::FormatType::NORM: - return WriteTexcoord16s(main, coords); - case uni::FormatType::UNORM: + if (attribute.format == uni::FormatType::UNORM) { return WriteTexcoord16u(main, coords); - default: - return WriteTexcoord32(main, coords); } + + if (main.quantizeMesh && attribute.format == uni::FormatType::NORM) { + return WriteTexcoord16s(main, coords); + } + + return WriteTexcoord32(main, coords); } size_t SaveColor(GLTFModel &main, const char *data, size_t numVertices, @@ -938,6 +948,33 @@ gltf::Attributes GLTFModel::SaveVertices(const void *data, size_t numVertices, } } + if (weightElement > 1) { + for (size_t idx = 0; auto &bw : weightsBuffer) { + BWBuffer &bones = bonesBuffer.at(idx++); + BWBuffer newBones{}; + BWBuffer newWeights{}; + uint8 curBone = 0; + + for (int16 ci = -1; uint8 c : bones.data) { + if (c == 0xff || bw.data[++ci] == 0) { + continue; + } + + for (uint8 b = 0; b < 8; b++) { + if (bones.data[b] == c) { + bones.data[b] = -1; + newWeights.data[curBone] += bw.data[b]; + } + } + + newBones.data[curBone++] = c; + } + + bw = newWeights; + bones = newBones; + } + } + if (boneElement > 4) { auto &stream = GetVt8(); auto [acc0, index0] = NewAccessor(stream, 4); @@ -981,7 +1018,7 @@ gltf::Attributes GLTFModel::SaveVertices(const void *data, size_t numVertices, acc1.componentType = gltf::Accessor::ComponentType::UnsignedByte; acc1.type = gltf::Accessor::Type::Vec4; - if (weightElement == 0) { + if (weightsBuffer.empty()) { for (size_t v = 0; v < numVertices; v++) { stream.wr.Write(0xff); }