Files
2026-05-19 13:42:41 +07:00

1655 lines
48 KiB
C++

// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmConvertIKRig.h"
#include "VrmConvert.h"
#include "VrmUtil.h"
#include "VrmAssetListObject.h"
#include "VrmMetaObject.h"
#include "LoaderBPFunctionLibrary.h"
#include "VrmBPFunctionLibrary.h"
#include "Engine/SkeletalMesh.h"
#include "RenderingThread.h"
#include "Rendering/SkeletalMeshModel.h"
#include "Rendering/SkeletalMeshLODModel.h"
#include "Rendering/SkeletalMeshLODRenderData.h"
#include "Rendering/SkeletalMeshRenderData.h"
#include "Animation/MorphTarget.h"
#include "Animation/NodeMappingContainer.h"
#include "Animation/Skeleton.h"
#include "Components/SkeletalMeshComponent.h"
#include "UObject/UnrealType.h"
#if UE_VERSION_OLDER_THAN(5,4,0)
#include "Animation/Rig.h"
#endif
#include "PhysicsEngine/PhysicsAsset.h"
#include "PhysicsEngine/PhysicsConstraintTemplate.h"
#include "VrmRigHeader.h"
#if WITH_EDITOR
#include "IPersonaToolkit.h"
#include "PersonaModule.h"
#include "Modules/ModuleManager.h"
#include "Animation/DebugSkelMeshComponent.h"
#endif
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/mesh.h>
#include <assimp/postprocess.h>
#include <assimp/GltfMaterial.h>
#include <assimp/vrm/vrmmeta.h>
//#include "Engine/.h"
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(5,4,0)
#else
#define VRM4U_USE_AUTOALIGN 1
#endif
#endif
#ifndef VRM4U_USE_AUTOALIGN
#define VRM4U_USE_AUTOALIGN 0
#endif
#define VRM4U_USE_EDITOR_RIG WITH_EDITOR
namespace {
#if VRM4U_USE_EDITOR_RIG && WITH_EDITOR
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
static void LocalSolverSetup(UIKRigController* rigcon, UVrmAssetListObject *assetList, int table_no=0xFFFF) {
if (rigcon == nullptr) return;
int sol_index = 0;
#if UE_VERSION_OLDER_THAN(5,2,0)
auto* sol = rigcon->GetSolver(sol_index);
#else
auto* sol = rigcon->GetSolverAtIndex(sol_index);
#endif
if (sol == nullptr) {
#if UE_VERSION_OLDER_THAN(5,2,0)
sol_index = rigcon->AddSolver(UIKRigPBIKSolver::StaticClass());
sol = rigcon->GetSolver(sol_index);
#elif UE_VERSION_OLDER_THAN(5,6,0)
sol_index = rigcon->AddSolver(UIKRigFBIKSolver::StaticClass());
sol = rigcon->GetSolverAtIndex(sol_index);
#else
sol_index = rigcon->AddSolver(FIKRigFullBodyIKSolver::StaticStruct());
sol = rigcon->GetSolverAtIndex(sol_index);
if (sol) {
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto s = sc->GetSolverSettings();
s.RootBehavior = EPBIKRootBehavior::PinToInput;
s.GlobalPullChainAlpha = 0;
sol->SetSolverSettings(&s);
}
}
#endif
}
if (sol == nullptr) return;
#if UE_VERSION_OLDER_THAN(5,4,0)
sol->SetEnabled(false);
#else
sol->SetEnabled(true);
#endif
// hip
for (auto& modelName : assetList->VrmMetaObject->humanoidBoneTable) {
if (modelName.Key == "" || modelName.Value == "") {
continue;
}
if (modelName.Key == TEXT("hips")) {
#if UE_VERSION_OLDER_THAN(5,6,0)
sol->SetRootBone(*modelName.Value);
#else
sol->SetStartBone(*modelName.Value);
#endif
}
}
{
TArray<FString> a = {
TEXT("leftHand"),
TEXT("rightHand"),
TEXT("leftToes"),
TEXT("rightToes"),
};
if (table_no == 0){
// not change
}else if (table_no == 1){
TArray < FString > tmp = {
TEXT("leftHand"),
TEXT("rightHand"),
TEXT("leftFoot"),
TEXT("rightFoot"),
};
a = tmp;
}
if (VRMConverter::Options::Get().IsBVHModel()) {
{
TArray < FString > tmp = {
TEXT("l_hand"),
TEXT("r_hand"),
TEXT("l_foot"),
TEXT("r_foot"),
};
a = tmp;
}
if (table_no == 1) {
TArray < FString > tmp = {
TEXT("l_hand"),
TEXT("r_hand"),
TEXT("l_toes"),
TEXT("r_toes"),
};
a = tmp;
}
}
for (int i = 0; i < a.Num(); ++i) {
for (auto& t : assetList->VrmMetaObject->humanoidBoneTable) {
if (t.Key.ToLower() == a[i].ToLower()) {
#if UE_VERSION_OLDER_THAN(5,1,0)
#elif UE_VERSION_OLDER_THAN(5,2,0)
auto* goal = rigcon->AddNewGoal(*(a[i] + TEXT("_Goal")), *t.Value);
if (goal) {
rigcon->ConnectGoalToSolver(*goal, sol_index);
// arm chain
if (i == 0 || i == 1) {
UIKRig_FBIKEffector* e = Cast<UIKRig_FBIKEffector>(sol->GetGoalSettings(goal->GoalName));
if (e) {
e->PullChainAlpha = 0.f;
}
}
const auto &chain = rigcon->GetRetargetChains();
for (auto& c : chain) {
if (c.EndBone.BoneName == *t.Value) {
rigcon->SetRetargetChainGoal(c.ChainName, goal->GoalName);
}
}
}
#elif UE_VERSION_OLDER_THAN(5,6,0)
auto goal = rigcon->AddNewGoal(*(a[i] + TEXT("_Goal")), *t.Value);
if (goal != NAME_None) {
rigcon->ConnectGoalToSolver(goal, sol_index);
// arm chain
if (i == 0 || i == 1) {
UIKRig_FBIKEffector* e = Cast<UIKRig_FBIKEffector>(sol->GetGoalSettings(goal));
if (e) {
e->PullChainAlpha = 0.f;
}
}
const auto& chain = rigcon->GetRetargetChains();
for (auto& c : chain) {
if (c.EndBone.BoneName == *t.Value) {
rigcon->SetRetargetChainGoal(c.ChainName, goal);
}
}
}
#else
auto goal = rigcon->AddNewGoal(*(a[i] + TEXT("_Goal")), *t.Value);
if (goal != NAME_None) {
rigcon->ConnectGoalToSolver(goal, sol_index);
// arm chain
if (i == 0 || i == 1) {
auto *sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetGoalSettings(goal);
settings.PullChainAlpha = 0.f;
sc->SetGoalSettings(goal, settings);
}
}
const auto& chain = rigcon->GetRetargetChains();
for (auto& c : chain) {
if (c.EndBone.BoneName == *t.Value) {
rigcon->SetRetargetChainGoal(c.ChainName, goal);
}
}
}
#endif
}
}
}
// BVH
if (VRMConverter::Options::Get().IsBVHModel()) {
#if UE_VERSION_OLDER_THAN(5,2,0)
#elif UE_VERSION_OLDER_THAN(5,6,0)
for (int i = 0; i < a.Num(); ++i) {
USkeletalMesh* sk = assetList->SkeletalMesh;
//auto boneList = VRMGetRefSkeleton(sk).GetRefBonePose();
auto ind = VRMGetRefSkeleton(sk).FindBoneIndex(*a[i]);
if (ind < 0) continue;
auto goal = rigcon->AddNewGoal(*(a[i] + TEXT("_Goal")), *a[i]);
if (goal != NAME_None) {
rigcon->ConnectGoalToSolver(goal, sol_index);
// arm chain
if (i == 0 || i == 1) {
UIKRig_FBIKEffector* e = Cast<UIKRig_FBIKEffector>(sol->GetGoalSettings(goal));
if (e) {
e->PullChainAlpha = 0.f;
}
}
const auto& chain = rigcon->GetRetargetChains();
for (auto& c : chain) {
if (c.EndBone.BoneName == *a[i]) {
rigcon->SetRetargetChainGoal(c.ChainName, goal);
}
}
}
}
#else
for (int i = 0; i < a.Num(); ++i) {
USkeletalMesh* sk = assetList->SkeletalMesh;
//auto boneList = VRMGetRefSkeleton(sk).GetRefBonePose();
auto ind = VRMGetRefSkeleton(sk).FindBoneIndex(*a[i]);
if (ind < 0) continue;
auto goal = rigcon->AddNewGoal(*(a[i] + TEXT("_Goal")), *a[i]);
if (goal != NAME_None) {
rigcon->ConnectGoalToSolver(goal, sol_index);
// arm chain
if (i == 0 || i == 1) {
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetGoalSettings(goal);
settings.PullChainAlpha = 0.f;
sc->SetGoalSettings(goal, settings);
}
//UIKRig_FBIKEffector* e = Cast<UIKRig_FBIKEffector>(sol->GetGoalSettings(goal));
//if (e) {
// e->PullChainAlpha = 0.f;
//}
}
const auto& chain = rigcon->GetRetargetChains();
for (auto& c : chain) {
if (c.EndBone.BoneName == *a[i]) {
rigcon->SetRetargetChainGoal(c.ChainName, goal);
}
}
}
}
#endif
}// bvh
}
{
TArray<FString> a = {
TEXT("leftShoulder"),
TEXT("rightShoulder"),
TEXT("leftLowerArm"),
TEXT("rightLowerArm"),
TEXT("leftUpperLeg"),
TEXT("rightUpperLeg"),
TEXT("leftLowerLeg"),
TEXT("rightLowerLeg"),
TEXT("leftFoot"),
TEXT("rightFoot"),
TEXT("hips"),
TEXT("spine"),
TEXT("chest"),
TEXT("upperChest"),
};
for (int i = 0; i < a.Num(); ++i) {
for (auto& t : assetList->VrmMetaObject->humanoidBoneTable) {
if (t.Key.ToLower() == a[i].ToLower()) {
if (t.Value == "") continue;
#if UE_VERSION_OLDER_THAN(5,2,0)
#else
typedef UIKRig_FBIKBoneSettings UIKRig_PBIKBoneSettings;
#endif
// shoulder
if (i == 0 || i == 1) {
#if UE_VERSION_OLDER_THAN(5,6,0)
sol->AddBoneSetting(*t.Value);
UIKRig_PBIKBoneSettings* s = Cast<UIKRig_PBIKBoneSettings>(sol->GetBoneSetting(*t.Value));
if (s == nullptr) continue;
s->RotationStiffness = 0.95f;
#else
sol->AddSettingsToBone(*t.Value);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(*t.Value);
settings.RotationStiffness = 0.95f;
sc->SetBoneSettings(*t.Value, settings);
}
#endif
}
// arm
if (i == 2 || i == 3) {
#if UE_VERSION_OLDER_THAN(5,6,0)
sol->AddBoneSetting(*t.Value);
UIKRig_PBIKBoneSettings* s = Cast<UIKRig_PBIKBoneSettings>(sol->GetBoneSetting(*t.Value));
if (s == nullptr) continue;
s->bUsePreferredAngles = true;
if (i == 2) {
s->PreferredAngles.Set(0, 0, 90);
}
else {
s->PreferredAngles.Set(0, 0, -90);
}
#else
sol->AddSettingsToBone(*t.Value);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(*t.Value);
settings.bUsePreferredAngles = true;
if (i == 2) {
settings.PreferredAngles.Set(0, 0, 90);
} else {
settings.PreferredAngles.Set(0, 0, -90);
}
sc->SetBoneSettings(*t.Value, settings);
}
#endif
}
// only lower leg
if (i == 6 || i == 7) {
#if UE_VERSION_OLDER_THAN(5,6,0)
sol->AddBoneSetting(*t.Value);
UIKRig_PBIKBoneSettings* s = Cast<UIKRig_PBIKBoneSettings>(sol->GetBoneSetting(*t.Value));
if (s == nullptr) continue;
//s->bUsePreferredAngles = true;
if (i == 4 || i == 5) {
//s->PreferredAngles.Set(-180, 0, 0);
}
else {
s->PreferredAngles.Set(180, 0, 0);
s->Y = EPBIKLimitType::Locked;
s->Z = EPBIKLimitType::Locked;
}
#else
sol->AddSettingsToBone(*t.Value);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(*t.Value);
//settings.bUsePreferredAngles = true;
if (i == 4 || i == 5) {
settings.PreferredAngles.Set(-180, 0, 0);
}
else {
settings.PreferredAngles.Set(180, 0, 0);
settings.Y = EPBIKLimitType::Locked;
settings.Z = EPBIKLimitType::Locked;
}
sc->SetBoneSettings(*t.Value, settings);
}
#endif
}
// foot
if (i == 8 || i == 9) {
#if UE_VERSION_OLDER_THAN(5,6,0)
sol->AddBoneSetting(*t.Value);
UIKRig_PBIKBoneSettings* s = Cast<UIKRig_PBIKBoneSettings>(sol->GetBoneSetting(*t.Value));
if (s == nullptr) continue;
s->RotationStiffness = 0.85f;
#else
sol->AddSettingsToBone(*t.Value);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(*t.Value);
settings.RotationStiffness = 0.85f;
sc->SetBoneSettings(*t.Value, settings);
}
#endif
}
// spine
if (i >= 10) {
#if UE_VERSION_OLDER_THAN(5,6,0)
sol->AddBoneSetting(*t.Value);
UIKRig_PBIKBoneSettings* s = Cast<UIKRig_PBIKBoneSettings>(sol->GetBoneSetting(*t.Value));
if (s == nullptr) continue;
if (i == 10) {
s->RotationStiffness = 1.f;
}
else {
s->RotationStiffness = 0.9f;
}
#else
sol->AddSettingsToBone(*t.Value);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(*t.Value);
if (i == 10) {
settings.RotationStiffness = 1.f;
}
else {
settings.RotationStiffness = 0.9f;
}
sc->SetBoneSettings(*t.Value, settings);
}
#endif
}
}
}
}
}
}
#endif
#endif
}
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
#if WITH_EDITOR
#else
class UIKRetargeterController {
public:
static void setSourceRig(UIKRetargeter* retargeter, UIKRigDefinition* rig){
retargeter->SourceIKRigAsset = rig;
}
};
#endif
#endif
#if UE_VERSION_OLDER_THAN(5,1,0)
#else
class SimpleRetargeterController {
//friend class UIKRetargeter;
UIKRetargeter *Retargeter = nullptr;
public:
SimpleRetargeterController(UIKRetargeter* rig) {
Retargeter = rig;
}
FName CreateRetargetPose(const FName& NewPoseName, const ERetargetSourceOrTarget SourceOrTarget) const {
#if UE_VERSION_OLDER_THAN(5,2,0)
return NAME_None;
#else
#if VRM4U_USE_EDITOR_RIG
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
return c->CreateRetargetPose(NewPoseName, SourceOrTarget);
#else
return NewPoseName;
#endif
#endif // 5.2
}
FIKRetargetPose* GetRetargetPosesByName(const ERetargetSourceOrTarget SourceOrTarget, FName poseName) const
{
#if VRM4U_USE_EDITOR_RIG
//FScopeLock Lock(&ControllerLock);
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
return &c->GetRetargetPoses(SourceOrTarget)[poseName];
#else
//return SourceOrTarget == ERetargetSourceOrTarget::Source ? Retargeter->SourceRetargetPoses : Retargeter->TargetRetargetPoses;
return const_cast<FIKRetargetPose*>(Retargeter->GetRetargetPoseByName(SourceOrTarget, poseName));
#endif
//return SourceOrTarget == ERetargetSourceOrTarget::Source ? GetAsset()->SourceRetargetPoses : GetAsset()->TargetRetargetPoses;
}
#if UE_VERSION_OLDER_THAN(5,2,0)
void SetIKRig(UIKRigDefinition* IKRig) const {
}
#else
void SetIKRig(const ERetargetSourceOrTarget SourceOrTarget, UIKRigDefinition* IKRig) const {
#if VRM4U_USE_EDITOR_RIG
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
c->SetIKRig(SourceOrTarget, IKRig);
#else
#if UE_VERSION_OLDER_THAN(5,6,0)
UIKRetargeterController::setSourceRig(Retargeter, IKRig);
#else
// no rig
#endif
#endif
}
#endif
void AutoAlignAllBones(const ERetargetSourceOrTarget SourceOrTarget) const {
#if !WITH_EDITOR || UE_VERSION_OLDER_THAN(5,4,0)
#else
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
c->AutoAlignAllBones(SourceOrTarget);
#endif
}
void SetCurrentRetargetPose(FName NewCurrentPose, const ERetargetSourceOrTarget SourceOrTarget) const {
#if !WITH_EDITOR || UE_VERSION_OLDER_THAN(5,4,0)
#else
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
c->SetCurrentRetargetPose(NewCurrentPose, SourceOrTarget);
#endif
}
TMap<FName, FIKRetargetPose>& GetRetargetPoses(const ERetargetSourceOrTarget SourceOrTarget) const {
#if !WITH_EDITOR || UE_VERSION_OLDER_THAN(5,4,0)
static TMap<FName, FIKRetargetPose> a;
return a;
#else
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
return c->GetRetargetPoses(SourceOrTarget);
#endif
};
void SetRotationOffsetForRetargetPoseBone(
const FName& BoneName,
const FQuat& RotationOffset,
const ERetargetSourceOrTarget SourceOrTarget) const {
#if !WITH_EDITOR || UE_VERSION_OLDER_THAN(5,4,0)
return;
#else
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
return c->SetRotationOffsetForRetargetPoseBone(BoneName, RotationOffset, SourceOrTarget);
#endif
}
void SetChainSetting() {
#if UE_VERSION_OLDER_THAN(5,2,0)
#else
#if VRM4U_USE_EDITOR_RIG
UIKRetargeterController* c = UIKRetargeterController::GetController(Retargeter);
PRAGMA_DISABLE_DEPRECATION_WARNINGS
{
auto cs = c->GetRetargetChainSettings(TEXT("Root"));
cs.FK.TranslationMode = ERetargetTranslationMode::GloballyScaled;
c->SetRetargetChainSettings(TEXT("Root"), cs);
}
{
TArray<FString> table = {
TEXT("FootRootIK"),
TEXT("LeftFootIK"),
TEXT("RightFootIK"),
TEXT("HandRootIK"),
TEXT("LeftHandIK"),
TEXT("RightHandIK"),
};
for (auto s : table) {
auto cs = c->GetRetargetChainSettings(*s);
cs.FK.TranslationMode = ERetargetTranslationMode::GloballyScaled;
c->SetRetargetChainSettings(*s, cs);
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/*
{
TArray<FString> table = {
TEXT("LeftLeg"),
TEXT("RightLeg"),
TEXT("LeftArm"),
TEXT("RightArm"),
};
for (auto s : table) {
auto cs = c->GetRetargetChainSettings(*s);
cs.FK.PoleVectorMatching = 1.f;
c->SetRetargetChainSettings(*s, cs);
}
}
{
TArray<FString> table = {
TEXT("LeftArm"),
TEXT("RightArm"),
};
for (auto s : table) {
auto cs = c->GetRetargetChainSettings(*s);
cs.IK.bAffectedByIKWarping = false;
c->SetRetargetChainSettings(*s, cs);
}
}
*/
#else
auto r = Retargeter->GetChainMapByName(TEXT("Root"));
r->Settings.FK.TranslationMode = ERetargetTranslationMode::GloballyScaled;
#endif // rig
#endif // 5.2
}
};
#endif // 5.0
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
class SimpleRigController {
public:
UIKRigDefinition* RigDefinition = nullptr;
SimpleRigController(UIKRigDefinition* rig) {
RigDefinition = rig;
}
#if VRM4U_USE_EDITOR_RIG
UIKRigController* LocalGetController(UIKRigDefinition* rig) {
#if UE_VERSION_OLDER_THAN(5,2,0)
return UIKRigController::GetIKRigController(rig);
#else
return UIKRigController::GetController(rig);
#endif
}
UIKRigController* LocalGetController(UIKRigDefinition* rig) const {
#if UE_VERSION_OLDER_THAN(5,2,0)
return UIKRigController::GetIKRigController(rig);
#else
return UIKRigController::GetController(rig);
#endif
}
#endif
void SetSkeletalMesh(USkeletalMesh* sk) {
#if UE_VERSION_OLDER_THAN(5,2,0)
#if VRM4U_USE_EDITOR_RIG
auto * r = LocalGetController(RigDefinition);
r->SetSkeletalMesh(sk);
#endif
#else
#if VRM4U_USE_EDITOR_RIG
auto *r = LocalGetController(RigDefinition);
r->SetSkeletalMesh(sk);
#else
RigDefinition->PreviewSkeletalMesh = sk;
const_cast<FIKRigSkeleton*>(&RigDefinition->GetSkeleton())->SetInputSkeleton(sk, RigDefinition->GetSkeleton().ExcludedBones);
ResetInitialGoalTransforms();
#endif
#endif
}
bool SetRetargetRoot(const FName RootBoneName) const
{
#if UE_VERSION_OLDER_THAN(5,2,0)
return true;
#else
#if VRM4U_USE_EDITOR_RIG
auto* r = LocalGetController(RigDefinition);
return r->SetRetargetRoot(RootBoneName);
#else
FName NewRootBone = RootBoneName;
if (RootBoneName != NAME_None && RigDefinition->GetSkeleton().GetBoneIndexFromName(RootBoneName) == INDEX_NONE)
{
NewRootBone = NAME_None;
}
//FScopedTransaction Transaction(LOCTEXT("SetRetargetRootBone_Label", "Set Retarget Root Bone"));
RigDefinition->Modify();
#if UE_VERSION_OLDER_THAN(5,6,0)
*const_cast<FName*>(&RigDefinition->GetRetargetRoot()) = NewRootBone;
#else
#endif
//BroadcastNeedsReinitialized();
return true;
#endif
#endif
}
FName VRMAddRetargetChain(FName name, FName begin, FName end) {
#if UE_VERSION_OLDER_THAN(5,2,0)
return NAME_None;
#else
FBoneChain c;
FBoneReference r1, r2;
r1.BoneName = begin;
r2.BoneName = end;
auto k = RigDefinition->GetPreviewMesh()->GetSkeleton();
r1.Initialize(k);
r2.Initialize(k);
c.ChainName = name;
c.StartBone = r1;
c.EndBone = r2;
#if VRM4U_USE_EDITOR_RIG
auto* r = LocalGetController(RigDefinition);
#if UE_VERSION_OLDER_THAN(5,4,0)
r->AddRetargetChain(c);
#else
r->AddRetargetChain(name, begin, end, NAME_None);
#endif
return NAME_None;
#else
if (c.StartBone.BoneName != NAME_None && RigDefinition->GetSkeleton().GetBoneIndexFromName(c.StartBone.BoneName) == INDEX_NONE)
{
//UE_LOG(LogIKRigEditor, Warning, TEXT("Could not create retarget chain. Start Bone does not exist, %s."), *c.StartBone.BoneName.ToString());
return NAME_None; // bone doesn't exist
}
if (c.EndBone.BoneName != NAME_None && RigDefinition->GetSkeleton().GetBoneIndexFromName(c.EndBone.BoneName) == INDEX_NONE)
{
//UE_LOG(LogIKRigEditor, Warning, TEXT("Could not create retarget chain. End Bone does not exist, %s."), *c.EndBone.BoneName.ToString());
return NAME_None; // bone doesn't exist
}
FBoneChain ChainToAdd = c;
// if no name specified, use a default
if (ChainToAdd.ChainName == NAME_None)
{
const FName DefaultChainName = FName("DefaultChainName");
ChainToAdd.ChainName = DefaultChainName;
}
ChainToAdd.ChainName = GetUniqueRetargetChainName(c.ChainName);
//FScopedTransaction Transaction(LOCTEXT("AddRetargetChain_Label", "Add Retarget Chain"));
RigDefinition->Modify();
const int32 NewChainIndex = const_cast<TArray<FBoneChain>*>(&RigDefinition->GetRetargetChains())->Emplace(ChainToAdd);
//RetargetChainAdded.Broadcast(RigDefinition);
//BroadcastNeedsReinitialized();
return NAME_None;// RigDefinition->RetargetDefinition.BoneChains[NewChainIndex].ChainName;
#endif
#endif
}
void LocalSolverSetup(UVrmAssetListObject *vrmAssetList, int table_no=0xFFFF) {
#if VRM4U_USE_EDITOR_RIG
auto* r = LocalGetController(RigDefinition);
::LocalSolverSetup(r, vrmAssetList, table_no);
#else
#endif
}
FTransform GetRefPoseTransformOfBone(const FName BoneName) const
{
#if UE_VERSION_OLDER_THAN(5,2,0)
return FTransform::Identity;
#else
const int32 BoneIndex = RigDefinition->GetSkeleton().GetBoneIndexFromName(BoneName);
if (BoneIndex == INDEX_NONE)
{
//UE_LOG(LogIKRigEditor, Warning, TEXT("Tried to get the ref pose of bone that is not loaded into this rig."));
return FTransform::Identity;
}
return RigDefinition->GetSkeleton().RefPoseGlobal[BoneIndex];
#endif
}
void ResetInitialGoalTransforms() const
{
for (UIKRigEffectorGoal* Goal : RigDefinition->GetGoalArray())
{
// record the current delta rotation
const FQuat DeltaRotation = Goal->CurrentTransform.GetRotation() * Goal->InitialTransform.GetRotation().Inverse();
// update the initial transform based on the new ref pose
const FTransform InitialTransform = GetRefPoseTransformOfBone(Goal->BoneName);
Goal->InitialTransform = InitialTransform;
// restore the current transform
Goal->CurrentTransform.SetRotation(Goal->InitialTransform.GetRotation() * DeltaRotation);
}
}
FName GetUniqueRetargetChainName(const FName NameToMakeUnique) const
{
auto IsNameBeingUsed = [this](const FName NameToTry)->bool
{
for (const FBoneChain& Chain : RigDefinition->GetRetargetChains())
{
if (Chain.ChainName == NameToTry)
{
return true;
}
}
return false;
};
// check if name is already unique
if (!IsNameBeingUsed(NameToMakeUnique))
{
return NameToMakeUnique;
}
// keep concatenating an incremented integer suffix until name is unique
int32 Number = NameToMakeUnique.GetNumber() + 1;
while (IsNameBeingUsed(FName(NameToMakeUnique, Number)))
{
Number++;
}
return FName(NameToMakeUnique, Number);
}
};
#endif // 5.0
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(5,6,0)
#else
static UIKRigDefinition* GenerateMannequinIK(UVrmAssetListObject* vrmAssetList, FString path_forSK, FString Footer) {
UObject* u = nullptr;
{
FSoftObjectPath r2(path_forSK);
u = r2.TryLoad();
if (u == nullptr) return nullptr;
}
USkeletalMesh* sk = nullptr;
if (u) {
auto r2 = Cast<USkeletalMesh>(u);
if (r2) {
sk = r2;
}
}
if (sk == nullptr) return nullptr;
FString name = FString(TEXT("IK_")) + TEXT("VRM4U_") + Footer;
UIKRigDefinition* rig_ik = nullptr;
{
// 生成済なら返す
FSoftObjectPath r2(name);
rig_ik = Cast <UIKRigDefinition>(r2.TryLoad());
if (rig_ik) return rig_ik;
}
rig_ik = VRM4U_NewObject<UIKRigDefinition>(vrmAssetList->Package, *name, RF_Public | RF_Standalone);
{
SimpleRigController rigcon = SimpleRigController(rig_ik);
rigcon.SetSkeletalMesh(sk);
// root
{
auto s = VRMGetRefSkeleton(sk).GetBoneName(0);
rigcon.VRMAddRetargetChain(TEXT("Root"), s, s);
}
struct TT {
FString chain;
FString s1;
FString s2;
uint32_t mask = 0xFFFF;
};
TArray<FString> AddedChainList;
TArray<TT> table = {
{TEXT("Spine"), TEXT("spine_01"), TEXT("spine_05"),},
{TEXT("Neck"), TEXT("neck_01"), TEXT("neck_02"),},
{TEXT("Head"), TEXT("head"), TEXT("head"),},
{TEXT("LeftClavicle"), TEXT("clavicle_l"), TEXT("clavicle_l"),},
{TEXT("LeftArm"), TEXT("upperarm_l"), TEXT("hand_l"),},
{TEXT("RightClavicle"), TEXT("clavicle_r"), TEXT("clavicle_r"),},
{TEXT("RightArm"), TEXT("upperarm_r"), TEXT("hand_r"),},
{TEXT("LeftIndexMetacarpal"), TEXT("index_metacarpal_l"), TEXT("index_metacarpal_l"),},
{TEXT("LeftIndex"), TEXT("index_01_l"), TEXT("index_03_l"),},
{TEXT("LeftMiddleMetacarpal"), TEXT("middle_metacarpal_l"), TEXT("middle_metacarpal_l"),},
{TEXT("LeftMiddle"), TEXT("middle_01_l"), TEXT("middle_03_l"),},
{TEXT("LeftThumb"), TEXT("thumb_01_l"), TEXT("thumb_03_l"),},
{TEXT("LeftPinkyMetacarpal"), TEXT("pinky_metacarpal_l"), TEXT("pinky_metacarpal_l"),},
{TEXT("LeftPinky"), TEXT("pinky_01_l"), TEXT("pinky_03_l"),},
{TEXT("LeftRingMetacarpal"), TEXT("ring_metacarpal_l"), TEXT("ring_metacarpal_l"),},
{TEXT("LeftRing"), TEXT("ring_01_l"), TEXT("ring_03_l"),},
{TEXT("RightIndexMetacarpal"), TEXT("index_metacarpal_r"), TEXT("index_metacarpal_r"),},
{TEXT("RightIndex"), TEXT("index_01_r"), TEXT("index_03_r"),},
{TEXT("RightMiddleMetacarpal"), TEXT("middle_metacarpal_r"), TEXT("middle_metacarpal_r"),},
{TEXT("RightMiddle"), TEXT("middle_01_r"), TEXT("middle_03_r"),},
{TEXT("RightThumb"), TEXT("thumb_01_r"), TEXT("thumb_03_r"),},
{TEXT("RightPinkyMetacarpal"), TEXT("pinky_metacarpal_r"), TEXT("pinky_metacarpal_r"),},
{TEXT("RightPinky"), TEXT("pinky_01_r"), TEXT("pinky_03_r"),},
{TEXT("RightRingMetacarpal"), TEXT("ring_metacarpal_r"), TEXT("ring_metacarpal_r"),},
{TEXT("RightRing"), TEXT("ring_01_r"), TEXT("ring_03_r"),},
{TEXT("LeftLeg"), TEXT("thigh_l"), TEXT("ball_l"),},
{TEXT("RightLeg"), TEXT("thigh_r"), TEXT("ball_r"),},
};
for (auto& t : table) {
rigcon.VRMAddRetargetChain(*t.chain, *t.s1, *t.s2);
}
}
{
auto* rigcon = UIKRigController::GetController(rig_ik);
int sol_index = 0;
sol_index = rigcon->AddSolver(FIKRigFullBodyIKSolver::StaticStruct());
auto *sol = rigcon->GetSolverAtIndex(sol_index);
{
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
auto s = sc->GetSolverSettings();
s.RootBehavior = EPBIKRootBehavior::Free;
s.GlobalPullChainAlpha = 0;
sol->SetSolverSettings(&s);
}
sol->SetEnabled(true);
{
FName boneName = TEXT("pelvis");
sol->SetStartBone(boneName);
rigcon->SetRetargetRoot(boneName);
}
{
FName boneList[] = {
TEXT("pelvis"),
TEXT("clavicle_l"),
TEXT("clavicle_r"),
};
for (auto& boneName : boneList) {
sol->AddSettingsToBone(boneName);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(boneName);
settings.RotationStiffness = 0.95f;
sc->SetBoneSettings(boneName, settings);
}
}
}
{
FName boneList[] = {
TEXT("lowerarm_r"),
TEXT("lowerarm_l"),
TEXT("calf_r"),
TEXT("calf_l"),
};
for (auto& boneName : boneList) {
sol->AddSettingsToBone(boneName);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(boneName);
settings.X = EPBIKLimitType::Locked;
settings.Y = EPBIKLimitType::Locked;
settings.RotationStiffness = 0.5f;
settings.bUsePreferredAngles = true;
settings.PreferredAngles.Set(0, 0, 45);
sc->SetBoneSettings(boneName, settings);
}
}
}
{
FName boneList[] = {
TEXT("foot_r"),
TEXT("foot_l"),
};
for (auto& boneName : boneList) {
sol->AddSettingsToBone(boneName);
auto* sc = Cast<UIKRigFBIKController>(rigcon->GetSolverController(sol_index));
if (sc) {
auto settings = sc->GetBoneSettings(boneName);
settings.X = EPBIKLimitType::Locked;
settings.Y = EPBIKLimitType::Locked;
settings.RotationStiffness = 0.5f;
settings.bUsePreferredAngles = true;
settings.PreferredAngles.Set(0, 0, 45);
sc->SetBoneSettings(boneName, settings);
}
}
}
{
auto goal = rigcon->AddNewGoal(TEXT("RightHandIK"), TEXT("hand_r"));
rigcon->SetRetargetChainGoal(TEXT("RightArm"), goal);
rigcon->ConnectGoalToSolver(goal, sol_index);
}
{
auto goal = rigcon->AddNewGoal(TEXT("LeftHandIK"), TEXT("hand_l"));
rigcon->SetRetargetChainGoal(TEXT("LeftArm"), goal);
rigcon->ConnectGoalToSolver(goal, sol_index);
}
{
auto goal = rigcon->AddNewGoal(TEXT("RightFootIK"), TEXT("foot_r"));
rigcon->SetRetargetChainGoal(TEXT("RightLeg"), goal);
rigcon->ConnectGoalToSolver(goal, sol_index);
}
{
auto goal = rigcon->AddNewGoal(TEXT("LeftFootIK"), TEXT("foot_l"));
rigcon->SetRetargetChainGoal(TEXT("LeftLeg"), goal);
rigcon->ConnectGoalToSolver(goal, sol_index);
}
}
return rig_ik;
}
#endif
#endif
bool VRMConverter::ConvertIKRig(UVrmAssetListObject *vrmAssetList) {
if (VRMConverter::Options::Get().IsDebugOneBone()) {
return true;
}
if (vrmAssetList->SkeletalMesh == nullptr) {
return false;
}
bool bPlay = false;
{
bool b1, b2, b3;
b1 = b2 = b3 = false;
UVrmBPFunctionLibrary::VRMGetPlayMode(b1, b2, b3);
bPlay = b1;
}
if (bPlay) {
}
if (vrmAssetList && VRMConverter::Options::Get().IsGenerateRigIK()) {
// ikrig
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
const VRM::VRMMetadata* meta = reinterpret_cast<VRM::VRMMetadata*>(aiData->mVRMMeta);
USkeletalMesh* sk = vrmAssetList->SkeletalMesh;
UIKRigDefinition* rig = nullptr;
{
FString name = FString(TEXT("IK_")) + vrmAssetList->BaseFileName + TEXT("_VrmHumanoid");
rig = VRM4U_NewObject<UIKRigDefinition>(vrmAssetList->Package, *name, RF_Public | RF_Standalone);
SimpleRigController rigcon(rig);
rigcon.SetSkeletalMesh(sk);
if (vrmAssetList->VrmMetaObject->humanoidBoneTable.Num() == 0) {
// immediate generate bone table
/*
if (mc) {
for (auto& boneMap : VRMUtil::table_ue4_vrm) {
FString s;
for (auto& table : mc->GetNodeMappingTable()) {
if (table.Key.ToString().ToLower() == boneMap.BoneUE4.ToLower()) {
s = table.Value.ToString();
}
}
if (s != "" && boneMap.BoneVRM != "") {
vrmAssetList->VrmMetaObject->humanoidBoneTable.Add(boneMap.BoneVRM, s);
}
}
}
*/
}
{
auto s = VRMGetRefSkeleton(sk).GetBoneName(0);
rigcon.VRMAddRetargetChain(TEXT("root"), s, s);
}
for (auto& modelName : vrmAssetList->VrmMetaObject->humanoidBoneTable) {
if (modelName.Key == "" || modelName.Value == "") {
continue;
}
// spine
int type = 0;
if (modelName.Key == TEXT("spine")) {
type = 1;
}
if (modelName.Key == TEXT("chest") || modelName.Key == TEXT("upperChest")) {
type = 2;
}
switch (type) {
case 0:
rigcon.VRMAddRetargetChain(*modelName.Key, *modelName.Value, *modelName.Value);
break;
case 1:
{
auto *s = vrmAssetList->VrmMetaObject->humanoidBoneTable.Find(TEXT("upperChest"));
if (s == nullptr) {
s = vrmAssetList->VrmMetaObject->humanoidBoneTable.Find(TEXT("chest"));
}
if (s) {
// spine chain
rigcon.VRMAddRetargetChain(*modelName.Key, *modelName.Value, **s);
}
}
break;
default:
break;
}
if (modelName.Key == TEXT("hips")) {
rigcon.SetRetargetRoot(*modelName.Value);
}
}
}
{
UIKRigDefinition* rig_epic = nullptr;
FString name = FString(TEXT("IK_")) + vrmAssetList->BaseFileName + TEXT("_MannequinBone");
rig_epic = VRM4U_NewObject<UIKRigDefinition>(vrmAssetList->Package, *name, RF_Public | RF_Standalone);
SimpleRigController rigcon = SimpleRigController(rig_epic);
rigcon.SetSkeletalMesh(sk);
{
auto s = VRMGetRefSkeleton(sk).GetBoneName(0);
rigcon.VRMAddRetargetChain(TEXT("root"), s, s);
}
for (auto& modelName : vrmAssetList->VrmMetaObject->humanoidBoneTable) {
if (modelName.Key == "" || modelName.Value == "") {
continue;
}
for (auto& a : VRMUtil::table_ue4_vrm) {
if (a.BoneUE4 == "" || a.BoneVRM == "") {
continue;
}
if (a.BoneVRM.ToLower() == modelName.Key.ToLower()) {
rigcon.VRMAddRetargetChain(*a.BoneUE4, *modelName.Value, *modelName.Value);
if (modelName.Key == TEXT("hips")) {
rigcon.SetRetargetRoot(*modelName.Value);
}
break;
}
}
}
}
UIKRigDefinition* table_rig_ik[2] = {};
{
FString table_name[2] = {
FString(TEXT("IK_")) + vrmAssetList->BaseFileName + TEXT("_Mannequin"),
FString(TEXT("IK_UEFN_")) + vrmAssetList->BaseFileName + TEXT("_Mannequin"),
};
for (int ik_no=0; ik_no<2; ik_no++){
FString name = table_name[ik_no];
table_rig_ik[ik_no] = VRM4U_NewObject<UIKRigDefinition>(vrmAssetList->Package, *name, RF_Public | RF_Standalone);
auto rig_ik = table_rig_ik[ik_no];
SimpleRigController rigcon = SimpleRigController(rig_ik);
rigcon.SetSkeletalMesh(sk);
{
auto s = VRMGetRefSkeleton(sk).GetBoneName(0);
rigcon.VRMAddRetargetChain(TEXT("Root"), s, s);
}
struct TT {
FString chain;
FString s1;
FString s2;
uint32_t mask = 0xFFFF;
};
TArray<FString> AddedChainList;
TArray<TT> table = {
{TEXT("Spine"), TEXT("spine"), TEXT("chest"),},
#if UE_VERSION_OLDER_THAN(5,4,0)
{TEXT("Head"), TEXT("neck"), TEXT("head"),},
#else
{TEXT("Neck"), TEXT("neck"), TEXT("neck"),},
{TEXT("Head"), TEXT("head"), TEXT("head"),},
#endif
{TEXT("RightArm"), TEXT("rightUpperArm"), TEXT("rightHand"),},
{TEXT("LeftArm"), TEXT("leftUpperArm"), TEXT("leftHand"),},
// 0
{TEXT("RightLeg"), TEXT("rightUpperLeg"), TEXT("rightToes"), 0x01},
{TEXT("LeftLeg"), TEXT("leftUpperLeg"), TEXT("leftToes"), 0x01},
// 1
{TEXT("RightLeg"), TEXT("rightUpperLeg"), TEXT("rightFoot"), 0x02},
{TEXT("LeftLeg"), TEXT("leftUpperLeg"), TEXT("leftFoot"), 0x02},
{TEXT("RightToe"), TEXT("rightToes"), TEXT("rightToes"), 0x02},
{TEXT("LeftToe"), TEXT("leftToes"), TEXT("leftToes"), 0x02},
{TEXT("LeftThumb"), TEXT("leftThumbMetacarpal"), TEXT("leftThumbDistal"),}, // vrm1 thumb
{TEXT("LeftThumb"), TEXT("leftThumbProximal"), TEXT("leftThumbDistal"),},
{TEXT("LeftIndex"), TEXT("leftIndexProximal"), TEXT("leftIndexDistal"),},
{TEXT("LeftMiddle"), TEXT("leftMiddleProximal"), TEXT("leftMiddleDistal"),},
{TEXT("LeftRing"), TEXT("leftRingProximal"), TEXT("leftRingDistal"),},
{TEXT("LeftPinky"), TEXT("leftLittleProximal"), TEXT("leftLittleDistal"),},
{TEXT("RightThumb"), TEXT("rightThumbMetacarpal"), TEXT("rightThumbDistal"),}, // vrm1 thumb
{TEXT("RightThumb"), TEXT("rightThumbProximal"), TEXT("rightThumbDistal"),},
{TEXT("RightIndex"), TEXT("rightIndexProximal"), TEXT("rightIndexDistal"),},
{TEXT("RightMiddle"), TEXT("rightMiddleProximal"), TEXT("rightMiddleDistal"),},
{TEXT("RightRing"), TEXT("rightRingProximal"), TEXT("rightRingDistal"),},
{TEXT("RightPinky"), TEXT("rightLittleProximal"), TEXT("rightLittleDistal"),},
{TEXT("LeftClavicle"), TEXT("leftShoulder"), TEXT("leftShoulder"),},
{TEXT("RightClavicle"), TEXT("rightShoulder"), TEXT("rightShoulder"),},
{TEXT("LeftHandIK"), TEXT("ik_hand_l"), TEXT("ik_hand_l"),},
{TEXT("RightHandIK"), TEXT("ik_hand_r"), TEXT("ik_hand_r"),},
{TEXT("HandGunIK"), TEXT("ik_hand_gun"), TEXT("ik_hand_gun"),},
{TEXT("FootRootIK"), TEXT("ik_foot_root"), TEXT("ik_foot_root"),},
{TEXT("HandRootIK"), TEXT("ik_hand_root"), TEXT("ik_hand_root"),},
};
TArray<TT> table_BVH = {
{TEXT("Spine"), TEXT("torso_1"), TEXT("torso_7"),},
#if UE_VERSION_OLDER_THAN(5,4,0)
{TEXT("Head"), TEXT("neck_1"), TEXT("head"),},
#else
{TEXT("Neck"), TEXT("neck_1"), TEXT("neck_2"),},
{TEXT("Head"), TEXT("head"), TEXT("head"),},
#endif
{TEXT("RightArm"), TEXT("r_up_arm"), TEXT("r_hand"),},
{TEXT("LeftArm"), TEXT("l_up_arm"), TEXT("l_hand"),},
// 0
{TEXT("RightLeg"), TEXT("r_up_leg"), TEXT("r_toes"), 0x01},
{TEXT("LeftLeg"), TEXT("l_up_leg"), TEXT("l_toes"), 0x01},
// 1
{TEXT("RightLeg"), TEXT("r_up_leg"), TEXT("r_foot"), 0x02},
{TEXT("LeftLeg"), TEXT("l_up_leg"), TEXT("l_foot"), 0x02},
{TEXT("RightToe"), TEXT("r_toes"), TEXT("r_toes"), 0x02},
{TEXT("LeftToe"), TEXT("l_toes"), TEXT("l_toes"), 0x02},
{TEXT("LeftClavicle"), TEXT("l_shoulder"), TEXT("l_shoulder"),},
{TEXT("RightClavicle"), TEXT("r_shoulder"), TEXT("r_shoulder"),},
};
// mocopi bvh bone name
if (Options::Get().IsBVHModel()) {
table.Append(table_BVH);
rigcon.SetRetargetRoot("root");
}
for (auto& t : table) {
if ((t.mask & (1 << 1)) == 0) {
//if ((t.mask & (1 << ik_no)) == 0) {
continue;
}
if (AddedChainList.Contains(t.chain)) {
continue;
}
if (t.chain == TEXT("LeftThumb") || (t.chain == TEXT("RightThumb"))) {
bool b0 = (t.s1 == TEXT("leftThumbProximal")) || (t.s1 == TEXT("rightThumbProximal"));
bool b1 = (t.s1 == TEXT("leftThumbMetacarpal")) || (t.s1 == TEXT("rightThumbMetacarpal"));
if (Options::Get().IsVRM10Model() && b0) {
continue;
}
if (Options::Get().IsVRM0Model() && b1) {
continue;
}
}
TT conv;
for (auto& modelName : vrmAssetList->VrmMetaObject->humanoidBoneTable) {
if (modelName.Key == "" || modelName.Value == "") {
continue;
}
if (t.s1.ToLower() == modelName.Key.ToLower()) {
conv.s1 = modelName.Value;
}
if (t.s2.ToLower() == modelName.Key.ToLower()) {
conv.s2 = modelName.Value;
}
}
if (conv.s1 == "" || conv.s2 == "") {
// for ik bone
if (VRMGetRefSkeleton(sk).FindBoneIndex(*t.s1) >= 0) {
conv.s1 = t.s1;
}
if (VRMGetRefSkeleton(sk).FindBoneIndex(*t.s2) >= 0) {
conv.s2 = t.s2;
}
}
if (conv.s1 == "" || conv.s2 == "") continue;
{
FString s2 = conv.s2;
if (t.chain == TEXT("Spine")) {
// neck parent
for (auto& modelName : vrmAssetList->VrmMetaObject->humanoidBoneTable) {
if (modelName.Key == "neck") {
auto& ref = VRMGetRefSkeleton(sk);
auto index = ref.FindRawBoneIndex(*modelName.Value);
auto tmp = ref.GetBoneName(ref.GetParentIndex(index));
s2 = tmp.ToString();
}
}
}
rigcon.VRMAddRetargetChain(*t.chain, *conv.s1, *s2);
AddedChainList.Add(t.chain);
}
}
//rigcon.LocalSolverSetup(vrmAssetList, ik_no);
rigcon.LocalSolverSetup(vrmAssetList, 1);
for (auto& modelName : vrmAssetList->VrmMetaObject->humanoidBoneTable) {
if (modelName.Key == "" || modelName.Value == "") {
continue;
}
if (modelName.Key == TEXT("hips")) {
rigcon.SetRetargetRoot(*modelName.Value);
}
}
} // ik_no
} // skeleton ik
#if UE_VERSION_OLDER_THAN(5,2,0)
#else
{
struct RTGdata{
FString NewAssetName;
TArray<FString> BaseIKRigName;
FString BaseSKName;
FString GenerateFooter;
int ModelType;
};
RTGdata rtgDataTable[3];
rtgDataTable[0].NewAssetName = FString(TEXT("RTG_")) + vrmAssetList->BaseFileName;
rtgDataTable[1].NewAssetName = FString(TEXT("RTG_UE4_")) + vrmAssetList->BaseFileName;
rtgDataTable[2].NewAssetName = FString(TEXT("RTG_UEFN_")) + vrmAssetList->BaseFileName;
rtgDataTable[0].BaseIKRigName.Add(TEXT("/Game/Characters/Mannequins/Rigs/IK_Mannequin.IK_Mannequin"));
rtgDataTable[0].BaseIKRigName.Add(TEXT("/Game/Characters/UE5_Mannequins/Rigs/IK_UE5_Mannequin_Retarget.IK_UE5_Mannequin_Retarget"));
rtgDataTable[1].BaseIKRigName.Add(TEXT("/Game/Characters/Mannequin_UE4/Rigs/IK_UE4_Mannequin.IK_UE4_Mannequin"));
rtgDataTable[1].BaseIKRigName.Add(TEXT("/Game/Characters/UE4_Mannequin/Rigs/IK_UE4_Mannequin_Retarget.IK_UE4_Mannequin_Retarget"));
rtgDataTable[2].BaseIKRigName.Add(TEXT("/Game/Characters/UEFN_Mannequin/Rigs/IK_UEFN_Mannequin.IK_UEFN_Mannequin"));
rtgDataTable[0].BaseSKName = TEXT("/Game/Characters/Mannequins/Meshes/SKM_Manny_Simple.SKM_Manny_Simple");
rtgDataTable[1].BaseSKName = TEXT("/Game/Characters/UE4_Mannequin/Meshes/SK_UE4_Mannequin.SK_UE4_Mannequin");
rtgDataTable[2].BaseSKName = "";
rtgDataTable[0].GenerateFooter = TEXT("UE5Mannequin");
rtgDataTable[1].GenerateFooter = TEXT("UE4Mannequin");
rtgDataTable[2].GenerateFooter = "";
rtgDataTable[0].ModelType = 0; // mannnequin UE5
rtgDataTable[1].ModelType = 0; // mannnequin UE4
rtgDataTable[2].ModelType = 1; // UEFN mannnequin
bool bGenerated[3] = {};
for (int ikr_no = 0; ikr_no < 3; ikr_no++) {
RTGdata& rtgData = rtgDataTable[ikr_no];
if (bGenerated[ikr_no]) {
continue;
}
auto *vrm_ikrig = table_rig_ik[rtgData.ModelType];
UObject* uobjectIK = nullptr;
for (auto rigName : rtgData.BaseIKRigName) {
FSoftObjectPath r(rigName);
uobjectIK = r.TryLoad();
if (uobjectIK) {
break;
}
}
if (uobjectIK == nullptr) {
if (ikr_no == 0) {
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(5,6,0)
#else
// IKRig 生成
uobjectIK = GenerateMannequinIK(vrmAssetList, rtgDataTable[ikr_no].BaseSKName, rtgDataTable[ikr_no].GenerateFooter);
#endif
#endif
}
}
if (uobjectIK == nullptr) {
// ベースのIKRigが無ければスキップ
continue;
}
FString name = rtgData.NewAssetName;
UIKRetargeter* ikr = VRM4U_NewObject<UIKRetargeter>(vrmAssetList->Package, *name, RF_Public | RF_Standalone);
#if WITH_EDITOR
ikr->TargetMeshOffset.Set(100, 0, 0);
#endif
auto SourceOrTargetVRM = ERetargetSourceOrTarget::Target;
auto SourceOrTargetMannequin = ERetargetSourceOrTarget::Source;
if (Options::Get().IsVRMAModel() || Options::Get().IsBVHModel()) {
SourceOrTargetVRM = ERetargetSourceOrTarget::Source;
SourceOrTargetMannequin = ERetargetSourceOrTarget::Target;
}
SimpleRetargeterController c = SimpleRetargeterController(ikr);
c.SetIKRig(SourceOrTargetVRM, vrm_ikrig);
if (uobjectIK) {
auto r2 = Cast<UIKRigDefinition>(uobjectIK);
if (r2) {
c.SetIKRig(SourceOrTargetMannequin, r2);
}
}
if (vrmAssetList && vrmAssetList->VrmMetaObject) {
auto& humanoidBoneTable = vrmAssetList->VrmMetaObject->humanoidBoneTable;
TArray<FString> KeyArray;
TArray<FString> ValueArray;
humanoidBoneTable.GenerateKeyArray(KeyArray);
humanoidBoneTable.GenerateValueArray(ValueArray);
auto FindKeyByValue = [humanoidBoneTable](const FString& SearchValue)
{
for (const auto& Pair : humanoidBoneTable)
{
if (Pair.Value.Compare(SearchValue, ESearchCase::IgnoreCase) == 0)
{
return Pair.Key;
}
}
return FString("");
};
VRMRetargetData retargetData;
retargetData.Setup(vrmAssetList,
VRMConverter::Options::Get().IsVRMModel(),
VRMConverter::Options::Get().IsBVHModel(),
VRMConverter::Options::Get().IsPMXModel());
auto FindRotData = [retargetData](const FString& boneVRM, FRotator& rot) {
for (auto& a : retargetData.retargetTable) {
if (a.BoneVRM.Compare(boneVRM, ESearchCase::IgnoreCase)) continue;
rot = a.rot;
return true;
}
return false;
};
{
//name
FName PoseName = "POSE_A";
const FName NewPoseName = c.CreateRetargetPose(PoseName, SourceOrTargetVRM);
FIKRetargetPose* NewPose = c.GetRetargetPosesByName(SourceOrTargetVRM, NewPoseName);
if (NewPose == nullptr) continue;
FReferenceSkeleton& RefSkeleton = sk->GetRefSkeleton();
const TArray<FTransform>& RefPose = RefSkeleton.GetRefBonePose();
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(5,6,0)
const FName RetargetRootBoneName = vrm_ikrig->GetRetargetRoot();
#else
auto rigc = UIKRigController::GetController(vrm_ikrig);
const FName RetargetRootBoneName = rigc->GetRetargetRoot();
#endif
#else
const FName RetargetRootBoneName = "";
#endif
for (int32 BoneIndex = 0; BoneIndex < RefSkeleton.GetNum(); ++BoneIndex)
{
auto BoneName = RefSkeleton.GetBoneName(BoneIndex);
auto str = FindKeyByValue(BoneName.ToString());
if (str == "") {
continue;
}
FRotator rot;
if (FindRotData(*str, rot) == false) {
continue;
}
// record a global space translation offset for the root bone
if (BoneName == RetargetRootBoneName)
{
// FTransform GlobalRefTransform = FAnimationRuntime::GetComponentSpaceTransform(RefSkeleton, RefPose, BoneIndex);
// FTransform GlobalImportedTransform = PoseAsset->GetComponentSpaceTransform(BoneName, LocalBoneTransformFromPose);
// NewPose.SetRootTranslationDelta(GlobalImportedTransform.GetLocation() - GlobalRefTransform.GetLocation());
}
// record a local space delta rotation (if there is one)
const FTransform& LocalRefTransform = RefPose[BoneIndex];
const FTransform& LocalImportedTransform = FTransform(rot, FVector(0, 0, 0), FVector(1, 1, 1));
//const FQuat DeltaRotation = LocalRefTransform.GetRotation().Inverse() * LocalImportedTransform.GetRotation();
FQuat DeltaRotation = FQuat(rot);
if (VRMConverter::Options::Get().IsVRM10Model()) {
FTransform dstTrans;
auto dstIndex = BoneIndex;
while (dstIndex >= 0)
{
dstTrans = RefSkeleton.GetRefBonePose()[dstIndex].GetRelativeTransform(dstTrans);
dstIndex = RefSkeleton.GetParentIndex(dstIndex);
if (dstIndex < 0) {
break;
}
}
//DeltaRotation = LocalRefTransform.GetRotation().Inverse() * DeltaRotation * LocalRefTransform.GetRotation();
//DeltaRotation = LocalRefTransform.GetRotation() * DeltaRotation * LocalRefTransform.GetRotation().Inverse();
//DeltaRotation = dstTrans.GetRotation() * DeltaRotation * dstTrans.GetRotation().Inverse();
DeltaRotation = dstTrans.GetRotation().Inverse() * DeltaRotation * dstTrans.GetRotation();
}
const float DeltaAngle = FMath::RadiansToDegrees(DeltaRotation.GetAngle());
constexpr float MinAngleThreshold = 0.05f;
if (DeltaAngle >= MinAngleThreshold)
{
NewPose->SetDeltaRotationForBone(BoneName, DeltaRotation);
#if UE_VERSION_OLDER_THAN(5,4,0)
NewPose->SortHierarchically(ikr->GetTargetIKRig()->GetSkeleton());
#else
NewPose->SortHierarchically(ikr->GetIKRig(SourceOrTargetVRM)->GetSkeleton());
#endif
}
}
}
#if VRM4U_USE_AUTOALIGN
#if UE_VERSION_OLDER_THAN(5,6,0)
#else
{
UIKRetargeterController* cp = UIKRetargeterController::GetController(ikr);
//UIKRetargeterController& c = *cp;
cp->AddDefaultOps();
}
#endif
c.SetCurrentRetargetPose(UIKRetargeter::GetDefaultPoseName(), SourceOrTargetVRM);
c.SetCurrentRetargetPose(UIKRetargeter::GetDefaultPoseName(), SourceOrTargetMannequin);
// 自動で姿勢を作る。
if (VRMConverter::Options::Get().IsBVHModel()) {
// bvhは bvh側をalignする
c.AutoAlignAllBones(SourceOrTargetVRM);
}else{
// 足首はそのまま。自動設定がうまく動作しないため。
c.AutoAlignAllBones(SourceOrTargetMannequin);
c.SetRotationOffsetForRetargetPoseBone(TEXT("foot_l"), FQuat::Identity, SourceOrTargetMannequin);
c.SetRotationOffsetForRetargetPoseBone(TEXT("foot_r"), FQuat::Identity, SourceOrTargetMannequin);
}
#endif
}
c.SetChainSetting();
bGenerated[ikr_no] = true;
} // loop
}
#endif // 5.2
#endif
} // ikrig
return true;
}