From 3409461c39cbbae3d23050b3c871825a1e85d6e0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 29 Jan 2013 02:01:28 +0100 Subject: [PATCH] SkeletalMesh::Skin now use threads Former-commit-id: 4b26b3e1950548887f0a7d246864a968688ca0b4 --- include/Nazara/Utility/Config.hpp | 3 + src/Nazara/Utility/SkeletalMesh.cpp | 155 ++++++++++++++++++++++------ src/Nazara/Utility/Utility.cpp | 4 + 3 files changed, 132 insertions(+), 30 deletions(-) diff --git a/include/Nazara/Utility/Config.hpp b/include/Nazara/Utility/Config.hpp index bfc25e633..d59a8c64a 100644 --- a/include/Nazara/Utility/Config.hpp +++ b/include/Nazara/Utility/Config.hpp @@ -35,6 +35,9 @@ // Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution) #define NAZARA_UTILITY_MEMORYLEAKTRACKER 0 +// Le skinning doit-il prendre avantage du multi-threading ? (Boost de performances sur les processeurs multi-coeurs) +#define NAZARA_UTILITY_MULTITHREADED_SKINNING 1 + // Active les tests de sécurité basés sur le code (Conseillé pour le développement) #define NAZARA_UTILITY_SAFE 1 diff --git a/src/Nazara/Utility/SkeletalMesh.cpp b/src/Nazara/Utility/SkeletalMesh.cpp index 2badca925..f7eb6bc90 100644 --- a/src/Nazara/Utility/SkeletalMesh.cpp +++ b/src/Nazara/Utility/SkeletalMesh.cpp @@ -3,13 +3,116 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include +#include #include #include #include #include #include +namespace +{ + struct SkinningInfos + { + const NzJoint* joints; + const NzWeight* weights; + }; + + void Skin_Position(const SkinningInfos& skinningInfos, NzMeshVertex* inputVertex, NzMeshVertex* outputVertex, const NzVertexWeight* vertexWeights, unsigned int vertexCount) + { + for (unsigned int i = 0; i < vertexCount; ++i) + { + NzVector3f finalPosition(NzVector3f::Zero()); + + unsigned int weightCount = vertexWeights[i].weights.size(); + for (unsigned int j = 0; j < weightCount; ++j) + { + const NzWeight& weight = skinningInfos.weights[vertexWeights[i].weights[j]]; + + NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix()); + mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix()); + mat *= weight.weight; + + finalPosition += mat.Transform(inputVertex->position); + } + + outputVertex->position = finalPosition; + outputVertex->uv = inputVertex->uv; + + inputVertex++; + outputVertex++; + } + } + + void Skin_PositionNormal(const SkinningInfos& skinningInfos, NzMeshVertex* inputVertex, NzMeshVertex* outputVertex, const NzVertexWeight* vertexWeights, unsigned int vertexCount) + { + for (unsigned int i = 0; i < vertexCount; ++i) + { + NzVector3f finalPosition(NzVector3f::Zero()); + NzVector3f finalNormal(NzVector3f::Zero()); + + unsigned int weightCount = vertexWeights[i].weights.size(); + for (unsigned int j = 0; j < weightCount; ++j) + { + const NzWeight& weight = skinningInfos.weights[vertexWeights[i].weights[j]]; + + NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix()); + mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix()); + mat *= weight.weight; + + finalPosition += mat.Transform(inputVertex->position); + finalNormal += mat.Transform(inputVertex->normal, 0.f); + } + + finalNormal.Normalize(); + + outputVertex->normal = finalNormal; + outputVertex->position = finalPosition; + outputVertex->uv = inputVertex->uv; + + inputVertex++; + outputVertex++; + } + } + + void Skin_PositionNormalTangent(const SkinningInfos& skinningInfos, NzMeshVertex* inputVertex, NzMeshVertex* outputVertex, const NzVertexWeight* vertexWeights, unsigned int vertexCount) + { + for (unsigned int i = 0; i < vertexCount; ++i) + { + NzVector3f finalPosition(NzVector3f::Zero()); + NzVector3f finalNormal(NzVector3f::Zero()); + NzVector3f finalTangent(NzVector3f::Zero()); + + unsigned int weightCount = vertexWeights[i].weights.size(); + for (unsigned int j = 0; j < weightCount; ++j) + { + const NzWeight& weight = skinningInfos.weights[vertexWeights[i].weights[j]]; + + NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix()); + mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix()); + mat *= weight.weight; + + finalPosition += mat.Transform(inputVertex->position); + finalNormal += mat.Transform(inputVertex->normal, 0.f); + finalTangent += mat.Transform(inputVertex->tangent, 0.f); + } + + finalNormal.Normalize(); + finalTangent.Normalize(); + + outputVertex->normal = finalNormal; + outputVertex->position = finalPosition; + outputVertex->tangent = finalTangent; + outputVertex->uv = inputVertex->uv; + + inputVertex++; + outputVertex++; + } + } +} + struct NzSkeletalMeshImpl { std::vector vertexWeights; @@ -276,40 +379,32 @@ void NzSkeletalMesh::Skin(const NzSkeleton* skeleton) const NzMeshVertex* inputVertex = reinterpret_cast(m_impl->bindPoseBuffer); NzMeshVertex* outputVertex = reinterpret_cast(mapper.GetPointer()); - const NzJoint* joints = skeleton->GetJoints(); unsigned int vertexCount = m_impl->vertexBuffer->GetVertexCount(); - for (unsigned int i = 0; i < vertexCount; ++i) + + SkinningInfos skinningInfos; + skinningInfos.joints = skeleton->GetJoints(); + skinningInfos.weights = &m_impl->weights[0]; + + #if NAZARA_UTILITY_MULTITHREADED_SKINNING + unsigned int workerCount = NzTaskScheduler::GetWorkerCount(); + unsigned int vertexPerWorker = vertexCount / workerCount; + unsigned int extraVertex = vertexCount % workerCount; // Il est très probable que la division ne soit pas parfaite + + for (unsigned int i = 0; i < workerCount; ++i) { - NzVector3f finalPosition(NzVector3f::Zero()); - NzVector3f finalNormal(NzVector3f::Zero()); - NzVector3f finalTangent(NzVector3f::Zero()); - - unsigned int weightCount = m_impl->vertexWeights[i].weights.size(); - for (unsigned int j = 0; j < weightCount; ++j) - { - const NzWeight& weight = m_impl->weights[m_impl->vertexWeights[i].weights[j]]; - - NzMatrix4f mat(joints[weight.jointIndex].GetInverseBindMatrix()); - mat.ConcatenateAffine(joints[weight.jointIndex].GetTransformMatrix()); - mat *= weight.weight; - - finalPosition += mat.Transform(inputVertex->position); - finalNormal += mat.Transform(inputVertex->normal, 0.f); - finalTangent += mat.Transform(inputVertex->tangent, 0.f); - } - - finalNormal.Normalize(); - finalTangent.Normalize(); - - outputVertex->normal = finalNormal; - outputVertex->position = finalPosition; - outputVertex->tangent = finalTangent; - outputVertex->uv = inputVertex->uv; - - inputVertex++; - outputVertex++; + NzTaskScheduler::AddTask(Skin_PositionNormalTangent, + skinningInfos, + &inputVertex[i*vertexPerWorker], + &outputVertex[i*vertexPerWorker], + &m_impl->vertexWeights[i*vertexPerWorker], + (i == workerCount-1) ? vertexPerWorker + extraVertex : vertexPerWorker); } + NzTaskScheduler::WaitForTasks(); + #else + Skin_PositionNormalTangent(skinningInfos, inputVertex, outputVertex, &m_impl->vertexWeights[0], vertexCount); + #endif + m_impl->aabb = skeleton->GetAABB(); } diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index 6f843901c..0ac701a76 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -23,7 +23,11 @@ bool NzUtility::Initialize() return true; // Déjà initialisé // Initialisation des dépendances + #if NAZARA_UTILITY_MULTITHREADED_SKINNING + if (!NzCore::Initialize(false, true)) + #else if (!NzCore::Initialize()) + #endif { NazaraError("Failed to initialize core module"); Uninitialize();