Loading [MathJax]/extensions/TeX/AMSmath.js
Radium Engine  1.6.3
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
HandleWeightOperation.cpp
1#include <Core/Animation/HandleWeightOperation.hpp>
2#include <Core/Math/LinearAlgebra.hpp> // Math::checkInvalidNumbers
3#include <Core/Math/Math.hpp>
4#include <Core/Types.hpp>
5#include <Core/Utils/Log.hpp>
6#include <Eigen/Core>
7#include <algorithm>
8#include <memory>
9#include <ostream>
10#include <string>
11#include <utility>
12
13namespace Ra {
14namespace Core {
15namespace Animation {
16
17using namespace Utils; // log
18
19WeightMatrix extractWeightMatrix( const MeshWeight& weight, const uint weight_size ) {
20 WeightMatrix W( weight.size(), weight_size );
21 W.setZero();
22 for ( uint i = 0; i < weight.size(); ++i ) {
23 for ( const auto& w : weight[i] ) {
24 W.coeffRef( i, w.first ) = w.second;
25 }
26 }
27 return W;
28}
29
30MeshWeight extractMeshWeight( Eigen::Ref<const WeightMatrix> matrix ) {
31 MeshWeight W( matrix.rows() );
32 for ( int i = 0; i < matrix.rows(); ++i ) {
33 for ( int j = 0; j < matrix.cols(); ++j ) {
34 if ( matrix.coeff( i, j ) != 0.0 ) {
35 std::pair<uint, Scalar> w( uint( j ), matrix.coeff( i, j ) );
36 W[i].push_back( w );
37 }
38 }
39 }
40 return W;
41}
42
43WeightMatrix partitionOfUnity( Eigen::Ref<const WeightMatrix> weights ) {
44 WeightMatrix W = weights;
45 normalizeWeights( W );
46 return W;
47}
48
49uint getMaxWeightIndex( Eigen::Ref<const WeightMatrix> weights, const uint vertexID ) {
50 uint maxId = uint( -1 );
51 VectorN row = weights.row( vertexID );
52 row.maxCoeff( &maxId );
53 return maxId;
54}
55
56void getMaxWeightIndex( Eigen::Ref<const WeightMatrix> weights, std::vector<uint>& handleID ) {
57 handleID.resize( weights.rows() );
58 for ( int i = 0; i < weights.rows(); ++i ) {
59 handleID[i] = getMaxWeightIndex( weights, i );
60 }
61}
62
63bool checkWeightMatrix( Eigen::Ref<const WeightMatrix> matrix,
64 const bool FAIL_ON_ASSERT,
65 const bool MT ) {
66 bool ok = Math::checkInvalidNumbers( matrix, FAIL_ON_ASSERT ) &&
67 checkNoWeightVertex( matrix, FAIL_ON_ASSERT, MT );
68
69 if ( !ok ) { LOG( logDEBUG ) << "Matrix is not good."; }
70
71 return ok;
72}
73
74bool checkNoWeightVertex( Eigen::Ref<const WeightMatrix> matrix,
75 const bool FAIL_ON_ASSERT,
76 const bool MT ) {
77 int status = 1;
78 LOG( logDEBUG ) << "Searching for empty rows in the matrix...";
79 if ( MT ) {
80#pragma omp parallel for
81 for ( int i = 0; i < matrix.rows(); ++i ) {
82 Sparse row = matrix.row( i );
83 const int check = ( row.nonZeros() > 0 ) ? 1 : 0;
84#pragma omp atomic
85 status &= check;
86 }
87 if ( status == 0 ) {
88 if ( FAIL_ON_ASSERT ) { CORE_ASSERT( false, "At least a vertex as no weights" ); }
89 else { LOG( logDEBUG ) << "At least a vertex as no weights"; }
90 }
91 }
92 else {
93 for ( int i = 0; i < matrix.rows(); ++i ) {
94 Sparse row = matrix.row( i );
95 if ( row.nonZeros() == 0 ) {
96 status = 0;
97
98 const std::string text = "Vertex " + std::to_string( i ) + " has no weights.";
99 if ( FAIL_ON_ASSERT ) { CORE_ASSERT( false, text.c_str() ); }
100 else { LOG( logDEBUG ) << text; }
101 }
102 }
103 }
104 return status != 0;
105}
106
107bool normalizeWeights( Eigen::Ref<WeightMatrix> matrix, const bool MT ) {
108 CORE_UNUSED( MT );
109
110 bool skinningWeightOk = true;
111
112#pragma omp parallel for if ( MT )
113 for ( int k = 0; k < matrix.innerSize(); ++k ) {
114 const Scalar sum = matrix.row( k ).sum();
115 if ( !Ra::Core::Math::areApproxEqual( sum, 0_ra ) ) {
116 if ( !Ra::Core::Math::areApproxEqual( sum, 1_ra ) ) {
117 skinningWeightOk = false;
118 matrix.row( k ) /= sum;
119 }
120 }
121 }
122 return !skinningWeightOk;
123}
124
125} // namespace Animation
126} // Namespace Core
127} // 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:4
T resize(T... args)
T to_string(T... args)