1#include <Core/Animation/DualQuaternionSkinning.hpp>
3#include <Core/Animation/SkinningData.hpp>
9DQList computeDQ(
const Pose& pose,
const Sparse& weight ) {
10 CORE_ASSERT( ( pose.size() ==
size_t( weight.cols() ) ),
"pose/weight size mismatch." );
11 DQList DQ( weight.rows(),
12 DualQuaternion( Quaternion( 0, 0, 0, 0 ), Quaternion( 0, 0, 0, 0 ) ) );
20 for (
int j = 0; j < weight.outerSize(); ++j ) {
21 poseDQ[j] = DualQuaternion( pose[j] );
23 const int nonZero = weight.col( j ).nonZeros();
25 Sparse::InnerIterator it0( weight, j );
26#pragma omp parallel for
40 for (
int nz = 0; nz < nonZero; ++nz ) {
41 Sparse::InnerIterator itn = it0 + Eigen::Index( nz );
42 const uint i = itn.row();
43 const Scalar w = itn.value();
45 firstNonZero[i] =
std::min( firstNonZero[i], uint( j ) );
49 const auto wq = poseDQ[j] * w *
sign;
55#pragma omp parallel for
56 for (
int i = 0; i < int( DQ.size() ); ++i ) {
65DQList computeDQ_naive(
const Pose& pose,
const Sparse& weight ) {
66 CORE_ASSERT( ( pose.size() ==
size_t( weight.cols() ) ),
"pose/weight size mismatch." );
67 DQList DQ( weight.rows(),
68 DualQuaternion( Quaternion( 0, 0, 0, 0 ), Quaternion( 0, 0, 0, 0 ) ) );
72#pragma omp parallel for
73 for (
int j = 0; j < weight.cols(); ++j ) {
74 poseDQ[j] = DualQuaternion( pose[j] );
78 for (
int i = 0; i < weight.rows(); ++i ) {
79 int firstNonZero = -1;
80 for ( uint j = 0; j < weight.cols(); ++j ) {
81 const Scalar& w = weight.coeff( i, j );
82 if ( w == 0 ) {
continue; }
84 if ( firstNonZero < 0 ) { firstNonZero = j; }
91 DQ[i] +=
sign * w * poseDQ[j];
96#pragma omp parallel for
97 for (
int i = 0; i < int( DQ.size() ); ++i ) {
104Vector3Array applyDualQuaternions(
const DQList& DQ,
const Vector3Array& vertices ) {
105 Vector3Array out( vertices.size(), Vector3::Zero() );
106#pragma omp parallel for
107 for (
int i = 0; i < int( vertices.size() ); ++i ) {
108 out[i] = DQ[i].transform( vertices[i] );
113void dualQuaternionSkinning(
const SkinningRefData& refData,
114 const Vector3Array& tangents,
115 const Vector3Array& bitangents,
116 SkinningFrameData& frameData ) {
118 auto pose = frameData.m_skeleton.getPose( HandleArray::SpaceType::MODEL );
119#pragma omp parallel for
120 for (
int i = 0; i < int( frameData.m_skeleton.size() ); ++i ) {
121 pose[i] = refData.m_meshTransformInverse * pose[i] * refData.m_bindMatrices[i];
124 const auto DQ = computeDQ( pose, refData.m_weights );
126 const auto& vertices = refData.m_referenceMesh.vertices();
127 const auto& normals = refData.m_referenceMesh.normals();
128#pragma omp parallel for
129 for (
int i = 0; i < int( frameData.m_currentPosition.size() ); ++i ) {
130 const auto& DQi = DQ[i];
131 frameData.m_currentPosition[i] = DQi.transform( vertices[i] );
132 frameData.m_currentNormal[i] = DQi.rotate( normals[i] );
133 frameData.m_currentTangent[i] = DQi.rotate( tangents[i] );
134 frameData.m_currentBitangent[i] = DQi.rotate( bitangents[i] );
constexpr T signNZ(const T &val)
constexpr int sign(const T &val)
Returns the sign of any numeric type as { -1, 0, 1}.
hepler function to manage enum as underlying types in VariableSet