Radium Engine  1.5.20
Loading...
Searching...
No Matches
HandleWeightOperation.cpp
1#include <Core/Animation/HandleWeightOperation.hpp>
2#include <Core/Math/LinearAlgebra.hpp> // Math::checkInvalidNumbers
3#include <Core/Utils/Log.hpp>
4#include <utility>
5
6namespace Ra {
7namespace Core {
8namespace Animation {
9
10using namespace Utils; // log
11
12WeightMatrix extractWeightMatrix( const MeshWeight& weight, const uint weight_size ) {
13 WeightMatrix W( weight.size(), weight_size );
14 W.setZero();
15 for ( uint i = 0; i < weight.size(); ++i ) {
16 for ( const auto& w : weight[i] ) {
17 W.coeffRef( i, w.first ) = w.second;
18 }
19 }
20 return W;
21}
22
23MeshWeight extractMeshWeight( Eigen::Ref<const WeightMatrix> matrix ) {
24 MeshWeight W( matrix.rows() );
25 for ( int i = 0; i < matrix.rows(); ++i ) {
26 for ( int j = 0; j < matrix.cols(); ++j ) {
27 if ( matrix.coeff( i, j ) != 0.0 ) {
28 std::pair<uint, Scalar> w( uint( j ), matrix.coeff( i, j ) );
29 W[i].push_back( w );
30 }
31 }
32 }
33 return W;
34}
35
36WeightMatrix partitionOfUnity( Eigen::Ref<const WeightMatrix> weights ) {
37 WeightMatrix W = weights;
38 normalizeWeights( W );
39 return W;
40}
41
42uint getMaxWeightIndex( Eigen::Ref<const WeightMatrix> weights, const uint vertexID ) {
43 uint maxId = uint( -1 );
44 VectorN row = weights.row( vertexID );
45 row.maxCoeff( &maxId );
46 return maxId;
47}
48
49void getMaxWeightIndex( Eigen::Ref<const WeightMatrix> weights, std::vector<uint>& handleID ) {
50 handleID.resize( weights.rows() );
51 for ( int i = 0; i < weights.rows(); ++i ) {
52 handleID[i] = getMaxWeightIndex( weights, i );
53 }
54}
55
56bool checkWeightMatrix( Eigen::Ref<const WeightMatrix> matrix,
57 const bool FAIL_ON_ASSERT,
58 const bool MT ) {
59 bool ok = Math::checkInvalidNumbers( matrix, FAIL_ON_ASSERT ) &&
60 checkNoWeightVertex( matrix, FAIL_ON_ASSERT, MT );
61
62 if ( !ok ) { LOG( logDEBUG ) << "Matrix is not good."; }
63
64 return ok;
65}
66
67bool checkNoWeightVertex( Eigen::Ref<const WeightMatrix> matrix,
68 const bool FAIL_ON_ASSERT,
69 const bool MT ) {
70 int status = 1;
71 LOG( logDEBUG ) << "Searching for empty rows in the matrix...";
72 if ( MT ) {
73#pragma omp parallel for
74 for ( int i = 0; i < matrix.rows(); ++i ) {
75 Sparse row = matrix.row( i );
76 const int check = ( row.nonZeros() > 0 ) ? 1 : 0;
77#pragma omp atomic
78 status &= check;
79 }
80 if ( status == 0 ) {
81 if ( FAIL_ON_ASSERT ) { CORE_ASSERT( false, "At least a vertex as no weights" ); }
82 else { LOG( logDEBUG ) << "At least a vertex as no weights"; }
83 }
84 }
85 else {
86 for ( int i = 0; i < matrix.rows(); ++i ) {
87 Sparse row = matrix.row( i );
88 if ( row.nonZeros() == 0 ) {
89 status = 0;
90
91 const std::string text = "Vertex " + std::to_string( i ) + " has no weights.";
92 if ( FAIL_ON_ASSERT ) { CORE_ASSERT( false, text.c_str() ); }
93 else { LOG( logDEBUG ) << text; }
94 }
95 }
96 }
97 return status != 0;
98}
99
100bool normalizeWeights( Eigen::Ref<WeightMatrix> matrix, const bool MT ) {
101 CORE_UNUSED( MT );
102
103 bool skinningWeightOk = true;
104
105#pragma omp parallel for if ( MT )
106 for ( int k = 0; k < matrix.innerSize(); ++k ) {
107 const Scalar sum = matrix.row( k ).sum();
108 if ( !Ra::Core::Math::areApproxEqual( sum, 0_ra ) ) {
109 if ( !Ra::Core::Math::areApproxEqual( sum, 1_ra ) ) {
110 skinningWeightOk = false;
111 matrix.row( k ) /= sum;
112 }
113 }
114 }
115 return !skinningWeightOk;
116}
117
118} // namespace Animation
119} // Namespace Core
120} // Namespace Ra
T c_str(T... args)
std::enable_if<!std::numeric_limits< T >::is_integer, bool >::type areApproxEqual(T x, T y, T espilonBoostFactor=T(10))
Compare two numbers such that |x-y| < espilon*epsilonBoostFactor.
Definition Math.hpp:42
bool checkInvalidNumbers(Eigen::Ref< Eigen::Quaternion< S > > q, const bool FAIL_ON_ASSERT=false)
Call std::isfinite on quaternion entries.
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T resize(T... args)
T to_string(T... args)