From 0c8128b7e401702ab8dbb0c4a6969d3b1b412272 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 24 Nov 2016 09:43:56 +0100 Subject: [PATCH] Mesh/MeshParams: Replace flipUVs by texCoordOffset and texCoordScale --- SDK/include/NDK/LuaAPI.inl | 3 +- include/Nazara/Utility/Mesh.hpp | 26 ++++------- plugins/Assimp/Plugin.cpp | 25 +++++------ src/Nazara/Utility/Formats/MD2Loader.cpp | 46 ++++++++++---------- src/Nazara/Utility/Formats/MD5MeshLoader.cpp | 10 ++--- src/Nazara/Utility/Formats/OBJLoader.cpp | 4 +- 6 files changed, 52 insertions(+), 62 deletions(-) diff --git a/SDK/include/NDK/LuaAPI.inl b/SDK/include/NDK/LuaAPI.inl index f2ddf251c..d830ae8a2 100644 --- a/SDK/include/NDK/LuaAPI.inl +++ b/SDK/include/NDK/LuaAPI.inl @@ -156,9 +156,10 @@ namespace Nz params->animated = instance.CheckField("Animated", params->animated); params->center = instance.CheckField("Center", params->center); - params->flipUVs = instance.CheckField("FlipUVs", params->flipUVs); params->matrix = instance.CheckField("Matrix", params->matrix); params->optimizeIndexBuffers = instance.CheckField("OptimizeIndexBuffers", params->optimizeIndexBuffers); + params->texCoordOffset = instance.CheckField("TexCoordOffset", params->texCoordOffset); + params->texCoordScale = instance.CheckField("TexCoordScale", params->texCoordScale); return 1; } diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index 60ccb98b1..38067ce81 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -28,25 +28,15 @@ namespace Nz { struct NAZARA_UTILITY_API MeshParams : ResourceParameters { - MeshParams(); // Vérifie que le storage par défaut est supporté (software autrement) + MeshParams(); - // La transformation appliquée à tous les sommets du mesh - Matrix4f matrix = Matrix4f::Identity(); - - // Si ceci sera le stockage utilisé par les buffers - UInt32 storage = DataStorage_Hardware; - - // Charger une version animée du mesh si possible ? - bool animated = true; - - // Faut-il centrer le mesh autour de l'origine ? - bool center = false; - - // Faut-il retourner les UV ? - bool flipUVs = false; - - // Faut-il optimiser les index buffers ? (Rendu plus rapide, mais le chargement dure plus longtemps) - bool optimizeIndexBuffers = true; + Matrix4f matrix = Matrix4f::Identity(); ///< A matrix which will transform every vertex position + UInt32 storage = DataStorage_Hardware; ///< The place where the buffers will be allocated + Vector2f texCoordOffset = {0.f, 0.f}; ///< Offset to apply on the texture coordinates (not scaled) + Vector2f texCoordScale = {1.f, 1.f}; ///< Scale to apply on the texture coordinates + bool animated = true; ///< If true, will load an animated version of the model if possible + bool center = false; ///< If true, will center the mesh vertices around the origin + bool optimizeIndexBuffers = true; ///< Optimize the index buffers after loading, improve cache locality (and thus rendering speed) but increase loading time. bool IsValid() const; }; diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index a668ec634..746549568 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -97,17 +97,14 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) unsigned int postProcess = aiProcess_CalcTangentSpace | aiProcess_JoinIdenticalVertices | aiProcess_MakeLeftHanded | aiProcess_Triangulate | aiProcess_RemoveComponent | aiProcess_GenSmoothNormals - | aiProcess_SplitLargeMeshes | aiProcess_LimitBoneWeights - | aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials - | aiProcess_FixInfacingNormals | aiProcess_SortByPType - | aiProcess_FindInvalidData | aiProcess_GenUVCoords - | aiProcess_TransformUVCoords | aiProcess_OptimizeMeshes - | aiProcess_OptimizeGraph | aiProcess_FlipWindingOrder + | aiProcess_SplitLargeMeshes | aiProcess_LimitBoneWeights + | aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials + | aiProcess_FixInfacingNormals | aiProcess_SortByPType + | aiProcess_FindInvalidData | aiProcess_GenUVCoords + | aiProcess_TransformUVCoords | aiProcess_OptimizeMeshes + | aiProcess_OptimizeGraph | aiProcess_FlipWindingOrder | aiProcess_Debone; - if (parameters.flipUVs) - postProcess |= aiProcess_FlipUVs; - if (parameters.optimizeIndexBuffers) postProcess |= aiProcess_ImproveCacheLocality; @@ -157,7 +154,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) if (animatedMesh) { mesh->CreateSkeletal(joints.size()); - + Skeleton* skeleton = mesh->GetSkeleton(); // First, assign names @@ -172,9 +169,9 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) else { mesh->CreateStatic(); - + // aiMaterial index in scene => Material index and data in Mesh - std::unordered_map> materials; + std::unordered_map> materials; for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { @@ -219,7 +216,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) vertex->position = parameters.matrix * Vector3f(position.x, position.y, position.z); vertex->normal.Set(normal.x, normal.y, normal.z); vertex->tangent.Set(tangent.x, tangent.y, tangent.z); - vertex->uv.Set(uv.x, uv.y); + vertex->uv.Set(parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale); vertex++; } @@ -311,7 +308,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) mesh->AddSubMesh(subMesh); } - mesh->SetMaterialCount(std::max(materials.size(), 1)); + mesh->SetMaterialCount(std::max(materials.size(), 1)); for (const auto& pair : materials) mesh->SetMaterialData(pair.second.first, pair.second.second); } diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index dde203482..04628ba90 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -81,15 +81,14 @@ namespace Nz return false; } - /// Création du mesh - // Le moteur ne supporte plus les animations image-clé, nous ne pouvons charger qu'en statique - if (!mesh->CreateStatic()) // Ne devrait jamais échouer + // Since the engine no longer supports keyframe animations, let's make a static mesh + if (!mesh->CreateStatic()) { NazaraInternalError("Failed to create mesh"); return false; } - /// Chargement des skins + // Extract skins (texture name) if (header.num_skins > 0) { mesh->SetMaterialCount(header.num_skins); @@ -109,16 +108,15 @@ namespace Nz } } - /// Chargement des submesh - // Actuellement le loader ne charge qu'un submesh IndexBufferRef indexBuffer = IndexBuffer::New(false, header.num_tris*3, parameters.storage, BufferUsage_Static); - /// Lecture des triangles + // Extract triangles data std::vector triangles(header.num_tris); stream.SetCursorPos(header.offset_tris); stream.Read(&triangles[0], header.num_tris*sizeof(MD2_Triangle)); + // And convert them into an index buffer BufferMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); UInt16* index = static_cast(indexMapper.GetPointer()); @@ -135,7 +133,7 @@ namespace Nz SwapBytes(&triangles[i].texCoords[2], sizeof(UInt16)); #endif - // On respécifie le triangle dans l'ordre attendu + // Reverse winding order *index++ = triangles[i].vertices[0]; *index++ = triangles[i].vertices[2]; *index++ = triangles[i].vertices[1]; @@ -143,10 +141,11 @@ namespace Nz indexMapper.Unmap(); + // Optimize if requested (improves cache locality) if (parameters.optimizeIndexBuffers) indexBuffer->Optimize(); - /// Lecture des coordonnées de texture + // Extracting texture coordinates std::vector texCoords(header.num_st); stream.SetCursorPos(header.offset_st); @@ -168,15 +167,15 @@ namespace Nz return false; } - /// Chargement des vertices + // Extracting vertices stream.SetCursorPos(header.offset_frames); - std::unique_ptr vertices(new MD2_Vertex[header.num_vertices]); + std::vector vertices(header.num_vertices); Vector3f scale, translate; stream.Read(scale, sizeof(Vector3f)); stream.Read(translate, sizeof(Vector3f)); - stream.Read(nullptr, 16*sizeof(char)); // Nom de la frame, inutile ici - stream.Read(vertices.get(), header.num_vertices*sizeof(MD2_Vertex)); + stream.Read(nullptr, 16*sizeof(char)); //< Frame name, unused + stream.Read(vertices.data(), header.num_vertices*sizeof(MD2_Vertex)); #ifdef NAZARA_BIG_ENDIAN SwapBytes(&scale.x, sizeof(float)); @@ -196,23 +195,26 @@ namespace Nz BufferMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); MeshVertex* vertex = static_cast(vertexMapper.GetPointer()); - /// Chargement des coordonnées de texture - const unsigned int indexFix[3] = {0, 2, 1}; // Pour respécifier les indices dans le bon ordre + // Loading texture coordinates + const unsigned int indexFix[3] = {0, 2, 1}; + Vector2f invSkinSize(1.f / header.skinwidth, 1.f / header.skinheight); for (unsigned int i = 0; i < header.num_tris; ++i) { for (unsigned int j = 0; j < 3; ++j) { - const unsigned int fixedIndex = indexFix[j]; - const MD2_TexCoord& texC = texCoords[triangles[i].texCoords[fixedIndex]]; - float u = static_cast(texC.u) / header.skinwidth; - float v = static_cast(texC.v) / header.skinheight; + const unsigned int fixedIndex = indexFix[j]; //< Reverse winding order - vertex[triangles[i].vertices[fixedIndex]].uv.Set(u, (parameters.flipUVs) ? 1.f - v : v); + const MD2_TexCoord& texC = texCoords[triangles[i].texCoords[fixedIndex]]; + Vector2f uv(texC.u, texC.v); + uv *= invSkinSize; + + vertex[triangles[i].vertices[fixedIndex]].uv.Set(parameters.texCoordOffset + uv * parameters.texCoordScale); } } - /// Chargement des positions - // Pour que le modèle soit correctement aligné, on génère un quaternion que nous appliquerons à chacune des vertices + // Loading vertex position + + // Align the model to our coordinates system Quaternionf rotationQuat = EulerAnglesf(-90.f, 90.f, 0.f); Nz::Matrix4f matrix = Matrix4f::Transform(translate, rotationQuat, scale); matrix *= parameters.matrix; diff --git a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp index 59988405a..bccf17568 100644 --- a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp @@ -184,7 +184,7 @@ namespace Nz } vertices->position = finalPos; - vertices->uv.Set(vertex.uv.x, (parameters.flipUVs) ? 1.f - vertex.uv.y : vertex.uv.y); // Inversion des UV si demandé + vertices->uv.Set(parameters.texCoordOffset + vertex.uv * parameters.texCoordScale); vertices++; } @@ -254,7 +254,7 @@ namespace Nz VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage); BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); - MeshVertex* vertex = static_cast(vertexMapper.GetPointer()); + MeshVertex* vertices = static_cast(vertexMapper.GetPointer()); for (const MD5MeshParser::Vertex& md5Vertex : md5Mesh.vertices) { // Skinning MD5 (Formule d'Id Tech) @@ -268,9 +268,9 @@ namespace Nz } // On retourne le modèle dans le bon sens - vertex->position = matrix * finalPos; - vertex->uv.Set(md5Vertex.uv.x, (parameters.flipUVs) ? 1.f - md5Vertex.uv.y : md5Vertex.uv.y); // Inversion des UV si demandé - vertex++; + vertices->position = matrix * finalPos; + vertices->uv.Set(parameters.texCoordOffset + md5Vertex.uv * parameters.texCoordScale); + vertices++; } vertexMapper.Unmap(); diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index 2a59ba703..79af8f36c 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -265,8 +265,8 @@ namespace Nz if (vertexIndices.texCoord > 0) { - const Vector3f& uvw = texCoords[vertexIndices.texCoord-1]; - vertex.uv.Set(uvw.x, (parameters.flipUVs) ? 1.f - uvw.y : uvw.y); // Inversion des UVs si demandé + Vector2f uv = texCoords[vertexIndices.texCoord - 1]; + vertex.uv.Set(parameters.texCoordOffset + uv * parameters.texCoordScale); } else hasTexCoords = false;