@@ -42,11 +42,14 @@ void FAnimNode_JacobianIK::InitializeBoneReferences(const FBoneContainer& Requir
42
42
43
43
for (FIKConstraint& IKConstraint : IKJoint.Constraints )
44
44
{
45
- // EffectiveRootJointはすでにどれかのFIKJointで指定されておりInitializeされているはず
46
- if (!IKConstraint.EffectiveRootJoint .Initialize (RequiredBones))
45
+ if (IKConstraint.Type == EIKConstraintType::KEEP_POSITION)
47
46
{
48
- // TODO:UE_LOG
49
- return ;
47
+ // EffectiveRootJointはすでにどれかのFIKJointで指定されておりInitializeされているはず
48
+ if (!IKConstraint.EffectiveRootJoint .Initialize (RequiredBones))
49
+ {
50
+ // TODO:UE_LOG
51
+ return ;
52
+ }
50
53
}
51
54
}
52
55
}
@@ -103,42 +106,44 @@ void FAnimNode_JacobianIK::InitializeBoneReferences(const FBoneContainer& Requir
103
106
continue ;
104
107
}
105
108
106
- if (!IKConstraint.EffectiveRootJoint .IsValidToEvaluate (RequiredBones))
107
- {
108
- // TODO:UE_LOG
109
- return ;
110
- }
111
-
112
109
const FCompactPoseBoneIndex& ConstraintJointIndex = IKJoint.Joint .GetCompactPoseIndex (RequiredBones);
113
- const FCompactPoseBoneIndex& EffectiveRootIndex = IKConstraint.EffectiveRootJoint .GetCompactPoseIndex (RequiredBones);
114
- if (ConstraintJointIndex == EffectiveRootIndex)
110
+ TArray<FCompactPoseBoneIndex> EffectiveJointIndices;
111
+
112
+ if (IKConstraint.Type == EIKConstraintType::KEEP_POSITION)
115
113
{
116
- // TODO:UE_LOG
117
- return ;
118
- }
114
+ // PositionコンストレイントのときはIK計算に加えるジョイントをすべて洗い出す
119
115
120
- TArray<FCompactPoseBoneIndex> EffectiveJointIndices;
116
+ if (!IKConstraint.EffectiveRootJoint .IsValidToEvaluate (RequiredBones))
117
+ {
118
+ // TODO:UE_LOG
119
+ return ;
120
+ }
121
121
122
- FCompactPoseBoneIndex JointIndex = ConstraintJointIndex;
123
- IKJointWorkData WorkData = IKJointWorkDataMap[JointIndex.GetInt ()];
122
+ const FCompactPoseBoneIndex& EffectiveRootIndex = IKConstraint.EffectiveRootJoint .GetCompactPoseIndex (RequiredBones);
123
+ if (ConstraintJointIndex == EffectiveRootIndex)
124
+ {
125
+ // TODO:UE_LOG
126
+ return ;
127
+ }
124
128
125
- for (JointIndex = WorkData.ParentJointIndex , WorkData = IKJointWorkDataMap[JointIndex.GetInt ()]; // 自分はEffectiveJointIndicesには含めない
126
- JointIndex != EffectiveRootIndex && JointIndex != WorkData.ParentJointIndex ; // IKスケルトンのルートに達したときもループは抜ける
127
- JointIndex = WorkData.ParentJointIndex , WorkData = IKJointWorkDataMap[JointIndex.GetInt ()])
128
- {
129
- EffectiveJointIndices.Add (JointIndex);
130
- }
131
- EffectiveJointIndices.Add (JointIndex); // EffectiveRootIndexも含める
129
+ FCompactPoseBoneIndex JointIndex = ConstraintJointIndex;
130
+ IKJointWorkData WorkData = IKJointWorkDataMap[JointIndex.GetInt ()];
132
131
133
- EffectiveJointIndices.Sort (
134
- [](const FCompactPoseBoneIndex& A, const FCompactPoseBoneIndex& B)
135
- {
136
- return A.GetInt () < B.GetInt ();
137
- }
138
- );
132
+ for (JointIndex = WorkData.ParentJointIndex , WorkData = IKJointWorkDataMap[JointIndex.GetInt ()]; // 自分はEffectiveJointIndicesには含めない
133
+ JointIndex != EffectiveRootIndex && JointIndex != WorkData.ParentJointIndex ; // IKスケルトンのルートに達したときもループは抜ける
134
+ JointIndex = WorkData.ParentJointIndex , WorkData = IKJointWorkDataMap[JointIndex.GetInt ()])
135
+ {
136
+ EffectiveJointIndices.Add (JointIndex);
137
+ }
138
+ EffectiveJointIndices.Add (JointIndex); // EffectiveRootIndexも含める
139
+
140
+ EffectiveJointIndices.Sort (
141
+ [](const FCompactPoseBoneIndex& A, const FCompactPoseBoneIndex& B)
142
+ {
143
+ return A.GetInt () < B.GetInt ();
144
+ }
145
+ );
139
146
140
- if (IKConstraint.Type == EIKConstraintType::KEEP_POSITION)
141
- {
142
147
NumPositionConstraint++;
143
148
}
144
149
@@ -195,34 +200,41 @@ void FAnimNode_JacobianIK::EvaluateSkeletalControl_AnyThread(FComponentSpacePose
195
200
196
201
const FBoneContainer& BoneContainer = Output.Pose .GetPose ().GetBoneContainer ();
197
202
203
+ // ワークデータのTransformの初期化
204
+ for (TPair<int32, IKJointWorkData>& WorkData : IKJointWorkDataMap)
205
+ {
206
+ WorkData.Value .ComponentTransform = Output.Pose .GetComponentSpaceTransform (FCompactPoseBoneIndex (WorkData.Key ));
207
+ WorkData.Value .LocalTransform = WorkData.Value .ComponentTransform * Output.Pose .GetComponentSpaceTransform (FCompactPoseBoneIndex (WorkData.Value .ParentJointIndex )).Inverse ();
208
+ }
209
+
198
210
// TODO:各IKノードと共通化しよう
199
- // そもそもジョイントの長さ的にIKの解に到達しうるかの確認
200
- // コンストレイントごとに確認する
201
211
uint32 PositionConstraintIndex = 0 ;
202
212
for (const IKConstraintWorkData& Constraint : IKConstraintWorkDataArray)
203
213
{
204
- float IKJointTotalLength = 0 ; // このアニメーションノードに入力されるポーズにScaleがないなら、一度だけ計算してキャッシュしておけばよいが、今は毎回計算する
205
- // TODO:だがチェック処理にしては毎フレームの計算コスト高すぎかも
206
-
207
- // エフェクタのボーン以外の長さの合計
208
- for (int32 i = 0 ; i < Constraint.EffectiveJointIndices .Num () - 1 ; i++)
209
- {
210
- IKJointTotalLength += (Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [i + 1 ]).GetLocation () - Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [i]).GetLocation ()).Size ();
211
- }
212
- // エフェクタのボーンも合計する
213
- IKJointTotalLength += (Output.Pose .GetComponentSpaceTransform (Constraint.JointIndex ).GetLocation () - Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [Constraint.EffectiveJointIndices .Num () - 1 ]).GetLocation ()).Size ();
214
-
215
- float EffectorToIKRootLength = (Constraint.Position - Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [0 ]).GetLocation ()).Size ();
216
- if (IKJointTotalLength < EffectorToIKRootLength)
217
- {
218
- UE_LOG (LogAnimation, Warning, TEXT (" IK cannot reach effector target location. The total length of joints is not enough." ));
219
- return ;
220
- }
221
-
222
214
switch (Constraint.Type )
223
215
{
224
216
case EIKConstraintType::KEEP_POSITION:
225
217
{
218
+ // そもそもジョイントの長さ的にIKの解に到達しうるかの確認
219
+ // コンストレイントごとに確認する
220
+ float IKJointTotalLength = 0 ; // このアニメーションノードに入力されるポーズにScaleがないなら、一度だけ計算してキャッシュしておけばよいが、今は毎回計算する
221
+ // TODO:だがチェック処理にしては毎フレームの計算コスト高すぎかも
222
+
223
+ // エフェクタのボーン以外の長さの合計
224
+ for (int32 i = 0 ; i < Constraint.EffectiveJointIndices .Num () - 1 ; i++)
225
+ {
226
+ IKJointTotalLength += (Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [i + 1 ]).GetLocation () - Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [i]).GetLocation ()).Size ();
227
+ }
228
+ // エフェクタのボーンも合計する
229
+ IKJointTotalLength += (Output.Pose .GetComponentSpaceTransform (Constraint.JointIndex ).GetLocation () - Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [Constraint.EffectiveJointIndices .Num () - 1 ]).GetLocation ()).Size ();
230
+
231
+ float EffectorToIKRootLength = (Constraint.Position - Output.Pose .GetComponentSpaceTransform (Constraint.EffectiveJointIndices [0 ]).GetLocation ()).Size ();
232
+ if (IKJointTotalLength < EffectorToIKRootLength)
233
+ {
234
+ UE_LOG (LogAnimation, Warning, TEXT (" IK cannot reach effector target location. The total length of joints is not enough." ));
235
+ return ;
236
+ }
237
+
226
238
// ノードの入力されたエフェクタの位置から目標位置への差分ベクトル
227
239
const FVector& DeltaLocation = Constraint.Position - Output.Pose .GetComponentSpaceTransform (Constraint.JointIndex ).GetLocation ();
228
240
@@ -236,7 +248,13 @@ void FAnimNode_JacobianIK::EvaluateSkeletalControl_AnyThread(FComponentSpacePose
236
248
break ;
237
249
case EIKConstraintType::KEEP_ROTATION:
238
250
{
251
+ IKJointWorkData& WorkData = IKJointWorkDataMap.FindChecked (Constraint.JointIndex .GetInt ());
239
252
253
+ const FRotator& DeltaRotation = Constraint.Rotation - Output.Pose .GetComponentSpaceTransform (Constraint.JointIndex ).GetRotation ().Rotator ();
254
+ WorkData.LocalTransform .SetRotation (FQuat (Constraint.Rotation ));
255
+ WorkData.LocalTransform .NormalizeRotation ();
256
+
257
+ WorkData.ComponentTransform = WorkData.LocalTransform * Output.Pose .GetComponentSpaceTransform (FCompactPoseBoneIndex (WorkData.ParentJointIndex ));
240
258
}
241
259
break ;
242
260
case EIKConstraintType::INVALID:
@@ -247,13 +265,6 @@ void FAnimNode_JacobianIK::EvaluateSkeletalControl_AnyThread(FComponentSpacePose
247
265
}
248
266
}
249
267
250
- // ワークデータのTransformの初期化
251
- for (TPair<int32, IKJointWorkData>& WorkData : IKJointWorkDataMap)
252
- {
253
- WorkData.Value .ComponentTransform = Output.Pose .GetComponentSpaceTransform (FCompactPoseBoneIndex (WorkData.Key ));
254
- WorkData.Value .LocalTransform = WorkData.Value .ComponentTransform * Output.Pose .GetComponentSpaceTransform (FCompactPoseBoneIndex (WorkData.Value .ParentJointIndex )).Inverse ();
255
- }
256
-
257
268
// JacobianIKのメインアルゴリズム
258
269
// JacobianIKアルゴリズムについてはComputer Graphics Gems JP 2012の8章を参照
259
270
uint32 iterCount = 0 ;
@@ -271,9 +282,14 @@ void FAnimNode_JacobianIK::EvaluateSkeletalControl_AnyThread(FComponentSpacePose
271
282
IKJointWorkData& WorkData = WorkDataPair.Value ;
272
283
const FCompactPoseBoneIndex& JointIndex = FCompactPoseBoneIndex (WorkDataPair.Key );
273
284
274
- for (int32 ConstraintIndex = 0 ; ConstraintIndex < IKConstraintWorkDataArray.Num (); ConstraintIndex++)
285
+ PositionConstraintIndex = 0 ;
286
+ for (IKConstraintWorkData& Constraint : IKConstraintWorkDataArray)
275
287
{
276
- const IKConstraintWorkData& Constraint = IKConstraintWorkDataArray[ConstraintIndex];
288
+ if (Constraint.Type != EIKConstraintType::KEEP_POSITION)
289
+ {
290
+ continue ;
291
+ }
292
+
277
293
bool bEffectiveJoint = false ;
278
294
for (const FCompactPoseBoneIndex& EffectiveJoint : Constraint.EffectiveJointIndices )
279
295
{
@@ -339,21 +355,23 @@ void FAnimNode_JacobianIK::EvaluateSkeletalControl_AnyThread(FComponentSpacePose
339
355
for (int32 RotAxis = 0 ; RotAxis < ROTATION_AXIS_COUNT; ++RotAxis)
340
356
{
341
357
const FVector& JacobianRow = (ChildRestMatrix * LocalMatrix[RotAxis] * ParentRestMatrix).TransformPosition (FVector::ZeroVector);
342
- Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, ConstraintIndex * AXIS_COUNT + 0 , JacobianRow.X );
343
- Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, ConstraintIndex * AXIS_COUNT + 1 , JacobianRow.Y );
344
- Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, ConstraintIndex * AXIS_COUNT + 2 , JacobianRow.Z );
358
+ Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, PositionConstraintIndex * AXIS_COUNT + 0 , JacobianRow.X );
359
+ Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, PositionConstraintIndex * AXIS_COUNT + 1 , JacobianRow.Y );
360
+ Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, PositionConstraintIndex * AXIS_COUNT + 2 , JacobianRow.Z );
345
361
}
346
362
}
347
363
else
348
364
{
349
365
// このジョイントがこのコンストレイントに影響を及ぼすジョイントでないときはヤコビアンの要素は0
350
366
for (int32 RotAxis = 0 ; RotAxis < ROTATION_AXIS_COUNT; ++RotAxis)
351
367
{
352
- Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, ConstraintIndex * AXIS_COUNT + 0 , 0 .0f );
353
- Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, ConstraintIndex * AXIS_COUNT + 1 , 0 .0f );
354
- Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, ConstraintIndex * AXIS_COUNT + 2 , 0 .0f );
368
+ Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, PositionConstraintIndex * AXIS_COUNT + 0 , 0 .0f );
369
+ Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, PositionConstraintIndex * AXIS_COUNT + 1 , 0 .0f );
370
+ Jacobian.Set (RotationIndex * ROTATION_AXIS_COUNT + RotAxis, PositionConstraintIndex * AXIS_COUNT + 2 , 0 .0f );
355
371
}
356
372
}
373
+
374
+ PositionConstraintIndex++;
357
375
}
358
376
359
377
RotationIndex++;
@@ -374,9 +392,9 @@ void FAnimNode_JacobianIK::EvaluateSkeletalControl_AnyThread(FComponentSpacePose
374
392
375
393
JJti.ZeroClear (); // 最終的に全要素に値が入るので0クリアする必要はないがデバッグのしやすさのために0クリアする
376
394
#if 0
377
- float Determinant = AnySizeMatrix::InverseNxN(AXIS_COUNT * IKConstraintWorkDataArray.Num(), JJt, JJti);
395
+ float Determinant = AnySizeMatrix::InverseNxN(JJt, JJti);
378
396
#else
379
- float Determinant = AnySizeMatrix::InverseNxN (AXIS_COUNT * IKConstraintWorkDataArray. Num (), JJtPlusLambdaI, JJti);
397
+ float Determinant = AnySizeMatrix::InverseNxN (JJtPlusLambdaI, JJti);
380
398
#endif
381
399
// if (FMath::Abs(Determinant) < KINDA_SMALL_NUMBER)
382
400
if (FMath::Abs (Determinant) < SMALL_NUMBER)
0 commit comments