From 9daadb73bc895c82a436fcdc7f199b52e9b43617 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 21 Oct 2017 04:51:05 +0200 Subject: [PATCH] Utility: Make mesh loader use the parameters vertex declaration --- ChangeLog.md | 3 +- include/Nazara/Utility/Mesh.hpp | 2 +- plugins/Assimp/Plugin.cpp | 76 ++++++++++++++++---- src/Nazara/Utility/AlgorithmUtility.cpp | 2 +- src/Nazara/Utility/Formats/MD2Loader.cpp | 57 +++++++++------ src/Nazara/Utility/Formats/MD5MeshLoader.cpp | 31 +++++--- src/Nazara/Utility/Formats/OBJLoader.cpp | 51 ++++++++----- src/Nazara/Utility/Mesh.cpp | 12 +++- src/Nazara/Utility/SubMesh.cpp | 18 +++-- 9 files changed, 181 insertions(+), 71 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index a3648ad14..55662f1b5 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,7 +2,8 @@ Nazara Engine: - VertexMapper:GetComponentPtr no longer throw an error if component is disabled or incompatible with template type, instead a null pointer is returned. -- MeshParams now hold a ConstRef to the VertexDeclaration (preventing it to be freed before usage) +- Bitset swap operation is now correctly marked as noexcept` +- Mesh loaders now takes MeshParams vertexDeclaration into account # 0.4: diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index ebbb8130f..ca0971aa2 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -48,7 +48,7 @@ namespace Nz * If the declaration has a Vector3f Normals component enabled, Normals are generated. * If the declaration has a Vector3f Tangents component enabled, Tangents are generated. */ - VertexDeclarationConstRef vertexDeclaration = VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent); + VertexDeclaration* vertexDeclaration = VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent); bool IsValid() const; }; diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index 9aa9f84b7..61e290bca 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -32,6 +32,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -119,13 +120,27 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) long long vertexLimit = 1'000'000; parameters.custom.GetIntegerParameter("AssimpLoader_VertexLimit", &vertexLimit); + int excludedComponents = 0; + + if (!parameters.vertexDeclaration->HasComponent(VertexComponent_Color)) + excludedComponents |= aiComponent_COLORS; + + if (!parameters.vertexDeclaration->HasComponent(VertexComponent_Normal)) + excludedComponents |= aiComponent_NORMALS; + + if (!parameters.vertexDeclaration->HasComponent(VertexComponent_Tangent)) + excludedComponents |= aiComponent_TANGENTS_AND_BITANGENTS; + + if (!parameters.vertexDeclaration->HasComponent(VertexComponent_TexCoord)) + excludedComponents |= aiComponent_TEXCOORDS; + aiPropertyStore* properties = aiCreatePropertyStore(); aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, float(smoothingAngle)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SBP_REMOVE, ~aiPrimitiveType_TRIANGLE); //< We only want triangles aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, int(triangleLimit)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_VERTEX_LIMIT, int(vertexLimit)); - aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, aiComponent_COLORS); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, excludedComponents); const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, postProcess, &fileIO, properties); aiReleasePropertyStore(properties); @@ -210,22 +225,56 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) if (normalTangentMatrix.HasScale()) normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, parameters.vertexBufferFlags); - BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, vertexCount, parameters.storage, parameters.vertexBufferFlags); - MeshVertex* vertex = static_cast(vertexMapper.GetPointer()); + VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); + + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); for (unsigned int j = 0; j < vertexCount; ++j) { aiVector3D position = iMesh->mVertices[j]; - aiVector3D normal = iMesh->mNormals[j]; - aiVector3D tangent = (iMesh->HasTangentsAndBitangents()) ? iMesh->mTangents[j] : aiVector3D(0.f, 1.f, 0.f); - aiVector3D uv = (iMesh->HasTextureCoords(0)) ? iMesh->mTextureCoords[0][j] : aiVector3D(0.f); + *posPtr++ = parameters.matrix * Vector3f(position.x, position.y, position.z); + } - vertex->position = parameters.matrix * Vector3f(position.x, position.y, position.z); - vertex->normal = normalTangentMatrix.Transform({normal.x, normal.y, normal.z}, 0.f); - vertex->tangent = normalTangentMatrix.Transform({tangent.x, tangent.y, tangent.z}, 0.f); - vertex->uv.Set(parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale); - vertex++; + if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal)) + { + for (unsigned int j = 0; j < vertexCount; ++j) + { + aiVector3D normal = iMesh->mNormals[j]; + *normalPtr++ = normalTangentMatrix.Transform({normal.x, normal.y, normal.z}, 0.f); + } + } + + bool generateTangents = false; + if (auto tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent)) + { + if (iMesh->HasTangentsAndBitangents()) + { + for (unsigned int j = 0; j < vertexCount; ++j) + { + aiVector3D tangent = iMesh->mTangents[j]; + *tangentPtr++ = normalTangentMatrix.Transform({tangent.x, tangent.y, tangent.z}, 0.f); + } + } + else + generateTangents = true; + } + + if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord)) + { + if (iMesh->HasTextureCoords(0)) + { + for (unsigned int j = 0; j < vertexCount; ++j) + { + aiVector3D uv = iMesh->mTextureCoords[0][j]; + *uvPtr++ = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale; + } + } + else + { + for (unsigned int j = 0; j < vertexCount; ++j) + *uvPtr++ = Vector2f::Zero(); + } } vertexMapper.Unmap(); @@ -238,6 +287,9 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) subMesh->GenerateAABB(); subMesh->SetMaterialIndex(iMesh->mMaterialIndex); + if (generateTangents) + subMesh->GenerateTangents(); + auto matIt = materials.find(iMesh->mMaterialIndex); if (matIt == materials.end()) { diff --git a/src/Nazara/Utility/AlgorithmUtility.cpp b/src/Nazara/Utility/AlgorithmUtility.cpp index 111c45f1e..22bf4bb43 100644 --- a/src/Nazara/Utility/AlgorithmUtility.cpp +++ b/src/Nazara/Utility/AlgorithmUtility.cpp @@ -1164,6 +1164,6 @@ namespace Nz if (vertexPointers.tangentPtr) *vertexPointers.tangentPtr++ = matrix.Transform(*vertexPointers.tangentPtr, 0.f) / scale; - } + } } } diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index a91349617..6758a2e1b 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -7,11 +7,12 @@ #include #include #include -#include #include #include #include +#include #include +#include #include #include @@ -156,7 +157,7 @@ namespace Nz } #endif - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), header.num_vertices, parameters.storage, parameters.vertexBufferFlags); + VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, header.num_vertices, parameters.storage, parameters.vertexBufferFlags); StaticMeshRef subMesh = StaticMesh::New(mesh); if (!subMesh->Create(vertexBuffer)) { @@ -189,23 +190,26 @@ namespace Nz scale *= ScaleAdjust; translate *= ScaleAdjust; - BufferMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); - MeshVertex* vertex = static_cast(vertexMapper.GetPointer()); + VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); // 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) + if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord)) { - for (unsigned int j = 0; j < 3; ++j) + 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) { - const unsigned int fixedIndex = indexFix[j]; //< Reverse winding order + for (unsigned int j = 0; j < 3; ++j) + { + const unsigned int fixedIndex = indexFix[j]; //< Reverse winding order - const MD2_TexCoord& texC = texCoords[triangles[i].texCoords[fixedIndex]]; - Vector2f uv(texC.u, texC.v); - uv *= invSkinSize; + 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); + uvPtr[triangles[i].vertices[fixedIndex]].Set(parameters.texCoordOffset + uv * parameters.texCoordScale); + } } } @@ -216,18 +220,27 @@ namespace Nz Nz::Matrix4f matrix = Matrix4f::Transform(translate, rotationQuat, scale); matrix *= parameters.matrix; - Nz::Matrix4f normalMatrix = Matrix4f::Rotate(rotationQuat); - normalMatrix *= parameters.matrix; + if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal)) + { + Nz::Matrix4f normalMatrix = Matrix4f::Rotate(rotationQuat); + normalMatrix *= parameters.matrix; + + for (unsigned int v = 0; v < header.num_vertices; ++v) + { + const MD2_Vertex& vert = vertices[v]; + + *normalPtr++ = normalMatrix.Transform(md2Normals[vert.n], 0.f); + } + } + + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); + assert(posPtr); for (unsigned int v = 0; v < header.num_vertices; ++v) { const MD2_Vertex& vert = vertices[v]; - Vector3f position = matrix * Vector3f(vert.x, vert.y, vert.z); - vertex->position = position; - vertex->normal = normalMatrix.Transform(md2Normals[vert.n], 0.f); - - vertex++; + *posPtr++ = matrix * Vector3f(vert.x, vert.y, vert.z); } vertexMapper.Unmap(); @@ -236,7 +249,9 @@ namespace Nz subMesh->SetMaterialIndex(0); subMesh->GenerateAABB(); - subMesh->GenerateTangents(); + + if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent_Tangent)) + subMesh->GenerateTangents(); mesh->AddSubMesh(subMesh); diff --git a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp index 9ab8a93eb..d7104b9d0 100644 --- a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,7 @@ namespace Nz BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); SkeletalMeshVertex* vertices = static_cast(vertexMapper.GetPointer()); + for (const MD5MeshParser::Vertex& vertex : md5Mesh.vertices) { // Skinning MD5 (Formule d'Id Tech) @@ -254,13 +256,15 @@ namespace Nz indexMapper.Unmap(); // Vertex buffer - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); - BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); + + VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); + + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - MeshVertex* vertices = static_cast(vertexMapper.GetPointer()); for (const MD5MeshParser::Vertex& md5Vertex : md5Mesh.vertices) { - // Skinning MD5 (Formule d'Id Tech) + // Id Tech MD5 skinning Vector3f finalPos(Vector3f::Zero()); for (unsigned int j = 0; j < md5Vertex.weightCount; ++j) { @@ -271,9 +275,13 @@ namespace Nz } // On retourne le modèle dans le bon sens - vertices->position = matrix * finalPos; - vertices->uv.Set(parameters.texCoordOffset + md5Vertex.uv * parameters.texCoordScale); - vertices++; + *posPtr++ = matrix * finalPos; + } + + if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord)) + { + for (const MD5MeshParser::Vertex& md5Vertex : md5Mesh.vertices) + *uvPtr++ = parameters.texCoordOffset + md5Vertex.uv * parameters.texCoordScale; } vertexMapper.Unmap(); @@ -287,9 +295,16 @@ namespace Nz subMesh->SetIndexBuffer(indexBuffer); subMesh->GenerateAABB(); - subMesh->GenerateNormalsAndTangents(); subMesh->SetMaterialIndex(i); + if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent_Normal)) + { + if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent_Tangent)) + subMesh->GenerateNormalsAndTangents(); + else + subMesh->GenerateNormals(); + } + mesh->AddSubMesh(subMesh); // Material diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index da2480e4f..da69bcac7 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -4,11 +4,11 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -232,7 +232,7 @@ namespace Nz // Création des buffers IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), UInt32(indices.size()), parameters.storage, parameters.indexBufferFlags); - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); + VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); // Remplissage des indices IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); @@ -250,30 +250,45 @@ namespace Nz bool hasNormals = true; bool hasTexCoords = true; - BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); - MeshVertex* meshVertices = static_cast(vertexMapper.GetPointer()); + + VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); + + auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); + auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + + if (!normalPtr) + hasNormals = false; + + if (!uvPtr) + hasTexCoords = false; + for (auto& vertexPair : vertices) { const OBJParser::FaceVertex& vertexIndices = vertexPair.first; unsigned int index = vertexPair.second; - MeshVertex& vertex = meshVertices[index]; - const Vector4f& vec = positions[vertexIndices.position-1]; - vertex.position = Vector3f(parameters.matrix * vec); + posPtr[index] = Vector3f(parameters.matrix * vec); - if (vertexIndices.normal > 0) - vertex.normal = normalMatrix.Transform(normals[vertexIndices.normal - 1], 0.f); - else - hasNormals = false; - - if (vertexIndices.texCoord > 0) + if (hasNormals) { - Vector2f uv = Vector2f(texCoords[vertexIndices.texCoord - 1]); - vertex.uv.Set(parameters.texCoordOffset + uv * parameters.texCoordScale); + if (vertexIndices.normal > 0) + normalPtr[index] = normalMatrix.Transform(normals[vertexIndices.normal - 1], 0.f); + else + hasNormals = false; + } + + if (hasTexCoords) + { + if (vertexIndices.texCoord > 0) + { + Vector2f uv = Vector2f(texCoords[vertexIndices.texCoord - 1]); + uvPtr[index] = Vector2f(parameters.texCoordOffset + uv * parameters.texCoordScale); + } + else + hasTexCoords = false; } - else - hasTexCoords = false; } vertexMapper.Unmap(); @@ -298,7 +313,7 @@ namespace Nz subMesh->GenerateTangents(); else if (hasTexCoords) subMesh->GenerateNormalsAndTangents(); - else + else if (normalPtr) subMesh->GenerateNormals(); mesh->AddSubMesh(meshes[i].name + '_' + materials[meshes[i].material], subMesh); diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index 3861e389b..66ee817ff 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -47,6 +47,12 @@ namespace Nz return false; } + if (!vertexDeclaration->HasComponent(VertexComponent_Position)) + { + NazaraError("Vertex declaration must contains a vertex position"); + return false; + } + return true; } @@ -54,7 +60,7 @@ namespace Nz { MeshImpl() { - materialData.resize(1); // Un matériau par défaut + materialData.resize(1); // One material by default } std::unordered_map subMeshMap; @@ -62,10 +68,10 @@ namespace Nz std::vector subMeshes; AnimationType animationType; Boxf aabb; - Skeleton skeleton; // Uniquement pour les meshs squelettiques + Skeleton skeleton; // Only used by skeletal meshes String animationPath; bool aabbUpdated = false; - UInt32 jointCount; // Uniquement pour les meshs squelettiques + UInt32 jointCount; // Only used by skeletal meshes }; Mesh::~Mesh() diff --git a/src/Nazara/Utility/SubMesh.cpp b/src/Nazara/Utility/SubMesh.cpp index 910b3b2fb..44e601d22 100644 --- a/src/Nazara/Utility/SubMesh.cpp +++ b/src/Nazara/Utility/SubMesh.cpp @@ -28,12 +28,14 @@ namespace Nz void SubMesh::GenerateNormals() { VertexMapper mapper(this); - unsigned int vertexCount = GetVertexCount(); + UInt32 vertexCount = mapper.GetVertexCount(); SparsePtr normals = mapper.GetComponentPtr(VertexComponent_Normal); SparsePtr positions = mapper.GetComponentPtr(VertexComponent_Position); + if (!normals || !positions) + return; - for (unsigned int i = 0; i < vertexCount; ++i) + for (UInt32 i = 0; i < vertexCount; ++i) normals[i].MakeZero(); TriangleIterator iterator(this); @@ -52,21 +54,23 @@ namespace Nz } while (iterator.Advance()); - for (unsigned int i = 0; i < vertexCount; ++i) + for (UInt32 i = 0; i < vertexCount; ++i) normals[i].Normalize(); } void SubMesh::GenerateNormalsAndTangents() { VertexMapper mapper(this); - unsigned int vertexCount = GetVertexCount(); + UInt32 vertexCount = mapper.GetVertexCount(); SparsePtr normals = mapper.GetComponentPtr(VertexComponent_Normal); SparsePtr positions = mapper.GetComponentPtr(VertexComponent_Position); SparsePtr tangents = mapper.GetComponentPtr(VertexComponent_Tangent); SparsePtr texCoords = mapper.GetComponentPtr(VertexComponent_TexCoord); + if (!normals || !positions || !tangents || !texCoords) + return; - for (unsigned int i = 0; i < vertexCount; ++i) + for (UInt32 i = 0; i < vertexCount; ++i) { normals[i].MakeZero(); tangents[i].MakeZero(); @@ -105,7 +109,7 @@ namespace Nz } while (iterator.Advance()); - for (unsigned int i = 0; i < vertexCount; ++i) + for (UInt32 i = 0; i < vertexCount; ++i) { normals[i].Normalize(); tangents[i].Normalize(); @@ -120,6 +124,8 @@ namespace Nz SparsePtr positions = mapper.GetComponentPtr(VertexComponent_Position); SparsePtr tangents = mapper.GetComponentPtr(VertexComponent_Tangent); SparsePtr texCoords = mapper.GetComponentPtr(VertexComponent_TexCoord); + if (!normals || !positions || !tangents || !texCoords) + return; TriangleIterator iterator(this); do