diff --git a/src/Raw2Gltf.cpp b/src/Raw2Gltf.cpp index 8f12426..1f9a382 100644 --- a/src/Raw2Gltf.cpp +++ b/src/Raw2Gltf.cpp @@ -39,7 +39,7 @@ #include "glTF/SkinData.h" #include "glTF/TextureData.h" -typedef unsigned short TriangleIndex; +typedef uint32_t TriangleIndex; extern bool verboseOutput; @@ -290,7 +290,11 @@ ModelData *Raw2Gltf( } std::vector materialModels; - raw.CreateMaterialModels(materialModels, (1 << (sizeof(TriangleIndex) * 8)), options.keepAttribs, true); + raw.CreateMaterialModels( + materialModels, + options.useLongIndices == UseLongIndicesOptions::NEVER, + options.keepAttribs, + true); if (verboseOutput) { fmt::printf("%7d vertices\n", raw.GetVertexCount()); @@ -646,20 +650,6 @@ ModelData *Raw2Gltf( combine, tag, outputHasAlpha); }; - // acquire derived texture of two RawTextureUsage as *TextData, or nullptr if neither exists - auto merge3Tex = [&]( - const std::string tag, - RawTextureUsage u1, - RawTextureUsage u2, - RawTextureUsage u3, - const pixel_merger &combine, - bool outputHasAlpha - ) -> std::shared_ptr { - return getDerivedTexture( - { material.textures[u1], material.textures[u2], material.textures[u3] }, - combine, tag, outputHasAlpha); - }; - std::shared_ptr pbrMetRough; if (options.usePBRMetRough) { // albedo is a basic texture, no merging needed @@ -744,17 +734,14 @@ ModelData *Raw2Gltf( materialsByName[materialHash(material)] = mData; } - for (size_t surfaceIndex = 0; surfaceIndex < materialModels.size(); surfaceIndex++) { - const RawModel &surfaceModel = materialModels[surfaceIndex]; - + for (const auto &surfaceModel : materialModels) { assert(surfaceModel.GetSurfaceCount() == 1); - const RawSurface &rawSurface = surfaceModel.GetSurface(0); - const int surfaceId = rawSurface.id; + const RawSurface &rawSurface = surfaceModel.GetSurface(0); + const long surfaceId = rawSurface.id; const RawMaterial &rawMaterial = surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex); const MaterialData &mData = require(materialsByName, materialHash(rawMaterial)); - MeshData *mesh = nullptr; auto meshIter = meshBySurfaceId.find(surfaceId); if (meshIter != meshBySurfaceId.end()) { @@ -770,6 +757,11 @@ ModelData *Raw2Gltf( mesh = meshPtr.get(); } + bool useLongIndices = + (options.useLongIndices == UseLongIndicesOptions::ALWAYS) + || (options.useLongIndices == UseLongIndicesOptions::AUTO + && surfaceModel.GetVertexCount() > 65535); + std::shared_ptr primitive; if (options.useDraco) { int triangleCount = surfaceModel.GetTriangleCount(); @@ -786,13 +778,13 @@ ModelData *Raw2Gltf( dracoMesh->SetFace(draco::FaceIndex(ii), face); } - AccessorData &indexes = *gltf->accessors.hold(new AccessorData(GLT_USHORT)); + AccessorData &indexes = *gltf->accessors.hold(new AccessorData(useLongIndices ? GLT_UINT : GLT_USHORT)); indexes.count = 3 * triangleCount; primitive.reset(new PrimitiveData(indexes, mData, dracoMesh)); } else { const AccessorData &indexes = *gltf->AddAccessorWithView( *gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ELEMENT_ARRAY_BUFFER), - GLT_USHORT, getIndexArray(surfaceModel)); + useLongIndices ? GLT_UINT : GLT_USHORT, getIndexArray(surfaceModel)); primitive.reset(new PrimitiveData(indexes, mData)); }; diff --git a/src/Raw2Gltf.h b/src/Raw2Gltf.h index 9fdd75d..9127061 100644 --- a/src/Raw2Gltf.h +++ b/src/Raw2Gltf.h @@ -51,6 +51,7 @@ struct ComponentType { }; const ComponentType CT_USHORT = {ComponentType::GL_UNSIGNED_SHORT, 2}; +const ComponentType CT_UINT = {ComponentType::GL_UNSIGNED_INT, 4}; const ComponentType CT_FLOAT = {ComponentType::GL_FLOAT, 4}; // Map our low-level data types for glTF output @@ -64,7 +65,7 @@ struct GLType { unsigned int byteStride() const { return componentType.size * count; } void write(uint8_t *buf, const float scalar) const { *((float *) buf) = scalar; } - void write(uint8_t *buf, const uint16_t scalar) const { *((uint16_t *) buf) = scalar; } + void write(uint8_t *buf, const uint32_t scalar) const { *((uint32_t *) buf) = scalar; } template void write(uint8_t *buf, const mathfu::Vector &vector) const { @@ -101,6 +102,7 @@ struct GLType { const GLType GLT_FLOAT = {CT_FLOAT, 1, "SCALAR"}; const GLType GLT_USHORT = {CT_USHORT, 1, "SCALAR"}; +const GLType GLT_UINT = {CT_UINT, 1, "SCALAR"}; const GLType GLT_VEC2F = {CT_FLOAT, 2, "VEC2"}; const GLType GLT_VEC3F = {CT_FLOAT, 3, "VEC3"}; const GLType GLT_VEC4F = {CT_FLOAT, 4, "VEC4"}; diff --git a/src/RawModel.cpp b/src/RawModel.cpp index 9443608..e8b708a 100644 --- a/src/RawModel.cpp +++ b/src/RawModel.cpp @@ -327,15 +327,15 @@ void RawModel::Condense() void RawModel::TransformGeometry(ComputeNormalsOption normals) { switch(normals) { - case NEVER: + case ComputeNormalsOption::NEVER: break; - case MISSING: + case ComputeNormalsOption::MISSING: if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) { break; } // otherwise fall through - case BROKEN: - case ALWAYS: + case ComputeNormalsOption::BROKEN: + case ComputeNormalsOption::ALWAYS: size_t computedNormalsCount = this->CalculateNormals(normals == ComputeNormalsOption::BROKEN); vertexAttributes |= RAW_VERTEX_ATTRIBUTE_NORMAL; @@ -395,7 +395,7 @@ struct TriangleModelSortNeg }; void RawModel::CreateMaterialModels( - std::vector &materialModels, const int maxModelVertices, const int keepAttribs, const bool forceDiscrete) const + std::vector &materialModels, bool shortIndices, const int keepAttribs, const bool forceDiscrete) const { // Sort all triangles based on material first, then surface, then first vertex index. std::vector sortedTriangles; @@ -467,7 +467,7 @@ void RawModel::CreateMaterialModels( } if (i == 0 || - model->GetVertexCount() > maxModelVertices - 3 || + (shortIndices && model->GetVertexCount() >= 0xFFFE) || sortedTriangles[i].materialIndex != sortedTriangles[i - 1].materialIndex || (sortedTriangles[i].surfaceIndex != sortedTriangles[i - 1].surfaceIndex && (forceDiscrete || surfaces[sortedTriangles[i].surfaceIndex].discrete || diff --git a/src/RawModel.h b/src/RawModel.h index d0361ad..ce3ab67 100644 --- a/src/RawModel.h +++ b/src/RawModel.h @@ -17,13 +17,19 @@ /** * The variuos situations in which the user may wish for us to (re-)compute normals for our vertices. */ -enum ComputeNormalsOption { +enum class ComputeNormalsOption { NEVER, // do not ever compute any normals (results in broken glTF for some sources) BROKEN, // replace zero-length normals in any mesh that has a normal layer MISSING, // if a mesh lacks normals, compute them all ALWAYS // compute a new normal for every vertex, obliterating whatever may have been there before }; +enum class UseLongIndicesOptions { + NEVER, // only ever use 16-bit indices + AUTO, // use shorts or longs depending on vertex count + ALWAYS, // only ever use 32-bit indices +}; + /** * User-supplied options that dictate the nature of the glTF being generated. */ @@ -52,6 +58,8 @@ struct GltfOptions bool useBlendShapeTangents { false }; /** When to compute vertex normals from geometry. */ ComputeNormalsOption computeNormals = ComputeNormalsOption::BROKEN; + /** When to use 32-bit indices. */ + UseLongIndicesOptions useLongIndices = UseLongIndicesOptions::AUTO; }; enum RawVertexAttribute @@ -470,7 +478,7 @@ public: // Multiple surfaces with the same material will turn into a single model. // However, surfaces that are marked as 'discrete' will turn into separate models. void CreateMaterialModels( - std::vector &materialModels, const int maxModelVertices, const int keepAttribs, const bool forceDiscrete) const; + std::vector &materialModels, bool shortIndices, const int keepAttribs, const bool forceDiscrete) const; private: Vec3f getFaceNormal(int verts[3]) const; diff --git a/src/main.cpp b/src/main.cpp index 0f34e92..1f9ee6d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,6 +75,9 @@ int main(int argc, char *argv[]) ( "blend-shape-tangents", "Include blend shape tangents, if reported present by the FBX SDK.", cxxopts::value(gltfOptions.useBlendShapeTangents)) + ( + "long-indices", "Whether to use 32-bit indices (never|auto|always).", + cxxopts::value>()) ( "compute-normals", "When to compute normals for vertices (never|broken|missing|always).", cxxopts::value>()) @@ -137,16 +140,30 @@ Copyright (c) 2016-2017 Oculus VR, LLC. fmt::printf("Suppressing --flip-v transformation of texture coordinates.\n"); } + for (const std::string &choice : options["long-indices"].as>()) { + if (choice == "never") { + gltfOptions.useLongIndices = UseLongIndicesOptions::NEVER; + } else if (choice == "auto") { + gltfOptions.useLongIndices = UseLongIndicesOptions::AUTO; + } else if (choice == "always") { + gltfOptions.useLongIndices = UseLongIndicesOptions::ALWAYS; + } else { + fmt::printf("Unknown --long-indices: %s\n", choice); + fmt::printf(options.help()); + return 1; + } + } + if (options.count("compute-normals") > 0) { for (const std::string &choice : options["compute-normals"].as>()) { if (choice == "never") { - gltfOptions.computeNormals = NEVER; + gltfOptions.computeNormals = ComputeNormalsOption::NEVER; } else if (choice == "broken") { - gltfOptions.computeNormals = BROKEN; + gltfOptions.computeNormals = ComputeNormalsOption::BROKEN; } else if (choice == "missing") { - gltfOptions.computeNormals = MISSING; + gltfOptions.computeNormals = ComputeNormalsOption::MISSING; } else if (choice == "always") { - gltfOptions.computeNormals = ALWAYS; + gltfOptions.computeNormals = ComputeNormalsOption::ALWAYS; } else { fmt::printf("Unknown --compute-normals: %s\n", choice); fmt::printf(options.help());