1212#include " momentum/character/blend_shape.h"
1313#include " momentum/character/blend_shape_skinning.h"
1414#include " momentum/character/linear_skinning.h"
15+ #include " momentum/character/mesh_state.h"
1516#include " momentum/character/skeleton_state.h"
1617#include " momentum/character/skin_weights.h"
1718#include " momentum/common/checks.h"
@@ -33,9 +34,6 @@ SkinnedLocatorTriangleErrorFunctionT<T>::SkinnedLocatorTriangleErrorFunctionT(
3334 MT_THROW_IF (
3435 type != VertexConstraintType::Position && type != VertexConstraintType::Plane,
3536 " SkinnedLocatorTriangleErrorFunction only supports Position and Plane constraint types" );
36-
37- this ->neutralMesh_ = std::make_unique<MeshT<T>>(character_in.mesh ->template cast <T>());
38- this ->restMesh_ = std::make_unique<MeshT<T>>(character_in.mesh ->template cast <T>());
3937}
4038
4139template <typename T>
@@ -160,63 +158,60 @@ std::array<Eigen::Matrix3<T>, 3> compute_d_targetPos_d_vertexPos(
160158template <typename T>
161159double SkinnedLocatorTriangleErrorFunctionT<T>::getError(
162160 const ModelParametersT<T>& modelParameters,
163- const SkeletonStateT<T>& /* state*/ ,
164- const MeshStateT<T>& /* meshState */ ) {
161+ const SkeletonStateT<T>& /* state */ ,
162+ const MeshStateT<T>& meshState) {
165163 MT_PROFILE_FUNCTION ();
166164
167- updateMeshes (modelParameters );
165+ MT_CHECK_NOTNULL (meshState. restMesh_ );
168166
169- // loop over all constraints and calculate the error
170167 double error = 0.0 ;
171168
172169 if (constraintType_ == VertexConstraintType::Position) {
173- for (size_t i = 0 ; i < constraints_.size (); ++i) {
174- const SkinnedLocatorTriangleConstraintT<T>& constr = constraints_[i];
175-
170+ for (const auto & constr : constraints_) {
176171 // Get the skinned locator position
177172 const Eigen::Vector3<T> locatorRestPos =
178173 getLocatorRestPosition (modelParameters, constr.locatorIndex );
179174
180175 // Get the target position on the triangle
181- const Eigen::Vector3<T> tgtPoint = computeTargetPosition (*this -> restMesh_ , constr);
176+ const Eigen::Vector3<T> tgtPoint = computeTargetPosition (*meshState. restMesh_ , constr);
182177
183178 // Calculate position error
184179 const Eigen::Vector3<T> diff = locatorRestPos - tgtPoint;
185180 error += constr.weight * diff.squaredNorm ();
186181 }
187- } else if (constraintType_ == VertexConstraintType::Plane) {
188- for (size_t i = 0 ; i < constraints_.size (); ++i) {
189- const SkinnedLocatorTriangleConstraintT<T>& constr = constraints_[i];
190-
182+ } else {
183+ MT_CHECK (constraintType_ == VertexConstraintType::Plane);
184+ for (const auto & constr : constraints_) {
191185 // Get the skinned locator position
192186 const Eigen::Vector3<T> locatorRestPos =
193187 getLocatorRestPosition (modelParameters, constr.locatorIndex );
194188
195189 // Get the target position and normal
196- const Eigen::Vector3<T> targetNormal = computeTargetTriangleNormal (*this ->restMesh_ , constr);
190+ const Eigen::Vector3<T> targetNormal =
191+ computeTargetTriangleNormal (*meshState.restMesh_ , constr);
197192 const Eigen::Vector3<T> tgtPoint =
198- computeTargetBaryPosition (*this -> restMesh_ , constr) + constr.depth * targetNormal;
193+ computeTargetBaryPosition (*meshState. restMesh_ , constr) + constr.depth * targetNormal;
199194 // Calculate plane error (projection onto normal)
200195 const T dist = targetNormal.dot (locatorRestPos - tgtPoint);
201196 error += constr.weight * dist * dist;
202197 }
203198 }
204199
205- // return error
206200 return error * this ->weight_ ;
207201}
208202
209203template <typename T>
210204double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePositionGradient(
211205 const ModelParametersT<T>& modelParameters,
206+ const MeshStateT<T>& meshState,
212207 const SkinnedLocatorTriangleConstraintT<T>& constr,
213208 Eigen::Ref<Eigen::VectorX<T>> gradient) const {
214209 // Get the skinned locator position
215210 const Eigen::Vector3<T> locatorRestPos =
216211 getLocatorRestPosition (modelParameters, constr.locatorIndex );
217212
218213 // Get the target position on the triangle
219- const Eigen::Vector3<T> tgtPoint = computeTargetPosition (*this -> restMesh_ , constr);
214+ const Eigen::Vector3<T> tgtPoint = computeTargetPosition (*meshState. restMesh_ , constr);
220215
221216 // Calculate position error
222217 const Eigen::Vector3<T> diff = locatorRestPos - tgtPoint;
@@ -226,7 +221,7 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePositionGradient(
226221
227222 // Get the derivative of the target position with respect to the triangle vertices
228223 const auto d_targetPos_d_tgtTriVertexPos =
229- compute_d_targetPos_d_vertexPos (constr, *this -> restMesh_ );
224+ compute_d_targetPos_d_vertexPos (constr, *meshState. restMesh_ );
230225
231226 // Apply gradient for locator parameter if it exists
232227 int paramIndex = getSkinnedLocatorParameterIndex (constr.locatorIndex );
@@ -270,16 +265,17 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePositionGradient(
270265template <typename T>
271266double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePlaneGradient(
272267 const ModelParametersT<T>& modelParameters,
268+ const MeshStateT<T>& meshState,
273269 const SkinnedLocatorTriangleConstraintT<T>& constr,
274270 Eigen::Ref<Eigen::VectorX<T>> gradient) const {
275271 // Get the skinned locator position
276272 const Eigen::Vector3<T> locatorRestPos =
277273 getLocatorRestPosition (modelParameters, constr.locatorIndex );
278274
279275 // Get the target position and normal
280- const Eigen::Vector3<T> targetNormal = computeTargetTriangleNormal (*this -> restMesh_ , constr);
276+ const Eigen::Vector3<T> targetNormal = computeTargetTriangleNormal (*meshState. restMesh_ , constr);
281277 const Eigen::Vector3<T> tgtPoint =
282- computeTargetBaryPosition (*this -> restMesh_ , constr) + constr.depth * targetNormal;
278+ computeTargetBaryPosition (*meshState. restMesh_ , constr) + constr.depth * targetNormal;
283279
284280 // Calculate plane error (projection onto normal)
285281 const Vector3<T> diff = locatorRestPos - tgtPoint;
@@ -288,9 +284,9 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePlaneGradient(
288284
289285 // Get the derivative of the target position with respect to the triangle vertices
290286 const auto d_targetPos_d_tgtTriVertexPos =
291- compute_d_targetPos_d_vertexPos (constr, *this -> restMesh_ );
287+ compute_d_targetPos_d_vertexPos (constr, *meshState. restMesh_ );
292288 const auto d_targetNormal_d_tgtTriVertexPos =
293- compute_d_targetNormal_d_vertexPos (constr, *this -> restMesh_ );
289+ compute_d_targetNormal_d_vertexPos (constr, *meshState. restMesh_ );
294290
295291 // Apply gradient for locator parameter if it exists
296292 int paramIndex = getSkinnedLocatorParameterIndex (constr.locatorIndex );
@@ -334,6 +330,7 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePlaneGradient(
334330template <typename T>
335331double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePositionJacobian(
336332 const ModelParametersT<T>& modelParameters,
333+ const MeshStateT<T>& meshState,
337334 const SkinnedLocatorTriangleConstraintT<T>& constr,
338335 Ref<Eigen::MatrixX<T>> jac,
339336 Ref<Eigen::VectorX<T>> res) const {
@@ -342,7 +339,7 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePositionJacobian(
342339 getLocatorRestPosition (modelParameters, constr.locatorIndex );
343340
344341 // Get the target position on the triangle
345- const Eigen::Vector3<T> tgtPoint = computeTargetPosition (*this -> restMesh_ , constr);
342+ const Eigen::Vector3<T> tgtPoint = computeTargetPosition (*meshState. restMesh_ , constr);
346343
347344 // Calculate position error
348345 const Eigen::Vector3<T> diff = locatorRestPos - tgtPoint;
@@ -353,7 +350,7 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePositionJacobian(
353350
354351 // Get the derivative of the target position with respect to the triangle vertices
355352 const auto d_targetPos_d_tgtTriVertexPos =
356- compute_d_targetPos_d_vertexPos (constr, *this -> restMesh_ );
353+ compute_d_targetPos_d_vertexPos (constr, *meshState. restMesh_ );
357354
358355 // Apply Jacobian for locator parameter if it exists
359356 int paramIndex = getSkinnedLocatorParameterIndex (constr.locatorIndex );
@@ -395,6 +392,7 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePositionJacobian(
395392template <typename T>
396393double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePlaneJacobian(
397394 const ModelParametersT<T>& modelParameters,
395+ const MeshStateT<T>& meshState,
398396 const SkinnedLocatorTriangleConstraintT<T>& constr,
399397 Ref<Eigen::MatrixX<T>> jac,
400398 T& res) const {
@@ -403,23 +401,22 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePlaneJacobian(
403401 getLocatorRestPosition (modelParameters, constr.locatorIndex );
404402
405403 // Get the target position and normal
406- const Eigen::Vector3<T> targetNormal = computeTargetTriangleNormal (*this -> restMesh_ , constr);
404+ const Eigen::Vector3<T> targetNormal = computeTargetTriangleNormal (*meshState. restMesh_ , constr);
407405 const Eigen::Vector3<T> tgtPoint =
408- computeTargetBaryPosition (*this -> restMesh_ , constr) + constr.depth * targetNormal;
406+ computeTargetBaryPosition (*meshState. restMesh_ , constr) + constr.depth * targetNormal;
409407
410408 // Calculate plane error (projection onto normal)
411409 const Eigen::Vector3<T> diff = locatorRestPos - tgtPoint;
412410 const T dist = targetNormal.dot (diff);
413411
414- // Set residual
415412 const T wgt = std::sqrt (constr.weight * this ->weight_ );
416413 res = wgt * dist;
417414
418415 // Get the derivative of the target position with respect to the triangle vertices
419416 const auto d_targetPos_d_tgtTriVertexPos =
420- compute_d_targetPos_d_vertexPos (constr, *this -> restMesh_ );
417+ compute_d_targetPos_d_vertexPos (constr, *meshState. restMesh_ );
421418 const auto d_targetNormal_d_tgtTriVertexPos =
422- compute_d_targetNormal_d_vertexPos (constr, *this -> restMesh_ );
419+ compute_d_targetNormal_d_vertexPos (constr, *meshState. restMesh_ );
423420
424421 // Apply Jacobian for locator parameter if it exists
425422 int paramIndex = getSkinnedLocatorParameterIndex (constr.locatorIndex );
@@ -462,58 +459,68 @@ double SkinnedLocatorTriangleErrorFunctionT<T>::calculatePlaneJacobian(
462459template <typename T>
463460double SkinnedLocatorTriangleErrorFunctionT<T>::getGradient(
464461 const ModelParametersT<T>& modelParameters,
465- const SkeletonStateT<T>& /* state*/ ,
466- const MeshStateT<T>& /* meshState */ ,
462+ const SkeletonStateT<T>& /* state */ ,
463+ const MeshStateT<T>& meshState,
467464 Eigen::Ref<Eigen::VectorX<T>> gradient) {
468- updateMeshes (modelParameters );
465+ MT_CHECK_NOTNULL (meshState. restMesh_ );
469466
470- double error = 0.0 ;
467+ double error = 0 ;
471468
472- for (const auto & constraint : constraints_) {
473- if (constraintType_ == VertexConstraintType::Position) {
474- error += calculatePositionGradient (modelParameters, constraint, gradient);
475- } else if (constraintType_ == VertexConstraintType::Plane) {
476- error += calculatePlaneGradient (modelParameters, constraint, gradient);
469+ if (constraintType_ == VertexConstraintType::Position) {
470+ for (size_t iCons = 0 ; iCons < constraints_.size (); ++iCons) {
471+ error += calculatePositionGradient (modelParameters, meshState, constraints_[iCons], gradient);
472+ }
473+ } else {
474+ MT_CHECK (constraintType_ == VertexConstraintType::Plane);
475+ for (size_t iCons = 0 ; iCons < constraints_.size (); ++iCons) {
476+ error += calculatePlaneGradient (modelParameters, meshState, constraints_[iCons], gradient);
477477 }
478478 }
479479
480- return error * this ->weight_ ;
480+ return this ->weight_ * error ;
481481}
482482
483483template <typename T>
484484double SkinnedLocatorTriangleErrorFunctionT<T>::getJacobian(
485485 const ModelParametersT<T>& modelParameters,
486- const SkeletonStateT<T>& /* state*/ ,
487- const MeshStateT<T>& /* meshState */ ,
486+ const SkeletonStateT<T>& /* state */ ,
487+ const MeshStateT<T>& meshState,
488488 Eigen::Ref<Eigen::MatrixX<T>> jacobian,
489489 Eigen::Ref<Eigen::VectorX<T>> residual,
490490 int & usedRows) {
491491 MT_CHECK (
492492 jacobian.cols () == static_cast <Eigen::Index>(this ->parameterTransform_ .transform .cols ()));
493+ MT_CHECK (jacobian.rows () >= (Eigen::Index)(1 * constraints_.size ()));
494+ MT_CHECK (residual.rows () >= (Eigen::Index)(1 * constraints_.size ()));
493495
494- updateMeshes (modelParameters);
496+ MT_CHECK (
497+ meshState.restMesh_ , " MeshState must have rest mesh for SkinnedLocatorTriangleErrorFunction" );
495498
496- double error = 0.0 ;
497- usedRows = 0 ;
499+ double error = 0 ;
498500
499- for ( size_t iCons = 0 ; iCons < constraints_. size (); ++iCons ) {
500- if (constraintType_ == VertexConstraintType::Position ) {
501+ if (constraintType_ == VertexConstraintType::Position ) {
502+ for ( size_t i = 0 ; i < constraints_. size (); ++i ) {
501503 error += calculatePositionJacobian (
502504 modelParameters,
503- constraints_[iCons],
504- jacobian.block (usedRows, 0 , 3 , modelParameters.size ()),
505- residual.middleRows (usedRows, 3 ));
506- usedRows += 3 ;
507- } else if (constraintType_ == VertexConstraintType::Plane) {
508- T res;
505+ meshState,
506+ constraints_[i],
507+ jacobian.block (3 * i, 0 , 3 , modelParameters.size ()),
508+ residual.middleRows (3 * i, 3 ));
509+ }
510+ usedRows = 3 * constraints_.size ();
511+ } else {
512+ MT_CHECK (constraintType_ == VertexConstraintType::Plane);
513+ for (size_t i = 0 ; i < constraints_.size (); ++i) {
514+ T residualValue;
509515 error += calculatePlaneJacobian (
510516 modelParameters,
511- constraints_[iCons] ,
512- jacobian. block (usedRows, 0 , 1 , modelParameters. size ()) ,
513- res);
514- residual[usedRows] = res ;
515- usedRows += 1 ;
517+ meshState ,
518+ constraints_[i] ,
519+ jacobian. block (i, 0 , 1 , modelParameters. size ()),
520+ residualValue) ;
521+ residual (i) = residualValue ;
516522 }
523+ usedRows = constraints_.size ();
517524 }
518525
519526 return error;
@@ -529,42 +536,8 @@ size_t SkinnedLocatorTriangleErrorFunctionT<T>::getJacobianSize() const {
529536 return 0 ;
530537}
531538
532- template <typename T>
533- void SkinnedLocatorTriangleErrorFunctionT<T>::updateMeshes(
534- const ModelParametersT<T>& modelParameters) {
535- MT_PROFILE_FUNCTION ();
536-
537- bool doUpdateNormals = false ;
538- if (this ->character_ .blendShape ) {
539- const BlendWeightsT<T> blendWeights =
540- extractBlendWeights (this ->parameterTransform_ , modelParameters);
541- this ->character_ .blendShape ->computeShape (blendWeights, this ->restMesh_ ->vertices );
542- doUpdateNormals = true ;
543- }
544- if (this ->character_ .faceExpressionBlendShape ) {
545- if (!this ->character_ .blendShape ) {
546- // Set restMesh back to neutral, removing potential previous expressions.
547- // Note that if the character comes with (shape) blendShape, the previous if block already
548- // takes care of this step.
549- Eigen::Map<Eigen::VectorX<T>> outputVec (
550- &this ->restMesh_ ->vertices [0 ][0 ], this ->restMesh_ ->vertices .size () * 3 );
551- const Eigen::Map<Eigen::VectorX<T>> baseVec (
552- &this ->neutralMesh_ ->vertices [0 ][0 ], this ->neutralMesh_ ->vertices .size () * 3 );
553- outputVec = baseVec.template cast <T>();
554- }
555- const BlendWeightsT<T> faceExpressionBlendWeights =
556- extractFaceExpressionBlendWeights (this ->parameterTransform_ , modelParameters);
557- this ->character_ .faceExpressionBlendShape ->applyDeltas (
558- faceExpressionBlendWeights, this ->restMesh_ ->vertices );
559- doUpdateNormals = true ;
560- }
561- if (doUpdateNormals) {
562- this ->restMesh_ ->updateNormals ();
563- }
564- }
539+ } // namespace momentum
565540
566541// Explicit template instantiations
567- template class SkinnedLocatorTriangleErrorFunctionT <float >;
568- template class SkinnedLocatorTriangleErrorFunctionT <double >;
569-
570- } // namespace momentum
542+ template class momentum ::SkinnedLocatorTriangleErrorFunctionT<float >;
543+ template class momentum ::SkinnedLocatorTriangleErrorFunctionT<double >;
0 commit comments