Add Games File

This commit is contained in:
Ivan Anikin
2026-05-19 13:42:41 +07:00
parent 7908479e0c
commit 12e7e22c1a
3672 changed files with 125922 additions and 0 deletions
@@ -0,0 +1,322 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmConstraint.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "DrawDebugHelpers.h"
#include "VrmMetaObject.h"
#include "VrmAssetListObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmConstraint::FAnimNode_VrmConstraint() {
}
void FAnimNode_VrmConstraint::UpdateCache(FComponentSpacePoseContext& Output) {
}
void FAnimNode_VrmConstraint::Initialize_AnyThread(const FAnimationInitializeContext& Context) {
bCallInitialized = true;
Super::Initialize_AnyThread(Context);
VrmMetaObject_Internal = const_cast<UVrmMetaObject*>(VrmMetaObject);
if (VrmMetaObject_Internal == nullptr && EnableAutoSearchMetaData) {
VrmAssetListObject_Internal = VRMUtil::GetAssetListObject(VRMGetSkinnedAsset(Context.AnimInstanceProxy->GetSkelMeshComponent()));
if (VrmAssetListObject_Internal) {
VrmMetaObject_Internal = VrmAssetListObject_Internal->VrmMetaObject;
}
}
}
void FAnimNode_VrmConstraint::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {
Super::CacheBones_AnyThread(Context);
}
void FAnimNode_VrmConstraint::UpdateInternal(const FAnimationUpdateContext& Context){
Super::UpdateInternal(Context);
}
void FAnimNode_VrmConstraint::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmConstraint::EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) {
if (bCallByAnimInstance) {
ActualAlpha = 1.f;
} else {
Super::EvaluateComponentPose_AnyThread(Output);
}
}
void FAnimNode_VrmConstraint::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
UpdateCache(Output);
if (VrmMetaObject_Internal == nullptr) {
return;
}
for (auto& a : VrmMetaObject_Internal->VRMConstraintMeta) {
int32 dstBoneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().FindBoneIndex(*(a.Key));
if (Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().GetRefBonePose().IsValidIndex(dstBoneIndex) == false) {
continue;
}
FCompactPoseBoneIndex dstPoseBoneIndex(dstBoneIndex);
auto dstRefTrans = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().GetRefBonePose()[dstBoneIndex];
auto dstRefRot = dstRefTrans.GetRotation();
auto dstParentBoneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().GetParentIndex(dstBoneIndex);
FCompactPoseBoneIndex dstParentPoseBoneIndex(dstParentBoneIndex);
auto dstParentTrans = Output.Pose.GetComponentSpaceTransform(dstParentPoseBoneIndex);
int32 srcBoneIndex = -1;
switch (a.Value.type) {
case EVRMConstraintType::None:
break;
case EVRMConstraintType::Roll:
{
auto& tmp = a.Value.constraintRoll;
srcBoneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().FindBoneIndex(*(tmp.sourceName));
}
break;
case EVRMConstraintType::Aim :
{
auto& tmp = a.Value.constraintAim;
srcBoneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().FindBoneIndex(*(tmp.sourceName));
}
break;
case EVRMConstraintType::Rotation :
{
auto& tmp = a.Value.constraintRotation;
srcBoneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().FindBoneIndex(*(tmp.sourceName));
}
break;
}
if (srcBoneIndex < 0) {
continue;
}
FCompactPoseBoneIndex srcPoseBoneIndex(srcBoneIndex);
auto srcRefTrans = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().GetRefBonePose()[srcBoneIndex];
auto srcRefRot = srcRefTrans.GetRotation();
auto srcParentBoneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().GetParentIndex(srcBoneIndex);
FCompactPoseBoneIndex srcParentPoseBoneIndex(srcParentBoneIndex);
auto srcParentTrans = Output.Pose.GetComponentSpaceTransform(srcParentPoseBoneIndex);
if (a.Value.type == EVRMConstraintType::Rotation) {
auto& rot = a.Value.constraintRotation;
auto srcCurrentTrans = Output.Pose.GetLocalSpaceTransform(srcPoseBoneIndex);
auto srcCurrentRot = srcCurrentTrans.GetRotation();
auto dstCurrentTrans = Output.Pose.GetComponentSpaceTransform(dstPoseBoneIndex);
auto dstCurrentRot = dstCurrentTrans.GetRotation();
{
auto r = (srcRefRot.Inverse() * srcCurrentRot);
FVector axis;
decltype(FVector::X) angle;
r.ToAxisAndAngle(axis, angle);
r = FQuat(axis, angle * rot.weight);
r = dstParentTrans.GetRotation() * dstRefRot * r;
dstCurrentTrans.SetRotation(r);
Output.Pose.SetComponentSpaceTransform(dstPoseBoneIndex, dstCurrentTrans);
}
}
if (a.Value.type == EVRMConstraintType::Roll) {
auto& roll = a.Value.constraintRoll;
auto srcCurrentTrans = Output.Pose.GetLocalSpaceTransform(srcPoseBoneIndex);
auto srcCurrentRot = srcCurrentTrans.GetRotation();
auto dstCurrentTrans = Output.Pose.GetComponentSpaceTransform(dstPoseBoneIndex);
auto dstCurrentRot = dstCurrentTrans.GetRotation();
{
//auto r = (srcRefRot.Inverse() * srcCurrentRot);
auto r = srcCurrentRot;
//auto r = (srcCurrentRot);
FVector axis;
decltype(FVector::X) angle;
r.ToAxisAndAngle(axis, angle);
angle = FMath::UnwindRadians(angle);
FVector v;
if (roll.rollAxis.Find("X") >= 0) {
v.Set(1, 0, 0);
}
if (roll.rollAxis.Find("Y") >= 0) {
v.Set(0, 1, 0);
}
if (roll.rollAxis.Find("Z") >= 0) {
v.Set(0, 0, 1);
}
if (roll.rollAxis.Find("negative") >= 0) {
v *= -1.f;
}
//v = srcCurrentTrans.TransformVector(v);
//v *= -1.f;
auto d = FVector::DotProduct(axis, v);
r = FQuat(v, angle * roll.weight * d);
r = dstParentTrans.GetRotation() * r;
dstCurrentTrans.SetRotation(r);
Output.Pose.SetComponentSpaceTransform(dstPoseBoneIndex, dstCurrentTrans);
}
}
if (a.Value.type == EVRMConstraintType::Aim) {
auto& aim = a.Value.constraintAim;
//auto srcCurrentTrans = Output.Pose.GetComponentSpaceTransform(srcPoseBoneIndex);
//auto srcCurrentRot = srcCurrentTrans.GetRotation();
//auto dstCurrentTrans = Output.Pose.GetComponentSpaceTransform(dstPoseBoneIndex);
auto dstCurrentTrans = dstRefTrans * dstParentTrans;
//auto dstCurrentRot = dstCurrentTrans.GetRotation();
{
FVector v;
if (aim.aimAxis.Find("X") >= 0) {
v.Set(1, 0, 0);
}
if (aim.aimAxis.Find("Y") >= 0) {
v.Set(0, 1, 0);
}
if (aim.aimAxis.Find("Z") >= 0) {
v.Set(0, 0, 1);
}
if (aim.aimAxis.Find("negative") >= 0) {
v *= -1.f;
}
auto fromVec = dstCurrentTrans.TransformVector(v);
auto toVec = srcParentTrans.TransformVector(v);
//auto toVec = (srcCurrentTrans.GetLocation() - srcRefTrans.GetLocation()).Normalize();
auto fromToQuat = FQuat::FindBetweenNormals(fromVec, toVec);
auto r = fromToQuat;
FVector axis;
decltype(FVector::X) angle;
r.ToAxisAndAngle(axis, angle);
r = FQuat(axis, angle * aim.weight);
r = dstCurrentTrans.GetRotation().Inverse() * r * dstCurrentTrans.GetRotation();
r = dstParentTrans.GetRotation() * dstRefRot * r;
dstCurrentTrans.SetRotation(r);
Output.Pose.SetComponentSpaceTransform(dstPoseBoneIndex, dstCurrentTrans);
}
}
}
}
bool FAnimNode_VrmConstraint::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
return true;
}
void FAnimNode_VrmConstraint::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
void FAnimNode_VrmConstraint::ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground) const
{
#if WITH_EDITOR
auto MetaObjectLocal = VrmMetaObject_Internal;
if (MetaObjectLocal == nullptr && EnableAutoSearchMetaData) {
auto* p = VRMUtil::GetAssetListObject(VRMGetSkinnedAsset(PreviewSkelMeshComp));
if (p) {
MetaObjectLocal = p->VrmMetaObject;
}
}
if (MetaObjectLocal == nullptr || PreviewSkelMeshComp == nullptr) {
return;
}
if (PreviewSkelMeshComp->GetWorld() == nullptr) {
return;
}
ESceneDepthPriorityGroup Priority = SDPG_World;
if (bPreviewForeground) Priority = SDPG_Foreground;
const TArray<FLinearColor> color = {
FLinearColor(1.f, 0, 0),
FLinearColor(1.f, 0.5, 0),
FLinearColor(1.f, 0, 0.5),
};
for (const auto& c : MetaObjectLocal->VRMConstraintMeta) {
int colType = 0;
FString sourceName;
switch (c.Value.type) {
case EVRMConstraintType::Rotation:
sourceName = c.Value.constraintRotation.sourceName;
colType = 0;
break;
case EVRMConstraintType::Aim:
sourceName = c.Value.constraintAim.sourceName;
colType = 1;
break;
case EVRMConstraintType::Roll:
sourceName = c.Value.constraintRoll.sourceName;
colType = 2;
break;
}
FString targetName = c.Key;
const FTransform t1 = PreviewSkelMeshComp->GetSocketTransform(*sourceName);
const FTransform t2 = PreviewSkelMeshComp->GetSocketTransform(*targetName);
DrawWireSphere(PDI, t1, color[colType], 1, 32, Priority);
PDI->DrawLine(
t1.GetLocation(),
t2.GetLocation(),
color[colType] / 2.f,
Priority);
}
// PDI->DrawLine(
// t.GetLocation(),
// t2.GetLocation(),
// color[springNo % color.Num()] / 2.f,
// Priority);
#endif
}
@@ -0,0 +1,354 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmCopyHandBone.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "BonePose.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
namespace {
const TArray<FString> HandBoneTableLeap = {
// "L_Wrist",
//"L_Palm",
"L_thumb_meta",
"L_thumb_a",
"L_thumb_b",
// "L_thumb_end",
// "L_index_meta",
"L_index_a",
"L_index_b",
"L_index_c",
// "L_index_end",
// "L_middle_meta",
"L_middle_a",
"L_middle_b",
"L_middle_c",
// "L_middle_end",
// "L_ring_meta",
"L_ring_a",
"L_ring_b",
"L_ring_c",
// "L_ring_end",
// "L_pinky_meta",
"L_pinky_a",
"L_pinky_b",
"L_pinky_c",
// "L_pinky_end",
// "R_Wrist",
//"R_Palm",
"R_thumb_meta",
"R_thumb_a",
"R_thumb_b",
// "R_thumb_end",
// "R_index_meta",
"R_index_a",
"R_index_b",
"R_index_c",
// "R_index_end",
// "R_middle_meta",
"R_middle_a",
"R_middle_b",
"R_middle_c",
// "R_middle_end",
// "R_ring_meta",
"R_ring_a",
"R_ring_b",
"R_ring_c",
// "R_ring_end",
// "R_pinky_meta",
"R_pinky_a",
"R_pinky_b",
"R_pinky_c",
// "R_pinky_end",
};
const TArray<FString> HandBoneTableVRoid = {
//"J_Bip_L_Hand",
"J_Bip_L_Thumb1",
"J_Bip_L_Thumb2",
"J_Bip_L_Thumb3",
"J_Bip_L_Index1",
"J_Bip_L_Index2",
"J_Bip_L_Index3",
"J_Bip_L_Middle1",
"J_Bip_L_Middle2",
"J_Bip_L_Middle3",
"J_Bip_L_Ring1",
"J_Bip_L_Ring2",
"J_Bip_L_Ring3",
"J_Bip_L_Little1",
"J_Bip_L_Little2",
"J_Bip_L_Little3",
//"J_Bip_R_Hand",
"J_Bip_R_Thumb1",
"J_Bip_R_Thumb2",
"J_Bip_R_Thumb3",
"J_Bip_R_Index1",
"J_Bip_R_Index2",
"J_Bip_R_Index3",
"J_Bip_R_Middle1",
"J_Bip_R_Middle2",
"J_Bip_R_Middle3",
"J_Bip_R_Ring1",
"J_Bip_R_Ring2",
"J_Bip_R_Ring3",
"J_Bip_R_Little1",
"J_Bip_R_Little2",
"J_Bip_R_Little3",
};
const TArray<FString> HandBoneTableVRM = {
//"leftHand",
"leftThumbProximal",
"leftThumbIntermediate",
"leftThumbDistal",
"leftIndexProximal",
"leftIndexIntermediate",
"leftIndexDistal",
"leftMiddleProximal",
"leftMiddleIntermediate",
"leftMiddleDistal",
"leftRingProximal",
"leftRingIntermediate",
"leftRingDistal",
"leftLittleProximal",
"leftLittleIntermediate",
"leftLittleDistal",
//"rightHand"
"rightThumbProximal",
"rightThumbIntermediate",
"rightThumbDistal",
"rightIndexProximal",
"rightIndexIntermediate",
"rightIndexDistal",
"rightMiddleProximal",
"rightMiddleIntermediate",
"rightMiddleDistal",
"rightRingProximal",
"rightRingIntermediate",
"rightRingDistal",
"rightLittleProximal",
"rightLittleIntermediate",
"rightLittleDistal",
};
}
FAnimNode_VrmCopyHandBone::FAnimNode_VrmCopyHandBone()
{
}
void FAnimNode_VrmCopyHandBone::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmCopyHandBone::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
const auto dstRefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
//dstRefSkeleton.GetParentIndex
TArray<FBoneTransform> tmpOutTransform;
tmpOutTransform.SetNum(HandBoneTableVRoid.Num());
TArray<int> boneIndexTable;
boneIndexTable.SetNum(HandBoneTableVRoid.Num());
auto BoneSpace = EBoneControlSpace::BCS_ParentBoneSpace;
TArray<USkeletalMeshComponent*> MeshTable = {
SkeletalMeshComponentLeft,
SkeletalMeshComponentRight,
};
for (int i = 0; i < HandBoneTableVRM.Num(); ++i) {
FString BoneNameModel = HandBoneTableVRoid[i];
FString BoneNameLeap = HandBoneTableLeap[i];
if (VrmMetaObject) {
FString *s = VrmMetaObject->humanoidBoneTable.Find(HandBoneTableVRM[i]);
if (s) {
BoneNameModel = *s;
}
}
boneIndexTable[i] = -1;
int skelNo = -1;
for (auto SkeletalMeshComponent : MeshTable) {
skelNo++;
if (SkeletalMeshComponent == nullptr) {
continue;
}
const auto &dstRefSkeletonTransform = dstRefSkeleton.GetRefBonePose();
const auto &srcRefSkeletonTransform = VRMGetRefSkeleton( VRMGetSkinnedAsset(SkeletalMeshComponent) ).GetRefBonePose();
const auto srcIndex = SkeletalMeshComponent->GetBoneIndex(*BoneNameLeap);
const auto dstIndex = dstRefSkeleton.FindBoneIndex(*BoneNameModel);
if (srcIndex < 0 || dstIndex < 0) {
continue;
}
const auto& srcCurrentTrans = SkeletalMeshComponent->GetSocketTransform(*BoneNameLeap, RTS_ParentBoneSpace);
const auto& srcRefTrans = srcRefSkeletonTransform[srcIndex];
const auto& dstRefTrans = dstRefSkeletonTransform[dstIndex];
FCompactPoseBoneIndex CompactPoseBoneToModify(dstIndex);
//auto a = srcCurrentTrans;
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(CompactPoseBoneToModify);
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, BoneSpace);
FQuat baseDiff = FQuat::FindBetween(srcRefTrans.GetLocation(), dstRefTrans.GetLocation());
//FQuat q9 = FQuat(FVector(1, 0, 0), 3.14f / 2.f);
FQuat q9;
auto v = srcRefTrans.GetLocation().GetSafeNormal();
if (skelNo == 0) {
if (BoneNameLeap.Find(TEXT("thumb")) >= 0) {
if (BoneNameLeap.Find(TEXT("meta")) < 0) {
q9 = FQuat(FVector(1, 0, 0), 3.14f / 2.f) * FQuat(v, -3.14f / 2.f) * srcRefTrans.GetRotation().Inverse();
} else {
auto vv = srcRefTrans.GetLocation();
vv.Y = srcRefTrans.GetLocation().Z;
vv.Z = srcRefTrans.GetLocation().Y;
FQuat baseDiff2 = FQuat::FindBetween(vv, FVector(1,0,0));
q9 = FQuat(v, -3.14f / 2.f) * baseDiff2.Inverse() * srcRefTrans.GetRotation().Inverse();
}
}else {
q9 = FQuat(v, 3.14f / 2.f) * srcRefTrans.GetRotation().Inverse();
}
} else {
if (BoneNameLeap.Find(TEXT("thumb")) >= 0) {
if (BoneNameLeap.Find(TEXT("meta")) < 0) {
//q9 = srcRefTrans.GetRotation().Inverse();
q9 = FQuat(FVector(1, 0, 0), 3.14f / 2.f) * FQuat(v, -3.14f / 2.f) * srcRefTrans.GetRotation().Inverse();
} else {
//q9 = FQuat(-v, 3.14f) * srcRefTrans.GetRotation().Inverse();
auto vv = srcRefTrans.GetLocation();
vv.X = srcRefTrans.GetLocation().X;
vv.Y = srcRefTrans.GetLocation().Z;
vv.Z = srcRefTrans.GetLocation().Y;
FQuat baseDiff2 = FQuat::FindBetween(vv, FVector(-1,0,0));
auto tt = srcRefTrans;
tt.SetLocation(vv);
//q9 = FQuat(FVector(1, 0, 0), 3.14f / 2.f) * FQuat(v, 3.14f / 2.f) * baseDiff2.Inverse() * srcRefTrans.GetRotation().Inverse();
//q9 = FQuat(FVector(0, 0, -1), -3.14f / 2.f) * FQuat(FVector(1, 0, 0), -3.14f / 2.f) * FQuat(FVector(0, 1, 0), -3.14f / 2.f) * FQuat(v, 3.14f / 2.f) * baseDiff2.Inverse() * srcRefTrans.GetRotation().Inverse();
q9 = FQuat(FVector(0, 0, -1), -3.14f / 2.f) * FQuat(FVector(1, 0, 0), -3.14f / 2.f) * FQuat(FVector(0, 1, 0), -3.14f / 2.f) * FQuat(v, 3.14f / 2.f) * baseDiff2.Inverse() * srcRefTrans.GetRotation().Inverse();
//q9.X *= -1.f;
//q9.Y *= -1.f;
//q9.Z *= -1.f;
/*
auto vv = srcRefTrans.GetLocation();
vv.X = -srcRefTrans.GetLocation().X;
vv.Y = srcRefTrans.GetLocation().Z;
vv.Z = srcRefTrans.GetLocation().Y;
FQuat baseDiff2 = FQuat::FindBetween(vv, FVector(1,0,0));
//q9 = FQuat(FVector(1, 0, 0), 3.14f / 2.f) * FQuat(v, 3.14f / 2.f) * baseDiff2.Inverse() * srcRefTrans.GetRotation().Inverse();
q9 = FQuat(FVector(1, 0, 0), -3.14f / 2.f) * FQuat(FVector(0, 1, 0), -3.14f / 2.f) * FQuat(v, 3.14f / 2.f) * baseDiff2.Inverse() * srcRefTrans.GetRotation().Inverse();
*/
}
} else {
q9 = FQuat(-v, 3.14f / 2.f) * FQuat(FVector(0, 1, 0), 3.14f) * FQuat(FVector(0, 0, 1), 3.14f) * srcRefTrans.GetRotation().Inverse();
}
}
FQuat q = baseDiff * q9;
//FQuat q = FQuat::FindBetween(srcRefTrans.GetLocation(), dstRefTrans.GetLocation());
//NewBoneTM.SetRotation(q*FQuat(FVector(1, 0, 0), 3.14f / 2.f) * srcCurrentTrans.GetRotation() * FQuat(FVector(-1, 0, 0), 3.14f / 2.f));
//NewBoneTM.SetRotation(FQuat(FVector(1, 0, 0), 3.14f / 2.f) * srcCurrentTrans.GetRotation() * FQuat(FVector(-1, 0, 0), 3.14f / 2.f));
NewBoneTM.SetRotation(q * srcCurrentTrans.GetRotation() * q.Inverse());
//NewBoneTM.SetRotation(q9 * baseDiff*srcCurrentTrans.GetRotation() * baseDiff.Inverse() * q9.Inverse());
//NewBoneTM.SetRotation(q9 * baseDiff*srcCurrentTrans.GetRotation() * q9.Inverse());
//NewBoneTM.SetLocation(dstRefTrans.GetLocation());
//NewBoneTM.SetLocation(NewBoneTM.GetLocation() );
//NewBoneTM.SetLocation(NewBoneTM.GetRotation() * dstRefTrans.GetLocation() );
//NewBoneTM.SetLocation(dstRefTrans.GetLocation());
//a.SetLocation(dstRefTrans.GetLocation());
//FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, a, CompactPoseBoneToModify, EBoneControlSpace::BCS_ParentBoneSpace);
//OutBoneTransforms.Insert
tmpOutTransform[i] = FBoneTransform(CompactPoseBoneToModify, NewBoneTM);
boneIndexTable[i] = dstIndex;
break;
}
}
{
tmpOutTransform.Sort(FCompareBoneTransformIndex());
//tmpOutTransform.Sort([](const FBoneTransform& x, const FBoneTransform& y) { return x.BoneIndex.GetInt() < y.BoneIndex.GetInt(); });
boneIndexTable.Sort();
for (int i=0; i<tmpOutTransform.Num(); ++i){
if (boneIndexTable[i] < 0) {
continue;
}
auto &a = tmpOutTransform[i];
int parentBoneIndex = dstRefSkeleton.GetParentIndex(boneIndexTable[i]);
int parentInHandTable = boneIndexTable.Find(parentBoneIndex);
if (parentInHandTable >= 0) {
a.Transform *= tmpOutTransform[parentInHandTable].Transform;
}else {
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, a.Transform, a.BoneIndex, BoneSpace);
}
OutBoneTransforms.Add(a);
}
}
}
bool FAnimNode_VrmCopyHandBone::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmCopyHandBone::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
@@ -0,0 +1,126 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmModifyBoneDynamic.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmModifyBoneDynamic::FAnimNode_VrmModifyBoneDynamic()
: Translation(FVector::ZeroVector)
, Rotation(FRotator::ZeroRotator)
, Scale(FVector(1.0f))
, TranslationMode(BMM_Ignore)
, RotationMode(BMM_Ignore)
, ScaleMode(BMM_Ignore)
, TranslationSpace(BCS_ComponentSpace)
, RotationSpace(BCS_ComponentSpace)
, ScaleSpace(BCS_ComponentSpace)
{
}
void FAnimNode_VrmModifyBoneDynamic::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmModifyBoneDynamic::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
// the way we apply transform is same as FMatrix or FTransform
// we apply scale first, and rotation, and translation
// if you'd like to translate first, you'll need two nodes that first node does translate and second nodes to rotate.
const FBoneContainer& BoneContainer = Output.Pose.GetPose().GetBoneContainer();
//FCompactPoseBoneIndex CompactPoseBoneToModify = BoneToModify.GetCompactPoseIndex(BoneContainer);
int32 boneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().FindBoneIndex(BoneNameToModify);
if (boneIndex < 0) {
return;
}
FCompactPoseBoneIndex CompactPoseBoneToModify(boneIndex);
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(CompactPoseBoneToModify);
FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
if (ScaleMode != BMM_Ignore)
{
// Convert to Bone Space.
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, ScaleSpace);
if (ScaleMode == BMM_Additive)
{
NewBoneTM.SetScale3D(NewBoneTM.GetScale3D() * Scale);
}
else
{
NewBoneTM.SetScale3D(Scale);
}
// Convert back to Component Space.
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, ScaleSpace);
}
if (RotationMode != BMM_Ignore)
{
// Convert to Bone Space.
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, RotationSpace);
const FQuat BoneQuat(Rotation);
if (RotationMode == BMM_Additive)
{
NewBoneTM.SetRotation(BoneQuat * NewBoneTM.GetRotation());
}
else
{
NewBoneTM.SetRotation(BoneQuat);
}
// Convert back to Component Space.
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, RotationSpace);
}
if (TranslationMode != BMM_Ignore)
{
// Convert to Bone Space.
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, TranslationSpace);
if (TranslationMode == BMM_Additive)
{
NewBoneTM.AddToTranslation(Translation);
}
else
{
NewBoneTM.SetTranslation(Translation);
}
// Convert back to Component Space.
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, TranslationSpace);
}
if (boneIndex >= 0) {
//FCompactPoseBoneIndex b(boneIndex);
OutBoneTransforms.Add(FBoneTransform(CompactPoseBoneToModify, NewBoneTM));
//OutBoneTransforms.Add(FBoneTransform(BoneToModify.GetCompactPoseIndex(BoneContainer), NewBoneTM));
}
}
bool FAnimNode_VrmModifyBoneDynamic::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmModifyBoneDynamic::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
@@ -0,0 +1,190 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmModifyBoneList.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "DrawDebugHelpers.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmModifyBoneList::FAnimNode_VrmModifyBoneList()
{
}
//void FAnimNode_VrmModifyBoneList::Update_AnyThread(const FAnimationUpdateContext& Context) {
// Super::Update_AnyThread(Context);
// //Context.GetDeltaTime();
//}
void FAnimNode_VrmModifyBoneList::Initialize_AnyThread(const FAnimationInitializeContext& Context) {
Super::Initialize_AnyThread(Context);
}
void FAnimNode_VrmModifyBoneList::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {
Super::CacheBones_AnyThread(Context);
}
void FAnimNode_VrmModifyBoneList::UpdateInternal(const FAnimationUpdateContext& Context){
Super::UpdateInternal(Context);
}
void FAnimNode_VrmModifyBoneList::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmModifyBoneList::EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) {
Super::EvaluateComponentPose_AnyThread(Output);
}
void FAnimNode_VrmModifyBoneList::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
const auto Skeleton = Output.AnimInstanceProxy->GetSkeleton();
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
TArray<int> boneIndexTable;
TArray<FBoneTransform> tmpOutTransform;
//dstRefSkeleton.GetParentIndex
{
for (const auto &t : BoneTrans) {
int index = RefSkeleton.FindBoneIndex(*t.Key);
if (index < 0) continue;
FBoneTransform f(FCompactPoseBoneIndex(index), t.Value);
FVector v = RefSkeletonTransform[index].GetLocation();
//f.Transform.SetTranslation(v);
//f.Transform.SetTranslation(RefSkeletonTransform[index].GetLocation());
tmpOutTransform.Add(f);
boneIndexTable.Add(index);
}
// bone hierarchy
// start with 1
for (int i = 0; i < tmpOutTransform.Num(); ++i) {
auto& a = tmpOutTransform[i];
int parentBoneIndex = RefSkeleton.GetParentIndex(boneIndexTable[i]);
if (parentBoneIndex < 0) continue;
int parentInTable = boneIndexTable.Find(parentBoneIndex);
for (int j = 0; j < 100; ++j) {
if (parentInTable >= 0) {
// find in table
break;
}
if (parentBoneIndex < 0) {
// root bone
break;
}
// add outtransform with ref bone
//FBoneTransform f(FCompactPoseBoneIndex(parentBoneIndex), RefSkeletonTransform[parentBoneIndex]);
// add outtransform with input bone
FCompactPoseBoneIndex CompactPoseBoneToModify(parentBoneIndex);
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(CompactPoseBoneToModify);
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, EBoneControlSpace::BCS_ParentBoneSpace);
FBoneTransform f(CompactPoseBoneToModify, NewBoneTM);
tmpOutTransform.Add(f);
boneIndexTable.Add(parentBoneIndex);
parentBoneIndex = RefSkeleton.GetParentIndex(parentBoneIndex);
parentInTable = boneIndexTable.Find(parentBoneIndex);
}
}
// sort
tmpOutTransform.Sort(FCompareBoneTransformIndex());
boneIndexTable.Sort();
}
for (int i = 0; i < tmpOutTransform.Num(); ++i) {
auto& a = tmpOutTransform[i];
int parentBoneIndex = RefSkeleton.GetParentIndex(boneIndexTable[i]);
int parentInHandTable = boneIndexTable.Find(parentBoneIndex);
if (parentInHandTable < 0) {
// root
auto BoneSpace = EBoneControlSpace::BCS_ParentBoneSpace;
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, a.Transform, a.BoneIndex, BoneSpace);
}else{
bool bUseInputTrans = false;
#if UE_VERSION_OLDER_THAN(4,27,0)
#else
FString t = RefSkeleton.GetBoneName(boneIndexTable[i]).ToString();
auto ret = UseInputTransBoneList.FilterByPredicate([&t](FString a) {
return t.Compare(a, ESearchCase::IgnoreCase) == 0;
}
);
if (ret.Num() > 0) {
bUseInputTrans = true;
}
#endif
if (bUseInputTrans) {
FCompactPoseBoneIndex CompactPoseBoneToModify(boneIndexTable[i]);
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(CompactPoseBoneToModify);
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, EBoneControlSpace::BCS_ParentBoneSpace);
a.Transform = NewBoneTM * tmpOutTransform[parentInHandTable].Transform;
} else {
a.Transform *= tmpOutTransform[parentInHandTable].Transform;
}
}
OutBoneTransforms.Add(a);
}
}
bool FAnimNode_VrmModifyBoneList::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmModifyBoneList::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
void FAnimNode_VrmModifyBoneList::ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground) const
{
#if WITH_EDITOR
if (PreviewSkelMeshComp->GetWorld() == nullptr) {
return;
}
ESceneDepthPriorityGroup Priority = SDPG_World;
if (bPreviewForeground) Priority = SDPG_Foreground;
#endif
}
@@ -0,0 +1,193 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmModifyBoneListRetarget.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "DrawDebugHelpers.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmModifyBoneListRetarget::FAnimNode_VrmModifyBoneListRetarget()
{
}
//void FAnimNode_VrmModifyBoneListRetarget::Update_AnyThread(const FAnimationUpdateContext& Context) {
// Super::Update_AnyThread(Context);
// //Context.GetDeltaTime();
//}
void FAnimNode_VrmModifyBoneListRetarget::Initialize_AnyThread(const FAnimationInitializeContext& Context) {
Super::Initialize_AnyThread(Context);
}
void FAnimNode_VrmModifyBoneListRetarget::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {
Super::CacheBones_AnyThread(Context);
}
void FAnimNode_VrmModifyBoneListRetarget::UpdateInternal(const FAnimationUpdateContext& Context){
Super::UpdateInternal(Context);
}
void FAnimNode_VrmModifyBoneListRetarget::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmModifyBoneListRetarget::EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) {
Super::EvaluateComponentPose_AnyThread(Output);
}
void FAnimNode_VrmModifyBoneListRetarget::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
const auto Skeleton = Output.AnimInstanceProxy->GetSkeleton();
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
TArray<int> boneIndexTable;
TArray<FBoneTransform> tmpOutTransform;
//dstRefSkeleton.GetParentIndex
{
if (VrmMetaObject == nullptr) {
return;
}
bool bFirstBone = true;
for (const auto &t : VrmMetaObject->humanoidBoneTable) {
#if UE_VERSION_OLDER_THAN(4,27,0)
auto *tmpVal = BoneTrans.Find(t.Key.ToLower());
if (tmpVal == nullptr) continue;
auto modelBone = *tmpVal;
#else
auto filterList= BoneTrans.FilterByPredicate([&t](TPair<FString, FTransform> a) {
return a.Key.Compare(t.Key, ESearchCase::IgnoreCase) == 0;
}
);
if (filterList.Num() != 1) continue;
auto modelBone = filterList.begin()->Value;
#endif
int index = RefSkeleton.FindBoneIndex(*t.Value);
if (index < 0) continue;
FBoneTransform f(FCompactPoseBoneIndex(index), modelBone);
//f.Transform.SetRotation(FQuat::Identity);
if (bFirstBone) {
bFirstBone = false;
if (bUseRemoteCenterPos) {
auto v = f.Transform.GetLocation() * ModelRelativeScale;
f.Transform.SetTranslation(v);
} else {
auto v = RefSkeletonTransform[index].GetLocation();
f.Transform.SetTranslation(v);
}
} else {
FVector v = RefSkeletonTransform[index].GetLocation();
f.Transform.SetTranslation(v);
}
//f.Transform.SetTranslation(RefSkeletonTransform[index].GetLocation());
tmpOutTransform.Add(f);
boneIndexTable.Add(index);
}
// bone hierarchy
// start with 1
for (int i = 1; i < tmpOutTransform.Num(); ++i) {
auto& a = tmpOutTransform[i];
int parentBoneIndex = RefSkeleton.GetParentIndex(boneIndexTable[i]);
int parentInTable = boneIndexTable.Find(parentBoneIndex);
for (int j = 0; j < 100; ++j) {
if (parentInTable >= 0) {
break;
}
// add outtransform with ref bone
FBoneTransform f(FCompactPoseBoneIndex(parentBoneIndex), RefSkeletonTransform[parentBoneIndex]);
tmpOutTransform.Add(f);
boneIndexTable.Add(parentBoneIndex);
parentBoneIndex = RefSkeleton.GetParentIndex(parentBoneIndex);
parentInTable = boneIndexTable.Find(parentBoneIndex);
}
}
// sort
tmpOutTransform.Sort(FCompareBoneTransformIndex());
boneIndexTable.Sort();
}
for (int i = 0; i < tmpOutTransform.Num(); ++i) {
auto& a = tmpOutTransform[i];
int parentBoneIndex = RefSkeleton.GetParentIndex(boneIndexTable[i]);
int parentInHandTable = boneIndexTable.Find(parentBoneIndex);
if (parentInHandTable >= 0) {
a.Transform *= tmpOutTransform[parentInHandTable].Transform;
} else {
// root
auto BoneSpace = EBoneControlSpace::BCS_ParentBoneSpace;
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, a.Transform, a.BoneIndex, BoneSpace);
}
OutBoneTransforms.Add(a);
}
}
bool FAnimNode_VrmModifyBoneListRetarget::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmModifyBoneListRetarget::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
void FAnimNode_VrmModifyBoneListRetarget::ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground) const
{
#if WITH_EDITOR
if (VrmMetaObject == nullptr || PreviewSkelMeshComp == nullptr) {
return;
}
if (PreviewSkelMeshComp->GetWorld() == nullptr) {
return;
}
ESceneDepthPriorityGroup Priority = SDPG_World;
if (bPreviewForeground) Priority = SDPG_Foreground;
#endif
}
@@ -0,0 +1,212 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmModifyHumanoidBone.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "VrmAssetListObject.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmModifyHumanoidBone::FAnimNode_VrmModifyHumanoidBone()
:
//TranslationMode(BMM_Ignore)
//, RotationMode(BMM_Ignore)
//, TranslationSpace(BCS_ComponentSpace)
RotationSpace(BCS_WorldSpace)
{
}
void FAnimNode_VrmModifyHumanoidBone::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmModifyHumanoidBone::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
// the way we apply transform is same as FMatrix or FTransform
// we apply scale first, and rotation, and translation
// if you'd like to translate first, you'll need two nodes that first node does translate and second nodes to rotate.
const FBoneContainer& BoneContainer = Output.Pose.GetPose().GetBoneContainer();
if (VrmAssetList == nullptr) {
return;
}
const auto &Transform_hum = HumanoidBoneTransform.Transform;
const auto &Transform_ext = ExtBoneTransform.Transform;
const auto &a = VRMUtil::vrm_humanoid_bone_list;
const auto &table = VrmAssetList->VrmMetaObject->humanoidBoneTable;
int boneTableNo_hum = 0;
int boneTableNo_ext = 0;
while (boneTableNo_hum <= a.Num()) {
int currentBone = -1;
FTransform trans;
int boneIndex[2] = {-1, -1};
if (boneTableNo_hum < Transform_hum.Num() && boneTableNo_hum<a.Num()) {
auto boneName = table.Find(a[boneTableNo_hum]);
if (boneName) {
boneIndex[0] = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().FindBoneIndex(**boneName);
}
}
if (boneTableNo_ext < Transform_ext.Num()) {
boneIndex[1] = boneTableNo_ext;
}
if (boneIndex[0] < 0 && boneIndex[1] < 0) {
// no bone
++boneTableNo_hum;
continue;
//break;
}
if (boneIndex[0] == boneIndex[1]) {
currentBone = boneIndex[0];
trans = Transform_hum[boneTableNo_hum];
++boneTableNo_hum;
++boneTableNo_ext;
} else {
if (boneIndex[0] < 0) {
// find ext
currentBone = boneIndex[1];
trans = Transform_ext[boneTableNo_ext];
++boneTableNo_ext;
} else if (boneIndex[1] < 0) {
// find hum
currentBone = boneIndex[0];
trans = Transform_hum[boneTableNo_hum];
++boneTableNo_hum;
} else {
if (boneIndex[0] < boneIndex[1]) {
// find hum
currentBone = boneIndex[0];
trans = Transform_hum[boneTableNo_hum];
++boneTableNo_hum;
} else {
// find ext
currentBone = boneIndex[1];
trans = Transform_ext[boneTableNo_ext];
++boneTableNo_ext;
}
}
}
const FCompactPoseBoneIndex CompactPoseBoneToModify(currentBone);
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(CompactPoseBoneToModify);
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
const FTransform orgTM = NewBoneTM;
// Convert to Bone Space.
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, RotationSpace);
//const FQuat BoneQuat(Rotation);
const FQuat BoneQuat = trans.GetRotation();
//if (RotationMode == BMM_Additive)
//{
//NewBoneTM.SetRotation(BoneQuat * NewBoneTM.GetRotation());
//} else
//{
NewBoneTM.SetRotation(BoneQuat);
//}
// Convert back to Component Space.
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, RotationSpace);
{
TArray<FBoneTransform> bt;
bt.Add(FBoneTransform(CompactPoseBoneToModify, NewBoneTM));
const float BlendWeight = FMath::Clamp<float>(ActualAlpha, 0.f, 1.f);
Output.Pose.LocalBlendCSBoneTransforms(bt, BlendWeight);
}
//OutBoneTransforms.Add(FBoneTransform(CompactPoseBoneToModify, NewBoneTM));
}
if (0) {
for (int boneNo = 0; boneNo < Transform_hum.Num(); ++boneNo) {
if (boneNo >= a.Num()) {
continue;
}
auto boneName = table.Find(a[boneNo]);
if (boneName == nullptr) {
continue;
}
int32 boneIndex = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton().FindBoneIndex(**boneName);
if (boneIndex < 0) {
continue;
}
auto rot = Transform_hum[boneNo].GetRotation();
const FCompactPoseBoneIndex CompactPoseBoneToModify(boneIndex);
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(CompactPoseBoneToModify);
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
const FTransform orgTM = NewBoneTM;
// Convert to Bone Space.
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, RotationSpace);
//const FQuat BoneQuat(Rotation);
const FQuat BoneQuat = rot;
//if (RotationMode == BMM_Additive)
//{
//NewBoneTM.SetRotation(BoneQuat * NewBoneTM.GetRotation());
//} else
//{
NewBoneTM.SetRotation(BoneQuat);
//}
// Convert back to Component Space.
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, RotationSpace);
{
TArray<FBoneTransform> bt;
bt.Add(FBoneTransform(CompactPoseBoneToModify, NewBoneTM));
const float BlendWeight = FMath::Clamp<float>(ActualAlpha, 0.f, 1.f);
Output.Pose.LocalBlendCSBoneTransforms(bt, BlendWeight);
}
//OutBoneTransforms.Add(FBoneTransform(CompactPoseBoneToModify, NewBoneTM));
}
}
//OutBoneTransforms.Sort(FCompareBoneTransformIndex());
}
bool FAnimNode_VrmModifyHumanoidBone::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmModifyHumanoidBone::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
@@ -0,0 +1,104 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmPoseBlendNode.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "DrawDebugHelpers.h"
#include "VrmMetaObject.h"
#include "VrmAssetListObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmPoseBlendNode::FAnimNode_VrmPoseBlendNode() {
}
void FAnimNode_VrmPoseBlendNode::Initialize_AnyThread(const FAnimationInitializeContext& Context) {
bCallInitialized = true;
if (EnableAutoSearchMetaData) {
auto v = VRMUtil::GetAssetListObject(VRMGetSkinnedAsset(Context.AnimInstanceProxy->GetSkelMeshComponent()));
if (v) {
PoseAsset = v->PoseFace;
//SetPoseAsset(v->PoseFace);
}
}
Super::Initialize_AnyThread(Context);
}
void FAnimNode_VrmPoseBlendNode::Evaluate_AnyThread(FPoseContext& Output) {
Super::Evaluate_AnyThread(Output);
if (bRemovePoseCurve) {
auto* sk = VRMGetSkinnedAsset(Output.AnimInstanceProxy->GetSkelMeshComponent());
#if UE_VERSION_OLDER_THAN(5,0,0)
#elif UE_VERSION_OLDER_THAN(5,3,0)
auto& MorphList = sk->GetMorphTargets();
TArray<SmartName::UID_Type> removeList;
auto* k = sk->GetSkeleton();
auto CurveList = k->GetDefaultCurveUIDList();
//k->AddSmartNameAndModify(USkeleton::AnimCurveMappingName, *p.expressionName, sm);
auto* CurveMappingPtr = k->GetSmartNameContainer(USkeleton::AnimCurveMappingName);
//
TArray<FName> nameList;
CurveMappingPtr->FillUIDToNameArray(nameList);
TArray<SmartName::UID_Type> uidList;
CurveMappingPtr->FillUidArray(uidList);
for (int i = 0; i < nameList.Num(); ++i) {
auto* ind = MorphList.FindByPredicate([&nameList, &i](const TObjectPtr<UMorphTarget > morph) {
if (morph->GetName().Compare(nameList[i].ToString())) return false;
return true;
});
if (ind == nullptr) {
removeList.Add(uidList[i]);
}
}
#else
auto& MorphList = sk->GetMorphTargets();
TArray<FName> removeList;
Output.Curve.ForEachElement([&removeList, &MorphList](const UE::Anim::FCurveElement& InCurveElement)
{
FString CurveElementName = InCurveElement.Name.ToString();
auto* ind = MorphList.FindByPredicate([&CurveElementName](const TObjectPtr<UMorphTarget > morph) {
if (CurveElementName.Compare(morph->GetName(), ESearchCase::IgnoreCase) == 0) return true;
return false;
});
if (ind == nullptr) {
removeList.Add(InCurveElement.Name);
}
});
#endif
#if UE_VERSION_OLDER_THAN(5,0,0)
#elif UE_VERSION_OLDER_THAN(5,1,0)
for (auto a : removeList) {
Output.Curve.Set(a, 0);
}
#else
for (auto a : removeList) {
Output.Curve.InvalidateCurveWeight(a);
}
#endif
}
}
@@ -0,0 +1,300 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmQuestHandBone.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "BonePose.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
namespace {
/*
typedef enum ovrpBoneId_ {
ovrpBoneId_Invalid = -1,
ovrpBoneId_Hand_Start = 0,
ovrpBoneId_Hand_WristRoot = ovrpBoneId_Hand_Start + 0, // root frame of the hand, where the wrist is located
ovrpBoneId_Hand_ForearmStub = ovrpBoneId_Hand_Start + 1, // frame for user's forearm
ovrpBoneId_Hand_Thumb0 = ovrpBoneId_Hand_Start + 2, // thumb trapezium bone
ovrpBoneId_Hand_Thumb1 = ovrpBoneId_Hand_Start + 3, // thumb metacarpal bone
ovrpBoneId_Hand_Thumb2 = ovrpBoneId_Hand_Start + 4, // thumb proximal phalange bone
ovrpBoneId_Hand_Thumb3 = ovrpBoneId_Hand_Start + 5, // thumb distal phalange bone
ovrpBoneId_Hand_Index1 = ovrpBoneId_Hand_Start + 6, // index proximal phalange bone
ovrpBoneId_Hand_Index2 = ovrpBoneId_Hand_Start + 7, // index intermediate phalange bone
ovrpBoneId_Hand_Index3 = ovrpBoneId_Hand_Start + 8, // index distal phalange bone
ovrpBoneId_Hand_Middle1 = ovrpBoneId_Hand_Start + 9, // middle proximal phalange bone
ovrpBoneId_Hand_Middle2 = ovrpBoneId_Hand_Start + 10, // middle intermediate phalange bone
ovrpBoneId_Hand_Middle3 = ovrpBoneId_Hand_Start + 11, // middle distal phalange bone
ovrpBoneId_Hand_Ring1 = ovrpBoneId_Hand_Start + 12, // ring proximal phalange bone
ovrpBoneId_Hand_Ring2 = ovrpBoneId_Hand_Start + 13, // ring intermediate phalange bone
ovrpBoneId_Hand_Ring3 = ovrpBoneId_Hand_Start + 14, // ring distal phalange bone
ovrpBoneId_Hand_Pinky0 = ovrpBoneId_Hand_Start + 15, // pinky metacarpal bone
ovrpBoneId_Hand_Pinky1 = ovrpBoneId_Hand_Start + 16, // pinky proximal phalange bone
ovrpBoneId_Hand_Pinky2 = ovrpBoneId_Hand_Start + 17, // pinky intermediate phalange bone
ovrpBoneId_Hand_Pinky3 = ovrpBoneId_Hand_Start + 18, // pinky distal phalange bone
ovrpBoneId_Hand_MaxSkinnable = ovrpBoneId_Hand_Start + 19,
// Bone tips are position only. They are not used for skinning but useful for hit-testing.
// NOTE: ovrBoneId_Hand_ThumbTip == ovrBoneId_Hand_MaxSkinnable since the extended tips need to be contiguous
ovrpBoneId_Hand_ThumbTip = ovrpBoneId_Hand_Start + ovrpBoneId_Hand_MaxSkinnable + 0, // tip of the thumb
ovrpBoneId_Hand_IndexTip = ovrpBoneId_Hand_Start + ovrpBoneId_Hand_MaxSkinnable + 1, // tip of the index finger
ovrpBoneId_Hand_MiddleTip = ovrpBoneId_Hand_Start + ovrpBoneId_Hand_MaxSkinnable + 2, // tip of the middle finger
ovrpBoneId_Hand_RingTip = ovrpBoneId_Hand_Start + ovrpBoneId_Hand_MaxSkinnable + 3, // tip of the ring finger
ovrpBoneId_Hand_PinkyTip = ovrpBoneId_Hand_Start + ovrpBoneId_Hand_MaxSkinnable + 4, // tip of the pinky
ovrpBoneId_Hand_End = ovrpBoneId_Hand_Start + ovrpBoneId_Hand_MaxSkinnable + 5,
// add other skeleton bone definitions here...
ovrpBoneId_Max = ovrpBoneId_Hand_End,
ovrpBoneId_EnumSize = 0x7fff
} ovrpBoneId;
*/
const TArray<VRMUtil::VRMBoneTable> handtable_l_ue4_vrm = {
{"Hand_L","leftHand"}, // +0
{"lowerarm_l","----"}, //{"lowerarm_l","leftLowerArm"},
{"thumb_03_l","----"},
{"thumb_01_l","leftThumbProximal"},
{"thumb_02_l","leftThumbIntermediate"},
{"thumb_03_l","leftThumbDistal"},
{"index_01_l","leftIndexProximal"}, // +6
{"index_02_l","leftIndexIntermediate"},
{"index_03_l","leftIndexDistal"},
{"middle_01_l","leftMiddleProximal"},
{"middle_02_l","leftMiddleIntermediate"},
{"middle_03_l","leftMiddleDistal"},
{"ring_01_l","leftRingProximal"},
{"ring_02_l","leftRingIntermediate"},
{"ring_03_l","leftRingDistal"},
{"pinky_03_l","----"},
{"pinky_01_l","leftLittleProximal"},
{"pinky_02_l","leftLittleIntermediate"},
{"pinky_03_l","leftLittleDistal"},
};
const TArray<VRMUtil::VRMBoneTable> handtable_r_ue4_vrm = {
{"Hand_R", "rightHand"}, // +0
{"lowerarm_r","----"}, //{"lowerarm_r","rightLowerArm"},
{"lowerarm_r","----"},
{ "thumb_01_r","rightThumbProximal" },
{ "thumb_02_r","rightThumbIntermediate" },
{ "thumb_03_r","rightThumbDistal" },
{ "index_01_r","rightIndexProximal" }, // +6
{ "index_02_r","rightIndexIntermediate" },
{ "index_03_r","rightIndexDistal" },
{ "middle_01_r","rightMiddleProximal" },
{ "middle_02_r","rightMiddleIntermediate" },
{ "middle_03_r","rightMiddleDistal" },
{ "ring_01_r","rightRingProximal" },
{ "ring_02_r","rightRingIntermediate" },
{ "ring_03_r","rightRingDistal" },
{ "pinky_01_r","----" },
{ "pinky_01_r","rightLittleProximal" },
{ "pinky_02_r","rightLittleIntermediate" },
{ "pinky_03_r","rightLittleDistal" },
};
/*
{"lowerarm_twist_01_l",""},
{"upperarm_twist_01_l",""},
{"clavicle_r","rightShoulder"},
{"UpperArm_R","rightUpperArm"},
{"lowerarm_r","rightLowerArm"},
{"Hand_R","rightHand"},
{"index_01_r","rightIndexProximal"},
{"index_02_r","rightIndexIntermediate"},
{"index_03_r","rightIndexDistal"},
{"middle_01_r","rightMiddleProximal"},
{"middle_02_r","rightMiddleIntermediate"},
{"middle_03_r","rightMiddleDistal"},
{"pinky_01_r","rightLittleProximal"},
{"pinky_02_r","rightLittleIntermediate"},
{"pinky_03_r","rightLittleDistal"},
{"ring_01_r","rightRingProximal"},
{"ring_02_r","rightRingIntermediate"},
{"ring_03_r","rightRingDistal"},
{"thumb_01_r","rightThumbProximal"},
{"thumb_02_r","rightThumbIntermediate"},
{"thumb_03_r","rightThumbDistal"},
{"lowerarm_twist_01_r",""},
{"upperarm_twist_01_r",""},
{"neck_01","neck"},
{"head","head"},
{"Thigh_L","leftUpperLeg"},
{"calf_l","leftLowerLeg"},
{"calf_twist_01_l",""},
{"Foot_L","leftFoot"},
{"ball_l","leftToes"},
{"thigh_twist_01_l",""},
{"Thigh_R","rightUpperLeg"},
{"calf_r","rightLowerLeg"},
{"calf_twist_01_r",""},
{"Foot_R","rightFoot"},
{"ball_r","rightToes"},
{"thigh_twist_01_r",""},
{"ik_foot_root",""},
{"ik_foot_l",""},
{"ik_foot_r",""},
{"ik_hand_root",""},
*/
}
FAnimNode_VrmQuestHandBone::FAnimNode_VrmQuestHandBone()
{
}
void FAnimNode_VrmQuestHandBone::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmQuestHandBone::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
if (VrmMetaObject == nullptr){
return;
}
if (HandTransform.HandLeft.Num() < 10 || HandReferenceTransform.HandLeft.Num() < 10) {
return;
}
if (HandTransform.HandRight.Num() < 10 || HandReferenceTransform.HandRight.Num() < 10) {
return;
}
check(OutBoneTransforms.Num() == 0);
// the way we apply transform is same as FMatrix or FTransform
// we apply scale first, and rotation, and translation
// if you'd like to translate first, you'll need two nodes that first node does translate and second nodes to rotate.
const FBoneContainer& BoneContainer = Output.Pose.GetPose().GetBoneContainer();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
const TArray<VRMUtil::VRMBoneTable>* handTable[2] = {
&handtable_l_ue4_vrm,
&handtable_r_ue4_vrm,
};
const TArray<FTransform>* handTrans[2] = {
&HandTransform.HandLeft,
&HandTransform.HandRight,
};
const TArray<FTransform>* handRefTrans[2] = {
&HandReferenceTransform.HandLeft,
&HandReferenceTransform.HandRight,
};
for (int side = 0; side < 2; ++side) {
for (int boneNo = 0; boneNo < handTable[side]->Num(); ++boneNo) {
FString* boneName = VrmMetaObject->humanoidBoneTable.Find((*handTable[side])[boneNo].BoneVRM);
if (boneName == nullptr) {
continue;
}
int32_t boneIndex = BoneContainer.GetPoseBoneIndexForBoneName(**boneName);
if (boneIndex == INDEX_NONE) {
continue;
}
FCompactPoseBoneIndex CompactPoseBoneToModify(boneIndex);// = BoneContainer.GetCompactPoseIndexFromSkeletonIndex(boneIndex);
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(CompactPoseBoneToModify);
FTransform orgBoneTM = NewBoneTM;
// Convert to Bone Space.
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, EBoneControlSpace::BCS_WorldSpace);
FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, orgBoneTM, CompactPoseBoneToModify, EBoneControlSpace::BCS_ParentBoneSpace);
// HandLeft[i].GetRotation();
//NewBoneTM = HandTransform.HandLeft[i];// .SetRotation(BoneQuat);
FQuat q;
{
FQuat q_baseOffset;
if (side == 0) {
q_baseOffset = FRotator(0, 90, 180).Quaternion();
} else {
q_baseOffset = FRotator(0, 90, 0).Quaternion();
}
// correct base
{
q = (*handTrans[side])[boneNo].GetRotation() * q_baseOffset;
}
}
if (3<=boneNo && boneNo<=5){
//thumb
FQuat q_baseOffset;
if (side == 0) {
q_baseOffset = FRotator(0, 115, 0).Quaternion();
} else {
q_baseOffset = FRotator(-65, 0, 90).Quaternion();
}
//thumb
auto q2 = (*handRefTrans[side])[boneNo].GetRotation() *q_baseOffset;
q = q * q2.Inverse();
}
//for ref test
//q = HandReferenceTransform.HandLeft[i].GetRotation() * q;
if (boneNo > 0) {
{
//auto r = fromParentTM.GetRotation();
//q = r.Inverse() * q * r; // wrong
//q = r * q * r.Inverse();
}
//q = orgBoneTM.GetRotation() * q;
//auto ref = (*handRefTrans[side])[boneNo].GetRotation().Inverse();
//auto ref = HandReferenceTransform.HandLeft[boneNo].GetRotation().Inverse();
//q = ref * q;
}
//NewBoneTM.SetLocation(HandTransform.HandLeft[i].GetLocation()*100.f);
NewBoneTM.SetRotation(q);// .SetRotation(BoneQuat);
//NewBoneTM.SetRotation(HandTransform.HandLeft[i].GetRotation());// .SetRotation(BoneQuat);
// Convert back to Component Space.
//FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, EBoneControlSpace::BCS_ParentBoneSpace);
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, NewBoneTM, CompactPoseBoneToModify, EBoneControlSpace::BCS_WorldSpace);
OutBoneTransforms.Add(FBoneTransform(CompactPoseBoneToModify, NewBoneTM));
}
}
OutBoneTransforms.Sort(FCompareBoneTransformIndex());
}
bool FAnimNode_VrmQuestHandBone::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmQuestHandBone::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
@@ -0,0 +1,383 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmRetargetFromMannequin.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstance.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "DrawDebugHelpers.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmRetargetFromMannequin::FAnimNode_VrmRetargetFromMannequin() {
}
void FAnimNode_VrmRetargetFromMannequin::PreUpdate(const UAnimInstance* InAnimInstance)
{
//DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(PreUpdate)
Super::PreUpdate(InAnimInstance);
//FAnimNode_RetargetPoseFromMesh::EnsureInitialized
// if user hasn't explicitly connected a source mesh, optionally use the parent mesh component (if there is one)
if (!srcMannequinMesh.IsValid() && bUseAttachedParent)
{
USkeletalMeshComponent* TargetMesh = InAnimInstance->GetSkelMeshComponent();
// Walk up the attachment chain until we find a skeletal mesh component
USkeletalMeshComponent* ParentMeshComponent = nullptr;
for (USceneComponent* AttachParentComp = TargetMesh->GetAttachParent(); AttachParentComp != nullptr; AttachParentComp = AttachParentComp->GetAttachParent())
{
ParentMeshComponent = Cast<USkeletalMeshComponent>(AttachParentComp);
if (ParentMeshComponent)
{
break;
}
}
if (ParentMeshComponent == nullptr) {
AActor *targetActor = nullptr;
AActor *myActor = TargetMesh->GetOwner();
for (USceneComponent* AttachParentComp = TargetMesh->GetAttachParent(); AttachParentComp != nullptr; AttachParentComp = AttachParentComp->GetAttachParent()) {
targetActor = AttachParentComp->GetOwner();
if (targetActor != myActor) {
break;
}
targetActor = nullptr;
}
if (targetActor) {
TArray<USkeletalMeshComponent*> c;
targetActor->GetComponents<USkeletalMeshComponent>(c);
if (c.IsValidIndex(0)) {
ParentMeshComponent = c[0];
}
}
}
if (ParentMeshComponent)
{
srcMannequinMesh = ParentMeshComponent;
}
}
}
void FAnimNode_VrmRetargetFromMannequin::UpdateCache(FComponentSpacePoseContext& Output) {
if (srcMannequinMesh == nullptr){
srcSkeletalMesh = nullptr;
return;
}
if (srcSkeletalMesh == VRMGetSkeletalMeshAsset(srcMannequinMesh)) {
return;
}
srcSkeletalMesh = VRMGetSkeletalMeshAsset(srcMannequinMesh);
if (srcSkeletalMesh == nullptr) return;
if (dstSkeletalMesh == nullptr) return;
auto& srcRefSkeleton = VRMGetRefSkeleton(srcSkeletalMesh);
auto& dstRefSkeleton = VRMGetRefSkeleton(dstSkeletalMesh);
// ref pose
const auto& srcRefSkeletonTransform = srcRefSkeleton.GetRefBonePose();
const auto& dstRefSkeletonTransform = dstRefSkeleton.GetRefBonePose();
// ref component
srcRefSkeletonCompTransform = srcRefSkeletonTransform;
dstRefSkeletonCompTransform = dstRefSkeletonTransform;
for (int i = 1; i < srcRefSkeletonCompTransform.Num(); ++i) {
int parent = srcRefSkeleton.GetParentIndex(i);
srcRefSkeletonCompTransform[i] *= srcRefSkeletonCompTransform[parent];
}
for (int i = 1; i < dstRefSkeletonCompTransform.Num(); ++i) {
int parent = dstRefSkeleton.GetParentIndex(i);
dstRefSkeletonCompTransform[i] *= dstRefSkeletonCompTransform[parent];
}
// current A-pose compTransform
dstCurrentSkeletonCompTransform = dstRefSkeletonTransform;
for (int i = 0; i < dstRefSkeletonCompTransform.Num(); ++i) {
FCompactPoseBoneIndex ii(i);
auto t = Output.Pose.GetLocalSpaceTransform(ii);
if (i == 0) {
dstCurrentSkeletonCompTransform[i] = t;
} else {
int parent = dstRefSkeleton.GetParentIndex(i);
dstCurrentSkeletonCompTransform[i] = t * dstCurrentSkeletonCompTransform[parent];
}
}
}
void FAnimNode_VrmRetargetFromMannequin::Initialize_AnyThread(const FAnimationInitializeContext& Context) {
Super::Initialize_AnyThread(Context);
dstSkeletalMesh = nullptr;
srcSkeletalMesh = nullptr;
if (Context.AnimInstanceProxy == nullptr) return;
if (Context.AnimInstanceProxy->GetSkelMeshComponent() == nullptr) return;
dstSkeletalMesh = VRMGetSkinnedAsset(Context.AnimInstanceProxy->GetSkelMeshComponent());
srcSkeletalMesh = nullptr;
}
void FAnimNode_VrmRetargetFromMannequin::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {
Super::CacheBones_AnyThread(Context);
}
#if UE_VERSION_OLDER_THAN(4,20,0)
#else
void FAnimNode_VrmRetargetFromMannequin::ResetDynamics(ETeleportType InTeleportType) {
Super::ResetDynamics(InTeleportType);
}
#endif
void FAnimNode_VrmRetargetFromMannequin::UpdateInternal(const FAnimationUpdateContext& Context){
Super::UpdateInternal(Context);
}
void FAnimNode_VrmRetargetFromMannequin::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmRetargetFromMannequin::EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) {
Super::EvaluateComponentPose_AnyThread(Output);
}
void FAnimNode_VrmRetargetFromMannequin::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
UpdateCache(Output);
if (srcSkeletalMesh == nullptr) return;
if (dstSkeletalMesh == nullptr) return;
const UVrmMetaObject* dstMeta = VrmMetaObject;
if (dstMeta == nullptr) {
return;
}
auto srcSkeletalMeshComp = Cast<USkeletalMeshComponent>(srcMannequinMesh);
auto srcAsSkinnedMeshComp = srcMannequinMesh;
if (srcAsSkinnedMeshComp == nullptr) {
return;
}
auto &srcRefSkeleton = VRMGetRefSkeleton(VRMGetSkeletalMeshAsset(srcAsSkinnedMeshComp) );
auto &dstRefSkeleton = VRMGetRefSkeleton(VRMGetSkeletalMeshAsset(Output.AnimInstanceProxy->GetSkelMeshComponent()) );
// ref pose
const auto& dstRefSkeletonTransform = dstRefSkeleton.GetRefBonePose();
const auto& srcRefSkeletonTransform = srcRefSkeleton.GetRefBonePose();
const TArray<FString>* SrcBoneList = &VRMUtil::vrm_humanoid_bone_list;
// is ue5 mannequin remap
enum class RemapType {
E_None,
E_UpperChest,
E_Chest,
};
RemapType remapType = RemapType::E_None;
{
bool bUE5Mannequin = false;
for (int i = 1; i <= 5; ++i) {
int index = srcAsSkinnedMeshComp->GetBoneIndex(*(FString(TEXT("spine_0"))+FString::FromInt(i)));
if (index == INDEX_NONE) {
break;
}
if (i == 5) {
bUE5Mannequin = true;
}
}
if (bUE5Mannequin) {
TArray<FString>table = { TEXT("spine"), TEXT("chest"), TEXT("upperChest") };
bool b[3] = {false, false, false};
for (int i = 0; i < 3; ++i) {
auto* a = dstMeta->humanoidBoneTable.Find(*table[i]);
if (a && (*a) != "") {
b[i] = true;
}
}
if (b[0] && b[1] && b[2]) {
remapType = RemapType::E_UpperChest;
}
if (b[0] && b[1] && b[2]==false) {
remapType = RemapType::E_Chest;
}
}
}
int BoneCount = 0;
for (const auto& humanoidName : VRMUtil::vrm_humanoid_bone_list) {
FName srcName, dstName;
srcName = dstName = NAME_None;
++BoneCount;
{
for (auto& bonemap : VRMUtil::table_ue4_vrm) {
if (bonemap.BoneVRM == humanoidName) {
srcName = *bonemap.BoneUE4;
// replace src bone name by srcMeta object
if (MannequinVrmMetaObject) {
auto *p = MannequinVrmMetaObject->humanoidBoneTable.Find(bonemap.BoneVRM);
if (p) {
srcName = **p;
}
}
break;
}
}
}
if (srcName == NAME_None) {
continue;
}
switch (remapType) {
case RemapType::E_UpperChest:
if (humanoidName == TEXT("upperChest")) {
srcName = TEXT("spine_05");
}
if (humanoidName == TEXT("chest")) {
srcName = TEXT("spine_03");
//3,4
}
if (humanoidName == TEXT("spine")) {
srcName = TEXT("spine_01");
//1,2
}
break;
case RemapType::E_Chest:
if (humanoidName == TEXT("chest")) {
srcName = TEXT("spine_05");
}
if (humanoidName == TEXT("spine")) {
srcName = TEXT("spine_01");
}
break;
}
{
auto a = dstMeta->humanoidBoneTable.Find(humanoidName);
if (a) {
dstName = **a;
}
}
if (dstName == NAME_None) {
continue;
}
auto dstIndex = Output.AnimInstanceProxy->GetSkelMeshComponent()->GetBoneIndex(dstName);
if (dstIndex < 0) {
continue;
}
auto srcIndex = srcAsSkinnedMeshComp->GetBoneIndex(srcName);
if (srcIndex < 0) {
continue;
}
FCompactPoseBoneIndex srcPoseBoneIndex(srcIndex);
FCompactPoseBoneIndex dstPoseBoneIndex(dstIndex);
const auto srcCurrentTrans = srcAsSkinnedMeshComp->GetSocketTransform(srcName, RTS_Component);
auto modelBone = srcCurrentTrans;
{
{
if (bIgnoreCenterLocation) {
modelBone.SetLocation(CenterLocationOffset);
} else {
auto dd = Output.Pose.GetComponentSpaceTransform(dstPoseBoneIndex);
modelBone.SetLocation(dd.GetLocation());
if (BoneCount == 1) {
// RootBone transform
float s = dd.GetLocation().Z / FMath::Max(1.0f, srcRefSkeletonCompTransform[srcIndex].GetLocation().Z);
#if UE_VERSION_OLDER_THAN(4,24,0)
FVector ComponentScale = Output.AnimInstanceProxy->GetSkelMeshComponent()->RelativeScale3D;
#else
FVector ComponentScale = Output.AnimInstanceProxy->GetSkelMeshComponent()->GetRelativeScale3D();
#endif
if (ComponentScale.X == 0.f) {
ComponentScale.X = 0.001f;
}
if (ComponentScale.Y == 0.f) {
ComponentScale.Y = 0.001f;
}
if (ComponentScale.Z == 0.f) {
ComponentScale.Z = 0.001f;
}
modelBone.SetLocation(
FMath::Lerp(
srcCurrentTrans.GetLocation(), // original location
srcCurrentTrans.GetLocation() * s, // scled by height
CenterLocationScaleByHeightScale)
/ ComponentScale // inv model scale
+ CenterLocationOffset
);
} // RootBone transform
}
}
modelBone.SetRotation(
srcCurrentTrans.GetRotation()
* srcRefSkeletonCompTransform[srcIndex].GetRotation().Inverse()
* dstCurrentSkeletonCompTransform[dstIndex].GetRotation()
);
Output.Pose.SetComponentSpaceTransform(dstPoseBoneIndex, modelBone);
}
}
}
bool FAnimNode_VrmRetargetFromMannequin::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmRetargetFromMannequin::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
void FAnimNode_VrmRetargetFromMannequin::ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground) const
{
#if WITH_EDITOR
if (VrmMetaObject == nullptr || PreviewSkelMeshComp == nullptr) {
return;
}
if (PreviewSkelMeshComp->GetWorld() == nullptr) {
return;
}
#endif
}
@@ -0,0 +1,464 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
/*
// VRMSpringBone.cs
MIT License
Copyright (c) 2018 DWANGO Co., Ltd. for UniVRM
Copyright (c) 2018 ousttrue for UniGLTF, UniHumanoid
Copyright (c) 2018 Masataka SUMI for MToon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "AnimNode_VrmSpringBone.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "SceneInterface.h"
#include "DrawDebugHelpers.h"
#include "VrmMetaObject.h"
#include "VrmAssetListObject.h"
#include "VrmUtil.h"
#include "VrmSpringBone.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmSpringBone::FAnimNode_VrmSpringBone()
{
NoWindBoneNameList = TArray<FName>{
TEXT("J_Sec_L_Bust1"),
TEXT("J_Sec_L_Bust2"),
TEXT("J_Sec_R_Bust1"),
TEXT("J_Sec_R_Bust2"),
};
}
//void FAnimNode_VrmSpringBone::Update_AnyThread(const FAnimationUpdateContext& Context) {
// Super::Update_AnyThread(Context);
// //Context.GetDeltaTime();
//}
bool FAnimNode_VrmSpringBone::IsSpringInit() const {
if (SpringManager.Get()) {
return SpringManager->bInit;
}
return false;
}
void FAnimNode_VrmSpringBone::Initialize_AnyThread(const FAnimationInitializeContext& Context) {
Super::Initialize_AnyThread(Context);
if (Context.AnimInstanceProxy == nullptr) return;
VrmMetaObject_Internal = const_cast<UVrmMetaObject*>(VrmMetaObject);
if (VrmMetaObject_Internal == nullptr && EnableAutoSearchMetaData) {
VrmAssetListObject_Internal = VRMUtil::GetAssetListObject(VRMGetSkinnedAsset(Context.AnimInstanceProxy->GetSkelMeshComponent()));
if (VrmAssetListObject_Internal) {
VrmMetaObject_Internal = VrmAssetListObject_Internal->VrmMetaObject;
}
}
if (SpringManager.Get()) {
SpringManager.Get()->reset();
} else {
if (VrmMetaObject_Internal) {
if (VrmMetaObject_Internal->GetVRMVersion() >= 1) {
SpringManager = MakeShareable(new VRM1Spring::VRM1SpringManager());
}
}
if (SpringManager.IsValid() == false) {
SpringManager = MakeShareable(new VRMSpringBone::VRMSpringManager());
}
if (SpringManager.Get()) {
}
}
}
void FAnimNode_VrmSpringBone::Initialize_AnyThread_local(const FAnimationInitializeContext& Context) {
{
//Super::Initialize_AnyThread(Context); crash
//FAnimNode_SkeletalControlBase::Initialize_AnyThread
FAnimNode_Base::Initialize_AnyThread(Context);
//ComponentPose.Initialize(Context);
AlphaBoolBlend.Reinitialize();
AlphaScaleBiasClamp.Reinitialize();
}
if (SpringManager.Get()) {
SpringManager.Get()->reset();
}
else {
if (VrmMetaObject_Internal) {
if (VrmMetaObject_Internal->GetVRMVersion() >= 1) {
SpringManager = MakeShareable(new VRM1Spring::VRM1SpringManager());
}
}
if (SpringManager.IsValid() == false) {
SpringManager = MakeShareable(new VRMSpringBone::VRMSpringManager());
}
}
}
void FAnimNode_VrmSpringBone::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {
Super::CacheBones_AnyThread(Context);
}
#if UE_VERSION_OLDER_THAN(4,20,0)
#else
void FAnimNode_VrmSpringBone::ResetDynamics(ETeleportType InTeleportType) {
Super::ResetDynamics(InTeleportType);
if (SpringManager.Get()){
bool bReset = true;
if (InTeleportType == ETeleportType::TeleportPhysics) {
if (bIgnorePhysicsResetOnTeleport) {
bReset = false;
}
}
if (bReset) {
SpringManager.Get()->reset();
}
}
}
#endif
void FAnimNode_VrmSpringBone::UpdateInternal(const FAnimationUpdateContext& Context){
Super::UpdateInternal(Context);
CurrentDeltaTime = Context.GetDeltaTime();
}
void FAnimNode_VrmSpringBone::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmSpringBone::EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) {
if (bCallByAnimInstance) {
ActualAlpha = 1.f;
/*
EvaluateComponentSpaceInternal(Output);
BoneTransformsSpring.Reset(BoneTransformsSpring.Num());
EvaluateSkeletalControl_AnyThread(Output, BoneTransformsSpring);
if (BoneTransformsSpring.Num() > 0)
{
ActualAlpha = 1.f;
const float BlendWeight = FMath::Clamp<float>(ActualAlpha, 0.f, 1.f);
Output.Pose.LocalBlendCSBoneTransforms(BoneTransformsSpring, BlendWeight);
}
*/
}
else {
Super::EvaluateComponentPose_AnyThread(Output);
}
}
void FAnimNode_VrmSpringBone::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
//dstRefSkeleton.GetParentIndex
//auto BoneSpace = EBoneControlSpace::BCS_ParentBoneSpace;
auto BoneSpace = EBoneControlSpace::BCS_WorldSpace;
{
if (VrmMetaObject_Internal == nullptr) {
return;
}
if (VRMGetSkeleton(VrmMetaObject_Internal->SkeletalMesh) != Output.AnimInstanceProxy->GetSkeleton()) {
//skip for renamed bone
//return;
}
if (Output.Pose.GetPose().GetNumBones() <= 0) {
return;
}
const auto &RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
{
if (SpringManager.Get() == nullptr) {
return;
}
if (SpringManager->bInit == false) {
SpringManager->init(VrmMetaObject_Internal.Get(), Output);
return;
}
SpringManager->update(this, CurrentDeltaTime, Output, OutBoneTransforms);
SpringManager->applyToComponent(Output, OutBoneTransforms);
}
}
}
bool FAnimNode_VrmSpringBone::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmSpringBone::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
void FAnimNode_VrmSpringBone::ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground) const
{
#if WITH_EDITOR
auto MetaObjectLocal = VrmMetaObject_Internal;
if (MetaObjectLocal == nullptr && EnableAutoSearchMetaData) {
auto *p = VRMUtil::GetAssetListObject(VRMGetSkinnedAsset(PreviewSkelMeshComp));
if (p) {
MetaObjectLocal = p->VrmMetaObject;
}
}
if (MetaObjectLocal == nullptr || PreviewSkelMeshComp == nullptr) {
return;
}
if (PreviewSkelMeshComp->GetWorld() == nullptr) {
return;
}
ESceneDepthPriorityGroup Priority = SDPG_World;
if (bPreviewForeground) Priority = SDPG_Foreground;
if (MetaObjectLocal->VRM1SpringBoneMeta.Springs.Num() > 0) {
// vrm1
// col
for (const auto& c : MetaObjectLocal->VRM1SpringBoneMeta.Colliders) {
const FTransform t = PreviewSkelMeshComp->GetSocketTransform(*c.boneName);
float r = (c.radius) * 100.f;
auto offs = c.offset;
offs.Set(offs.X, -offs.Z, offs.Y);
offs *= 100;
offs = t.TransformVector(offs);
if (c.shapeType == TEXT("sphere")) {
FTransform tt = t;
tt.AddToTranslation(offs);
DrawWireSphere(PDI, tt, FLinearColor(1,1,0), r, 32, Priority);
}
else {
auto tail = c.tail;
tail.Set(tail.X, -tail.Z, tail.Y);
tail *= 100;
tail = t.TransformVector(tail);
FTransform t1 = t;
t1.AddToTranslation(offs);
FTransform t2 = t;
t2.AddToTranslation(tail);
if (0) {
// sphere and line
DrawWireSphere(PDI, t1, FLinearColor(1, 1, 1), r, 32, Priority);
DrawWireSphere(PDI, t2, FLinearColor::Green, r, 32, Priority);
PDI->DrawLine(
t1.GetLocation(),
t2.GetLocation(),
FLinearColor::Green,
Priority);
}
else {
// capsule
FVector center = (t1.GetLocation() + t2.GetLocation()) / 2.f;
FVector Up = (t1.GetLocation() - t2.GetLocation()).GetSafeNormal();
FVector Forward, Right;
Up.FindBestAxisVectors(Forward, Right);
const FVector X = (Forward);
const FVector Y = (Right);
const FVector Z = (Up);
float halfheight = (t1.GetLocation() - center).Size() + r;
DrawWireCapsule(PDI, center, X, Y, Z, FLinearColor::Green, r, halfheight, 32, Priority);
}
}
}
// spring col
for (int springNo = 0; springNo < MetaObjectLocal->VRM1SpringBoneMeta.Springs.Num(); ++springNo) {
const auto& s = MetaObjectLocal->VRM1SpringBoneMeta.Springs[springNo];
const TArray<FLinearColor> color = {
FLinearColor(1.f, 0, 0),
FLinearColor(1.f, 0.5, 0),
FLinearColor(1.f, 0, 0.5),
};
for (int jointNo = 0; jointNo < s.joints.Num()-1; ++jointNo) {
auto& j1 = s.joints[jointNo];
auto& j2 = s.joints[jointNo + 1];
const FTransform t = PreviewSkelMeshComp->GetSocketTransform(*j2.boneName);
float r = j1.hitRadius * 100.f;
DrawWireSphere(PDI, t.GetLocation(), color[springNo%color.Num()], r, 32, Priority);
const FTransform t2 = PreviewSkelMeshComp->GetSocketTransform(*j1.boneName);
PDI->DrawLine(
t.GetLocation(),
t2.GetLocation(),
color[springNo % color.Num()] / 2.f,
Priority);
}
}
}
// vrm0
for (const auto &colMeta : MetaObjectLocal->VRMColliderMeta) {
const FTransform t = PreviewSkelMeshComp->GetSocketTransform(*colMeta.boneName);
for (const auto &col : colMeta.collider) {
float r = (col.radius) * 100.f;
auto offs = col.offset;
//offs.Set(offs.X, -offs.Z, offs.Y); // 本来はこれが正しいが、VRM0の座標が間違っている
offs.Set(-offs.X, offs.Z, offs.Y); // VRM0の仕様としては これ
offs *= 100;
FVector v = t.TransformPosition(offs);
FTransform tt = t;
tt.AddToTranslation(offs);
DrawWireSphere(PDI, tt, FLinearColor::Green, r, 32, Priority);
}
}
{
struct SData{
int32 bone = 0;
float radius = 0.f;
bool operator==(const SData& a) const {
return (bone == a.bone && radius == a.radius);
}
};
TArray<SData> dataList;
TArray<int32> boneList;
for (const auto &spr : MetaObjectLocal->VRMSpringMeta) {
for (const auto &boneName : spr.boneNames) {
int32_t boneIndex = PreviewSkelMeshComp->GetBoneIndex(*boneName);
boneList.AddUnique(boneIndex);
{
SData s;
s.bone = boneIndex;
s.radius = spr.hitRadius;
dataList.AddUnique(s);
}
for (int i = 0; i < boneList.Num(); ++i) {
TArray<int32> c;
VRMUtil::GetDirectChildBones(VRMGetRefSkeleton( VRMGetSkinnedAsset(PreviewSkelMeshComp) ), boneList[i], c);
if (c.Num()) {
for (const auto &cc : c) {
boneList.AddUnique(cc);
SData s;
s.bone = cc;
s.radius = spr.hitRadius;
dataList.AddUnique(s);
}
}
}
}
}
const auto &RefBonePose = VRMGetRefSkeleton(VRMGetSkinnedAsset(PreviewSkelMeshComp)).GetRefBonePose();
for (int i = 0; i < dataList.Num(); ++i) {
FTransform t;
{
TArray<int32> c;
VRMUtil::GetDirectChildBones(VRMGetRefSkeleton(VRMGetSkinnedAsset(PreviewSkelMeshComp)), dataList[i].bone, c);
if (c.IsValidIndex(0)) {
const auto& name = PreviewSkelMeshComp->GetBoneName(c[0]);
t = PreviewSkelMeshComp->GetSocketTransform(name);
}
else {
const auto& name = PreviewSkelMeshComp->GetBoneName(dataList[i].bone);
t = PreviewSkelMeshComp->GetSocketTransform(name);
//t.SetLocation(t.GetLocation() * 1.7);
t.SetLocation(t.GetLocation() + RefBonePose[dataList[i].bone].GetLocation() * 0.7);
}
}
float r = dataList[i].radius * 100.f;
FVector v = t.GetLocation();
DrawWireSphere(PDI, t, FLinearColor::Red, r, 32, Priority);
}
}
if (PreviewSkelMeshComp && PreviewSkelMeshComp->GetWorld())
{
FVector const CSEffectorLocation = FVector(0, 0, 0);//CachedEffectorCSTransform.GetLocation();
FVector const Precision = FVector(1);//CachedEffectorCSTransform.GetLocation();
FTransform CachedEffectorCSTransform;
// Show end effector position.
//DrawDebugBox(PreviewSkelMeshComp->GetWorld(), CSEffectorLocation, FVector(Precision), FColor::Green, true, 0.1f);
//DrawDebugCoordinateSystem(PreviewSkelMeshComp->GetWorld(), CSEffectorLocation, CachedEffectorCSTransform.GetRotation().Rotator(), 5.f, true, 0.1f);
}
#endif
}
@@ -0,0 +1,307 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "RigUnit_VrmDynamicHierarchy.h"
#include "Engine/SkeletalMesh.h"
#include "Rigs/RigHierarchyController.h"
#include "Units/RigUnitContext.h"
#include "ControlRig.h"
#include "Components/SkeletalMeshComponent.h"
#include "VrmUtil.h"
#include "VrmAssetListObject.h"
#include "VrmMetaObject.h"
//#include "Units/Execution/RigUnit_PrepareForExecution.h"
//#include UE_INLINE_GENERATED_CPP_BY_NAME(RigUnit_DynamicHierarchy)
FRigUnit_VRMInitControllerTransform_Execute() {
const USkeletalMeshComponent* skc = ExecuteContext.UnitContext.DataSourceRegistry->RequestSource<USkeletalMeshComponent>(UControlRig::OwnerComponent);
if (skc == nullptr) return;
auto* sk = VRMGetSkeletalMeshAsset(skc);
if (sk == nullptr) return;
auto* k = sk->GetSkeleton();
if (k == nullptr) return;
URigHierarchyController* Controller = ExecuteContext.Hierarchy->GetController(true);
if (Controller == nullptr) return;
UVrmAssetListObject* assetList = VRMUtil::GetAssetListObject(sk);
if (assetList == nullptr) return;
//Controller->
TArray<FRigControlElement*> controlList = ExecuteContext.Hierarchy->GetControls();
TArray<FRigNullElement*> nullList = ExecuteContext.Hierarchy->GetNulls();
//contollerList[0]->GetNameString();
//ExecuteContext.Hierarchy->SetInitialGlobalTransform
//Controller
TMap<FRigElementKey, FTransform> elemInitTransformList;
for (auto& table : VRMUtil::table_ue4_vrm) {
auto* elem = nullList.FindByPredicate(
[&table](FRigNullElement* e) {
#if UE_VERSION_OLDER_THAN(5,4,0)
if (e->GetNameString().Compare(table.BoneUE4 + "_s") == 0) {
return true;
}
#else
if (e->GetName().Compare(table.BoneUE4 + "_s") == 0) {
return true;
}
#endif
return false;
});
if (elem == nullptr) continue;
FRigElementKey bone;
{
const auto& assetBoneTable = assetList->VrmMetaObject->humanoidBoneTable;
auto* str = assetBoneTable.Find(table.BoneVRM);
if (str == nullptr) continue;
bone.Type = ERigElementType::Bone;
bone.Name = *(*str);
}
FRigElementKey a;
a.Name = *(table.BoneUE4 + "_s");
a.Type = ERigElementType::Null;
auto index = k->GetReferenceSkeleton().FindBoneIndex(bone.Name);
auto refPose = k->GetReferenceSkeleton().GetRefBonePose();
elemInitTransformList.Add(a, refPose[index]);
}
for (auto& c : controlList) {
//ExecuteContext.Hierarchy->SetInitialLocalTransform(c->GetKey(), FTransform::Identity);
//ExecuteContext.Hierarchy->SetLocalTransform(c->GetKey(), FTransform::Identity);
}
for (auto& c : nullList) {
auto *f = elemInitTransformList.Find(c->GetKey());
if (f) {
ExecuteContext.Hierarchy->SetInitialGlobalTransform(c->GetKey(), *f);
ExecuteContext.Hierarchy->SetLocalTransform(c->GetKey(), *f);
} else {
ExecuteContext.Hierarchy->SetInitialLocalTransform(c->GetKey(), FTransform::Identity);
ExecuteContext.Hierarchy->SetLocalTransform(c->GetKey(), FTransform::Identity);
}
}
}
FRigUnit_VRMGenerateBoneToControlTable_Execute()
{
Items_MannequinBone.Empty();
//Items_MannequinControl.Empty();
Items_VRMBone.Empty();
const USkeletalMeshComponent* skc = ExecuteContext.UnitContext.DataSourceRegistry->RequestSource<USkeletalMeshComponent>(UControlRig::OwnerComponent);
if (skc == nullptr) return;
auto* sk = VRMGetSkeletalMeshAsset(skc);
if (sk == nullptr) return;
auto* k = sk->GetSkeleton();
if (k == nullptr) return;
URigHierarchyController* Controller = ExecuteContext.Hierarchy->GetController(true);
if (Controller == nullptr) return;
UVrmAssetListObject *assetList = VRMUtil::GetAssetListObject(sk);
if (assetList == nullptr) return;
//Controller->
TArray<FRigControlElement*> controllerList = ExecuteContext.Hierarchy->GetControls();
//contollerList[0]->GetNameString();
//ExecuteContext.Hierarchy->SetInitialGlobalTransform
//Controller
for (auto& table : VRMUtil::table_ue4_vrm) {
auto* elem = controllerList.FindByPredicate(
[&table](FRigControlElement* e) {
#if UE_VERSION_OLDER_THAN(5,4,0)
if (e->GetNameString().Compare(table.BoneUE4 + "_c") == 0) {
return true;
}
#else
if (e->GetName().Compare(table.BoneUE4 + "_c") == 0) {
return true;
}
#endif
return false;
});
if (elem == nullptr) continue;
FRigElementKey bone;
{
const auto& assetBoneTable = assetList->VrmMetaObject->humanoidBoneTable;
auto* str = assetBoneTable.Find(table.BoneVRM);
if (str == nullptr) continue;
bone.Type = ERigElementType::Bone;
bone.Name = *(*str);
Items_VRMBone.Add(*(*str));
}
{
FRigElementKey a;
a.Name = *(table.BoneUE4);
a.Type = ERigElementType::Control;
Items_MannequinBone.Add(*(table.BoneUE4));
}
{
FRigElementKey a;
a.Name = *(table.BoneUE4 + "_c");
a.Type = ERigElementType::Control;
//Items_MannequinControl.Add(a);
}
//Items_VRMBone.Add(bone);
}
}
FRigUnit_VRMGetCurveNameFromMesh_Execute() {
FString ErrorMessage;
Items_Curve.Reset();
Items_Morph.Reset();
const USkeletalMeshComponent* skc = ExecuteContext.UnitContext.DataSourceRegistry->RequestSource<USkeletalMeshComponent>(UControlRig::OwnerComponent);
if (skc == nullptr) return;
{
auto* sk = skc->GetSkinnedAsset();
auto* k = sk->GetSkeleton();
auto morph = sk->GetMorphTargets();
const FRigControlValue Value = FRigControlValue::Make<float>(0);
const FTransform ShapeTransform;
const FTransform OffsetTransform;
for (auto& a : morph) {
Items_Morph.Add(a.GetFName());
}
#if UE_VERSION_OLDER_THAN(5,3,0)
const FSmartNameMapping* CurveMapping = k->GetSmartNameContainer(USkeleton::AnimCurveMappingName);
if (CurveMapping) {
TArray<FName> CurveNames;
CurveMapping->FillNameArray(CurveNames);
for (const FName& CurveName : CurveNames) {
auto* meta = CurveMapping->GetCurveMetaData(CurveName);
if (meta->Type.bMorphtarget == true) {
continue;
}
Items_Curve.Add(CurveName);
}
}
#else
k->ForEachCurveMetaData([&](const FName& InCurveName, const FCurveMetaData& InMetaData)
{
if (InMetaData.Type.bMorphtarget == true) {
return;
}
Items_Curve.Add(InCurveName);
});
#endif
}
}
FRigUnit_VRMAddCurveFromMesh_Execute()
{
FString ErrorMessage;
Items_Curve.Reset();
Items_Morph.Reset();
const USkeletalMeshComponent* skc = ExecuteContext.UnitContext.DataSourceRegistry->RequestSource<USkeletalMeshComponent>(UControlRig::OwnerComponent);
if (skc == nullptr) return;
URigHierarchyController* Controller = ExecuteContext.Hierarchy->GetController(true);
if (Controller == nullptr) return;
FRigControlSettings ControlSettings;
ControlSettings.ControlType = ERigControlType::Float;
ControlSettings.PrimaryAxis = ERigControlAxis::X;
ControlSettings.MinimumValue = FRigControlValue::Make<float>(0);
ControlSettings.MaximumValue = FRigControlValue::Make<float>(1);
ControlSettings.SetupLimitArrayForType(true, true, true);
ControlSettings.SetVisible(false);
FRigHierarchyControllerInstructionBracket InstructionBracket(Controller, ExecuteContext.GetInstructionIndex());
{
auto *sk = skc->GetSkinnedAsset();
auto* k = sk->GetSkeleton();
auto morph = sk->GetMorphTargets();
const FRigControlValue Value = FRigControlValue::Make<float>(0);
const FTransform ShapeTransform;
const FTransform OffsetTransform;
if (bIncludeMorphs) {
auto root = Controller->AddNull(TEXT("VRM4U_Root_Morph"), FRigElementKey(), OffsetTransform);
for (auto& a : morph) {
FName n = *(Prefix + a.GetFName().ToString() + Suffix);
Items_Morph.Add(Controller->AddControl(n, root, ControlSettings, Value, OffsetTransform, ShapeTransform, false, false));
}
}
if (bIncludeCurves) {
auto root = Controller->AddNull(TEXT("VRM4U_Root_Curve"), FRigElementKey(), OffsetTransform);
#if UE_VERSION_OLDER_THAN(5,3,0)
const FSmartNameMapping* CurveMapping = k->GetSmartNameContainer(USkeleton::AnimCurveMappingName);
if (CurveMapping) {
TArray<FName> CurveNames;
CurveMapping->FillNameArray(CurveNames);
for (const FName& CurveName : CurveNames) {
auto* meta = CurveMapping->GetCurveMetaData(CurveName);
if (meta->Type.bMorphtarget == true) {
continue;
}
FName n = *(Prefix + CurveName.ToString() + Suffix);
Items_Curve.Add(Controller->AddControl(n, root, ControlSettings, Value, OffsetTransform, ShapeTransform, false, false));
}
}
#else
k->ForEachCurveMetaData([&](const FName& InCurveName, const FCurveMetaData& InMetaData)
{
if (InMetaData.Type.bMorphtarget == true) {
return;
}
FName n = *(Prefix + InCurveName.ToString() + Suffix);
Items_Curve.Add(Controller->AddControl(n, root, ControlSettings, Value, OffsetTransform, ShapeTransform, false, false));
});
#endif
}
}
}
@@ -0,0 +1,46 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VRM4U.h"
#include "Modules/ModuleManager.h"
#include "VrmRuntimeSettings.h"
#include "Developer/Settings/Public/ISettingsModule.h"
//#include "ISettingsModule.h"
#define LOCTEXT_NAMESPACE "FVRM4UModule"
DEFINE_LOG_CATEGORY(LogVRM4U);
void FVRM4UModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
{
}
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
SettingsModule->RegisterSettings("Project", "Plugins", "VRM4U",
LOCTEXT("RuntimeSettingsName", "VRM4U"),
LOCTEXT("RuntimeSettingsDescription", "Configure the VRM4U plugin"),
GetMutableDefault<UVrmRuntimeSettings>());
}
}
void FVRM4UModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
SettingsModule->UnregisterSettings("Project", "Plugins", "VRM4U");
}
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FVRM4UModule, VRM4U)
@@ -0,0 +1,80 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "VRM4U_AnimSubsystem.h"
void UVRM4U_AnimSubsystem::Clear() {
FScopeLock Lock(&cs);
baseData.Empty();
}
void UVRM4U_AnimSubsystem::GetBoneByIndex(int index, TMap<FString, FTransform>& trans) {
FScopeLock Lock(&cs);
if (baseData.IsValidIndex(index)) {
trans = baseData[index].BoneTransform;
}
}
void UVRM4U_AnimSubsystem::GetBoneByPort(int port, TMap<FString, FTransform>& trans) {
FScopeLock Lock(&cs);
for (auto& a : baseData) {
if (a.port == port) {
trans = a.BoneTransform;
return;
}
}
FVrmTransformData a;
a.port = port;
baseData.Add(a);
trans = baseData.Last(0).BoneTransform;
}
void UVRM4U_AnimSubsystem::GetRawdataByIndex(int index, TMap<FString, FTransform>& trans) {
FScopeLock Lock(&cs);
if (baseData.IsValidIndex(index)) {
trans = baseData[index].RawData;
}
}
void UVRM4U_AnimSubsystem::GetRawdataByPort(int port, TMap<FString, FTransform>& trans) {
FScopeLock Lock(&cs);
for (auto& a : baseData) {
if (a.port == port) {
trans = a.RawData;
return;
}
}
FVrmTransformData a;
a.port = port;
baseData.Add(a);
trans = baseData.Last(0).RawData;
}
void UVRM4U_AnimSubsystem::SetBoneTransform(int port, const TMap<FString, FTransform>& trans) {
FScopeLock Lock(&cs);
for (auto& a : baseData) {
if (a.port == port) {
a.BoneTransform = trans;
return;
}
}
FVrmTransformData a;
a.port = port;
a.BoneTransform = trans;
baseData.Add(a);
}
void UVRM4U_AnimSubsystem::SetRawData(int port, const TMap<FString, FTransform>& trans) {
FScopeLock Lock(&cs);
for (auto& a : baseData) {
if (a.port == port) {
a.RawData = trans;
return;
}
}
FVrmTransformData a;
a.port = port;
a.RawData = trans;
baseData.Add(a);
}
@@ -0,0 +1,6 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "Vrm1LicenseObject.h"
@@ -0,0 +1,411 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmAnimInstance.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
#include "Animation/AnimNodeBase.h"
#include "BoneControllers/AnimNode_Fabrik.h"
#include "BoneControllers/AnimNode_TwoBoneIK.h"
#include "BoneControllers/AnimNode_SplineIK.h"
#include "Misc/EngineVersionComparison.h"
void FVrmAnimInstanceProxy::Initialize(UAnimInstance* InAnimInstance) {
}
bool FVrmAnimInstanceProxy::Evaluate(FPoseContext& Output) {
Output.ResetToRefPose();
UVrmAnimInstance *animInstance = Cast<UVrmAnimInstance>(GetAnimInstanceObject());
if (animInstance == nullptr) {
return false;
}
/*
enum BoneTarget{
E_Hand_L,
E_UpperArm_L,
E_Hand_R,
E_UpperArm_R,
E_Head,
E_Spine,
E_MAX,
};
// boneName
FString targetBoneTable[] = {
TEXT("leftHand"),
TEXT("leftUpperArm"),
TEXT("rightHand"),
TEXT("rightUpperArm"),
TEXT("head"),
TEXT("spine"),
};
{
const UVrmMetaObject *meta = animInstance->MetaObject;
if (meta) {
for (auto &humanoidName : targetBoneTable) {
for (auto &modelName : meta->humanoidBoneTable) {
if (humanoidName.Compare(modelName.Key, ESearchCase::IgnoreCase) != 0) {
continue;
}
// bone rename
humanoidName = modelName.Value;
break;
}
}
}
}
// tracking point
FTransform targetTracking[] = {
animInstance->TransHandLeft,
animInstance->TransHandRight,
animInstance->TransHead,
};
{
const USceneComponent *targetComponent[] = {
animInstance->ComponentHandLeft,
animInstance->ComponentHandRight,
animInstance->ComponentHead,
};
for (int i = 0; i < 3; ++i) {
if (targetComponent[i] == nullptr) continue;
targetTracking[i] = targetComponent[i]->GetComponentTransform();
}
}
// mainBone Transform
//FTeransform boneTransform[E_MAX] = {
//};
USkeletalMeshComponent *srcMesh = animInstance->BaseSkeletalMeshComponent;
if (srcMesh == nullptr) {
// return false;
}
const auto &RefSkeletonTransform = GetSkelMeshComponent()->SkeletalMesh->RefSkeleton.GetRefBonePose();
auto &pose = Output.Pose;
FComponentSpacePoseContext ComponentSpacePoseContext(Output.AnimInstanceProxy);
ComponentSpacePoseContext.Pose.InitPose(Output.Pose);
for (int i = 2; i >=0 ; --i) {
if (targetTracking[i].GetLocation().Size() == 0) {
continue;
}
FAnimNode_Fabrik f;
{
f.EffectorTransformSpace = EBoneControlSpace::BCS_WorldSpace;
f.EffectorTransform = targetTracking[i];
//f.EffectorTarget;
f.EffectorRotationSource = EBoneRotationSource::BRS_CopyFromTarget;
f.TipBone.BoneName = *(targetBoneTable[i * 2]);
f.TipBone.Initialize(this->GetSkeleton());
f.RootBone.BoneName = *(targetBoneTable[i * 2 + 1]);
f.RootBone.Initialize(this->GetSkeleton());
f.Precision = 1.f;
f.MaxIterations = 10;
f.bEnableDebugDraw = false;
}
FAnimNode_TwoBoneIK t;
{
t.IKBone.BoneName = *(targetBoneTable[i * 2]);
t.bAllowStretching = true;
t.StartStretchRatio = 1.f;
t.MaxStretchScale = 1.1f;
//t.bTakeRotationFromEffectorSpace = false;
t.bMaintainEffectorRelRot = false;
t.bAllowTwist = true;
t.EffectorLocationSpace = EBoneControlSpace::BCS_WorldSpace;
t.EffectorLocation = targetTracking[i].GetLocation();
//f.EffectorTarget;
t.JointTargetLocationSpace = EBoneControlSpace::BCS_WorldSpace;
const USceneComponent *tmp[] = {
animInstance->ComponentHandJointTargetLeft,
animInstance->ComponentHandJointTargetRight,
nullptr,
};
if (tmp[i]) {
t.JointTargetLocation = tmp[i]->GetComponentLocation();
}
//f.JointTarget;
}
FAnimNode_SplineIK s;
{
s.StartBone.BoneName = *targetBoneTable[E_Spine];
s.StartBone.Initialize(this->GetSkeleton());
s.EndBone.BoneName = *targetBoneTable[E_Head];
s.EndBone.Initialize(this->GetSkeleton());
s.BoneAxis = ESplineBoneAxis::Y;
s.bAutoCalculateSpline = false;
s.PointCount = 2;
s.ControlPoints.SetNum(2);
s.ControlPoints[0].SetIdentity();
s.ControlPoints[1] = targetTracking[2];
s.ControlPoints[1].SetToRelativeTransform(GetComponentTransform());
//ComponentSpacePoseContext.
s.Roll = 0.f;
s.TwistStart = 0.f;
s.TwistEnd = 0.f;
//s.TwistBlend;
s.Stretch = 0.01f;
s.Offset = 0.f;
}
{
//ApplyBoneControllers(GetCurveBoneControllers(), ComponentSpacePoseContext);
//ApplyBoneControllers(BoneControllers, ComponentSpacePoseContext);
if (USkeleton* LocalSkeleton = ComponentSpacePoseContext.AnimInstanceProxy->GetSkeleton())
{
//for (auto& SingleBoneController : InBoneControllers)
if (i != 2) {
auto &SingleBoneController = t;
TArray<FBoneTransform> BoneTransforms;
FAnimationCacheBonesContext Proxy(this);
SingleBoneController.CacheBones_AnyThread(Proxy);
if (SingleBoneController.IsValidToEvaluate(LocalSkeleton, ComponentSpacePoseContext.Pose.GetPose().GetBoneContainer()))
{
SingleBoneController.EvaluateSkeletalControl_AnyThread(ComponentSpacePoseContext, BoneTransforms);
if (BoneTransforms.Num() > 0)
{
ComponentSpacePoseContext.Pose.LocalBlendCSBoneTransforms(BoneTransforms, 1.0f);
}
}
} else {
auto &SingleBoneController = s;
TArray<FBoneTransform> BoneTransforms;
FAnimationCacheBonesContext Proxy(this);
SingleBoneController.CacheBones_AnyThread(Proxy);
if (SingleBoneController.IsValidToEvaluate(LocalSkeleton, ComponentSpacePoseContext.Pose.GetPose().GetBoneContainer()))
{
SingleBoneController.EvaluateSkeletalControl_AnyThread(ComponentSpacePoseContext, BoneTransforms);
if (BoneTransforms.Num() > 0)
{
ComponentSpacePoseContext.Pose.LocalBlendCSBoneTransforms(BoneTransforms, 1.0f);
}
}
}
}
}
}
//
#if UE_VERSION_OLDER_THAN(4,21,0)
ComponentSpacePoseContext.Pose.ConvertToLocalPoses(Output.Pose);
#endif
for (int i=0; i<3; ++i){
auto b = GetSkelMeshComponent()->GetBoneIndex(*targetBoneTable[i*2]);
if (b == INDEX_NONE) {
continue;
}
FCompactPose::BoneIndexType bi(b);
auto t = Output.Pose[bi];
auto tmp = targetTracking[i];
//tmp.SetToRelativeTransform(GetComponentTransform());
//t.SetRotation( GetComponentTransform().GetRotation().Inverse() * (tmp.GetRotation()) );
//const FTransform& BoneTM = ComponentSpacePoseContext.Pose.GetComponentSpaceTransform(bi);
t.SetRotation( t.GetRotation() * (tmp.GetRotation()) );
Output.Pose[bi] = t;
}
*/
/*
for (auto &boneName : meta->humanoidBoneTable) {
if (boneName.Key == TEXT("leftEye") || boneName.Key == TEXT("rightEye")) {
continue;
}
//auto i = srcMesh->GetBoneIndex();
if (srcMesh->GetBoneIndex(*(boneName.Key)) < 0) {
continue;
}
auto t = srcMesh->GetSocketTransform(*(boneName.Key), RTS_ParentBoneSpace);
auto i = GetSkelMeshComponent()->GetBoneIndex(*(boneName.Value));
if (i < 0) {
continue;
}
auto refLocation = RefSkeletonTransform[i].GetLocation();
FVector newLoc = t.GetLocation();
if (newLoc.Normalize()) {
newLoc *= refLocation.Size();
t.SetLocation(newLoc);
}
FCompactPose::BoneIndexType bi(i);
pose[bi] = t;
}
*/
return true;
}
#if UE_VERSION_OLDER_THAN(4,24,0)
void FVrmAnimInstanceProxy::UpdateAnimationNode(float DeltaSeconds) {
}
#else
void FVrmAnimInstanceProxy::UpdateAnimationNode(const FAnimationUpdateContext& InContext){
}
#endif
/////
UVrmAnimInstance::UVrmAnimInstance(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
FAnimInstanceProxy* UVrmAnimInstance::CreateAnimInstanceProxy() {
return new FVrmAnimInstanceProxy(this);
}
void UVrmAnimInstance::NativeInitializeAnimation() {
}
void UVrmAnimInstance::NativeUpdateAnimation(float DeltaSeconds) {
{
if (BaseSkeletalMeshComponent == nullptr) {
return;
}
auto a = BaseSkeletalMeshComponent->GetAnimInstance();
if (a == nullptr) {
return;
}
if (VRMGetSkinnedAsset(BaseSkeletalMeshComponent) == nullptr) {
return;
}
a->CurrentSkeleton = VRMGetSkeleton( VRMGetSkinnedAsset(BaseSkeletalMeshComponent) );
}
}
void UVrmAnimInstance::NativePostEvaluateAnimation() {
if (BaseSkeletalMeshComponent) {
if (BaseSkeletalMeshComponent->AnimScriptInstance) {
IAnimClassInterface* AnimClassInterface = IAnimClassInterface::GetFromClass(this->GetClass());
//const USkeleton* AnimSkeleton = (AnimClassInterface) ? AnimClassInterface->GetTargetSkeleton() : nullptr;
if (AnimClassInterface) {
//AnimClassInterface->
}
//BaseSkeletalMeshComponent->AnimScriptInstance->target
//BaseSkeletalMeshComponent->AnimScriptInstance->CurrentSkeleton =
//BaseSkeletalMeshComponent->SkeletalMesh->Skeleton;
}
}
}
void UVrmAnimInstance::NativeUninitializeAnimation() {
}
void UVrmAnimInstance::NativeBeginPlay() {
}
namespace {
static TArray<FString> shapeBlend = {
"Neutral","A","I","U","E","O","Blink","Joy","Angry","Sorrow","Fun","LookUp","LookDown","LookLeft","LookRight","Blink_L","Blink_R",
};
}
void UVrmAnimInstance::SetMorphTargetVRM(EVRMBlendShapeGroup type, float Value) {
if (MetaObject == nullptr){
return;
}
USkeletalMeshComponent *skc = GetOwningComponent();
//auto &morphMap = skc->GetMorphTargetCurves();
for (auto &a : MetaObject->BlendShapeGroup) {
if (a.name != shapeBlend[(int)type]) {
continue;
}
for (auto &b : a.BlendShape) {
//b.meshName
SetMorphTarget(*(b.morphTargetName), Value);
/*
for (auto &m : skc->SkeletalMesh->MorphTargets) {
auto s = m->GetName();
//if (s.Find(b.meshName) < 0) {
// continue;
//}
auto s1 = FString::Printf(TEXT("%02d_"), b.meshID);
if (s.Find(s1) < 0) {
continue;
}
auto s2 = FString::Printf(TEXT("_%02d"), b.shapeIndex);
if (s.Find(s2) < 0) {
continue;
}
SetMorphTarget(*s, Value);
}
*/
}
}
}
void UVrmAnimInstance::SetVrmData(USkeletalMeshComponent *baseSkeletalMesh, UVrmMetaObject *meta) {
IAnimClassInterface* AnimClassInterface = IAnimClassInterface::GetFromClass(this->GetClass());
//const USkeleton* AnimSkeleton = (AnimClassInterface) ? AnimClassInterface->GetTargetSkeleton() : nullptr;
USkeletalMeshComponent *skc = GetOwningComponent();
skc->SetSkeletalMesh(meta->SkeletalMesh);
BaseSkeletalMeshComponent = baseSkeletalMesh;
MetaObject = meta;
//if (AnimClassInterface) {
// AnimClassInterface->
//}
//BaseSkeletalMeshComponent->AnimScriptInstance->target
//BaseSkeletalMeshComponent->AnimScriptInstance->CurrentSkeleton =
//BaseSkeletalMeshComponent->SkeletalMesh->Skeleton;
}
@@ -0,0 +1,576 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmAnimInstanceCopy.h"
#include "VrmMetaObject.h"
#include "VrmAssetListObject.h"
#include "VrmUtil.h"
#include "VrmBPFunctionLibrary.h"
#include "Animation/AnimNodeBase.h"
//#include "BoneControllers/AnimNode_Fabrik.h"
//#include "BoneControllers/AnimNode_TwoBoneIK.h"
//#include "BoneControllers/AnimNode_SplineIK.h"
#include "AnimNode_VrmSpringBone.h"
#include "AnimNode_VrmConstraint.h"
#if UE_VERSION_OLDER_THAN(5,4,0)
#include "Animation/Rig.h"
#endif
namespace {
// for UE4.19-4.22
template<class BaseType, class PoseType>
static void ConvertToLocalPoses(const BaseType &basePose, PoseType& OutPose)
{
checkSlow(basePose.GetPose().IsValid());
OutPose = basePose.GetPose();
// now we need to convert back to local bases
// only convert back that has been converted to mesh base
// if it was local base, and if it hasn't been modified
// that is still okay even if parent is changed,
// that doesn't mean this local has to change
// go from child to parent since I need parent inverse to go back to local
// root is same, so no need to do Index == 0
const FCSPose<FCompactPose>::BoneIndexType RootBoneIndex(0);
if (basePose.GetComponentSpaceFlags()[RootBoneIndex])
{
OutPose[RootBoneIndex] = basePose.GetPose()[RootBoneIndex];
}
const int32 NumBones = basePose.GetPose().GetNumBones();
for (int32 Index = NumBones - 1; Index > 0; Index--)
{
const FCSPose<FCompactPose>::BoneIndexType BoneIndex(Index);
if (basePose.GetComponentSpaceFlags()[BoneIndex])
{
const FCSPose<FCompactPose>::BoneIndexType ParentIndex = basePose.GetPose().GetParentBoneIndex(BoneIndex);
OutPose[BoneIndex].SetToRelativeTransform(OutPose[ParentIndex]);
OutPose[BoneIndex].NormalizeRotation();
}
}
}
}
FVrmAnimInstanceCopyProxy::FVrmAnimInstanceCopyProxy()
{
if (Node_SpringBone.Get() == nullptr) {
Node_SpringBone = MakeShareable(new FAnimNode_VrmSpringBone());
}
if (Node_Constraint.Get() == nullptr) {
Node_Constraint = MakeShareable(new FAnimNode_VrmConstraint());
}
}
FVrmAnimInstanceCopyProxy::FVrmAnimInstanceCopyProxy(UAnimInstance* InAnimInstance)
: FAnimInstanceProxy(InAnimInstance)
{
if (Node_SpringBone.Get() == nullptr) {
Node_SpringBone = MakeShareable(new FAnimNode_VrmSpringBone());
}
if (Node_Constraint.Get() == nullptr) {
Node_Constraint = MakeShareable(new FAnimNode_VrmConstraint());
}
}
void FVrmAnimInstanceCopyProxy::Initialize(UAnimInstance* InAnimInstance) {
}
bool FVrmAnimInstanceCopyProxy::Evaluate(FPoseContext& Output) {
if (bCopyStop) {
return false;
}
if (bAnimStop && bUseAnimStop) {
Output.Pose.CopyBonesFrom(CachedPose);
return true;
}
//Output.ResetToRefPose();
UVrmAnimInstanceCopy *animInstance = Cast<UVrmAnimInstanceCopy>(GetAnimInstanceObject());
if (animInstance == nullptr) {
return false;
}
if (animInstance->DstVrmAssetList == nullptr) {
//if (animInstance->SrcVrmAssetList == nullptr || animInstance->DstVrmAssetList == nullptr) {
return false;
}
const UVrmMetaObject *srcMeta = animInstance->SrcVrmMetaOverride;
if (srcMeta == nullptr){
if (animInstance->SrcVrmAssetList) {
srcMeta = animInstance->SrcVrmAssetList->VrmMetaObject;
}
}
const UVrmMetaObject *dstMeta = animInstance->DstVrmAssetList->VrmMetaObject;
if (dstMeta) {
if (animInstance->DstVrmMetaForCustomSpring) {
dstMeta = animInstance->DstVrmMetaForCustomSpring;
}
}
if (dstMeta == nullptr) {
//if (srcMeta == nullptr || dstMeta == nullptr) {
return false;
}
auto srcSkeletalMeshComp = animInstance->SrcSkeletalMeshComponent;
auto srcAsSkinnedMeshComp = animInstance->SrcAsSkinnedMeshComponent;
if (srcAsSkinnedMeshComp == nullptr) {
if (srcSkeletalMeshComp == nullptr || srcSkeletalMeshComp->GetAnimInstance() == nullptr) {
return false;
}
}
if (VRMGetSkinnedAsset(srcAsSkinnedMeshComp) == nullptr) {
return false;
}
// ref pose
const auto &dstRefSkeletonTransform = VRMGetRefSkeleton( VRMGetSkinnedAsset(GetSkelMeshComponent()) ).GetRefBonePose();
const auto &srcRefSkeletonTransform = VRMGetRefSkeleton( VRMGetSkinnedAsset(srcAsSkinnedMeshComp) ).GetRefBonePose();
auto &pose = Output.Pose;
// morph copy
if (srcSkeletalMeshComp && srcSkeletalMeshComp->GetAnimInstance()){
EAnimCurveType types[] = {
EAnimCurveType::AttributeCurve,
EAnimCurveType::MaterialCurve,
EAnimCurveType::MorphTargetCurve,
};
for (int i = 0; i < 3; ++i) {
const TMap<FName, float>& t = srcSkeletalMeshComp->GetAnimInstance()->GetAnimationCurveList(types[i]);
for (auto& a : t) {
GetSkelMeshComponent()->SetMorphTarget(a.Key, a.Value, true);
}
}
}
float HeightScale = 1.f;
bool bUniqueRootBone = true;
int BoneCount = 0;
for (const auto &t : VRMUtil::vrm_humanoid_bone_list) {
FName srcName, dstName;
srcName = dstName = NAME_None;
++BoneCount;
{
if (srcMeta) {
auto a = srcMeta->humanoidBoneTable.Find(t);
if (a) {
srcName = **a;
}
} else {
for (auto &bonemap : VRMUtil::table_ue4_vrm) {
if (bonemap.BoneVRM == t) {
srcName = *bonemap.BoneUE4;
}
}
}
}
//auto srcName = srcSkeletalMeshComp->SkeletalMesh->Skeleton->GetRigBoneMapping(t);
if (srcName == NAME_None) {
continue;
}
{
auto a = dstMeta->humanoidBoneTable.Find(t);
if (a) {
dstName = **a;
}
}
//auto dstName = GetSkelMeshComponent()->SkeletalMesh->Skeleton->GetRigBoneMapping(t);
if (dstName == NAME_None) {
continue;
}
auto dstIndex = GetSkelMeshComponent()->GetBoneIndex(dstName);
if (dstIndex < 0) {
continue;
}
auto srcIndex = srcAsSkinnedMeshComp->GetBoneIndex(srcName);
if (srcIndex < 0) {
continue;
}
const auto srcCurrentTrans = srcAsSkinnedMeshComp->GetSocketTransform(srcName, RTS_ParentBoneSpace);
const auto srcRefTrans = srcRefSkeletonTransform[srcIndex];
const auto dstRefTrans = dstRefSkeletonTransform[dstIndex];
FTransform dstTrans = dstRefTrans;
{
FQuat diff = srcCurrentTrans.GetRotation()*srcRefTrans.GetRotation().Inverse();
dstTrans.SetRotation(dstTrans.GetRotation()*diff);
}
//dstTrans.SetLocation(dstRefTrans.GetLocation());// +srcCurrentTrans.GetLocation() - srcRefTrans.GetLocation());
//FVector newLoc = dstTrans.GetLocation();
if (BoneCount == 1) {
if (bIgnoreCenterLocation) {
dstTrans.SetTranslation(CenterLocationOffset);
} else {
int32_t p = dstIndex;
float HipHeight = 0;
while (p != INDEX_NONE) {
HipHeight += dstRefSkeletonTransform[p].GetLocation().Z;
p = VRMGetRefSkeleton( VRMGetSkinnedAsset(GetSkelMeshComponent()) ).GetParentIndex(p);
}
//FVector diff = srcCurrentTrans.GetLocation() - srcRefTrans.GetLocation();
//FVector scale = dstRefTrans.GetLocation() / srcRefTrans.GetLocation();
FVector diff = srcCurrentTrans.GetLocation() - srcRefTrans.GetLocation();
HeightScale = HipHeight / srcRefTrans.GetLocation().Z;
#if UE_VERSION_OLDER_THAN(4,24,0)
FVector ComponentScale = Output.AnimInstanceProxy->GetSkelMeshComponent()->RelativeScale3D;
#else
FVector ComponentScale = Output.AnimInstanceProxy->GetSkelMeshComponent()->GetRelativeScale3D();
#endif
if (ComponentScale.X == 0.f) {
ComponentScale.X = 0.001f;
}
if (ComponentScale.Y == 0.f) {
ComponentScale.Y = 0.001f;
}
if (ComponentScale.Z == 0.f) {
ComponentScale.Z = 0.001f;
}
dstTrans.SetTranslation(
(dstRefTrans.GetLocation() + FMath::Lerp(diff, diff * HeightScale, CenterLocationScaleByHeightScale)) / ComponentScale
+ CenterLocationOffset
);
if (dstIndex == 0) {
bUniqueRootBone = false;
}
}
}
FCompactPose::BoneIndexType bi(dstIndex);
pose[bi] = dstTrans;
}
// root bone
if (bUniqueRootBone){
FCompactPose::BoneIndexType bi(0);
const auto srcTrans = srcAsSkinnedMeshComp->GetSocketTransform(srcAsSkinnedMeshComp->GetBoneName(0), RTS_ParentBoneSpace);
auto t = srcTrans;
if (bIgnoreCenterLocation) {
t.SetTranslation(CenterLocationOffset);
}else{
#if UE_VERSION_OLDER_THAN(4,24,0)
FVector ComponentScale = Output.AnimInstanceProxy->GetSkelMeshComponent()->RelativeScale3D;
#else
FVector ComponentScale = Output.AnimInstanceProxy->GetSkelMeshComponent()->GetRelativeScale3D();
#endif
if (ComponentScale.X == 0.f) {
ComponentScale.X = 0.001f;
}
if (ComponentScale.Y == 0.f) {
ComponentScale.Y = 0.001f;
}
if (ComponentScale.Z == 0.f) {
ComponentScale.Z = 0.001f;
}
t.SetTranslation(
(FMath::Lerp(t.GetTranslation(), t.GetTranslation() * HeightScale, CenterLocationScaleByHeightScale)) / ComponentScale
+ CenterLocationOffset
);
}
pose[bi] = t;
}
// constraint
if (bIgnoreVRMConstraint == false) {
// if (0){
bool bCalc = true;
{
bool bPlay, bSIE, bEditor;
bPlay = bSIE = bEditor = true;
UVrmBPFunctionLibrary::VRMGetPlayMode(bPlay, bSIE, bEditor);
if (bPlay == false) {
bCalc = false;
}
}
if (bCalc) {
if (Node_Constraint.Get() == nullptr) {
Node_Constraint = MakeShareable(new FAnimNode_VrmConstraint());
}
if (Node_Constraint.Get()) {
#if UE_VERSION_OLDER_THAN(4,22,0)
#else
if (animInstance->PendingDynamicResetTeleportType != ETeleportType::None)
{
Node_Constraint->ResetDynamics(animInstance->PendingDynamicResetTeleportType);
}
#endif
auto& constraint = *Node_Constraint.Get();
constraint.VrmMetaObject_Internal = const_cast<UVrmMetaObject*>(dstMeta);
constraint.bCallByAnimInstance = true;
FAnimationInitializeContext InitContext(this);
if (constraint. bCallInitialized == false) {
constraint.Initialize_AnyThread(InitContext);
constraint.ComponentPose.SetLinkNode(&constraint);
}
if (0) {
++CalcCount;
FComponentSpacePoseContext InputCSPose(this);
for (int i = 0; i < 20; ++i) {
InputCSPose.Pose.InitPose(Output.Pose);
constraint.EvaluateComponentSpace_AnyThread(InputCSPose);
ConvertToLocalPoses(InputCSPose.Pose, Output.Pose);
}
}
else {
FComponentSpacePoseContext InputCSPose(this);
InputCSPose.Pose.InitPose(Output.Pose);
constraint.EvaluateComponentSpace_AnyThread(InputCSPose);
ConvertToLocalPoses(InputCSPose.Pose, Output.Pose);
}
}
}
}
else {
Node_Constraint = nullptr;
}
if (bIgnoreVRMSwingBone == false) {
//if (0){
bool bCalc = true;
{
bool bPlay, bSIE, bEditor;
bPlay = bSIE = bEditor = true;
UVrmBPFunctionLibrary::VRMGetPlayMode(bPlay, bSIE, bEditor);
if (bPlay == false) {
bCalc = false;
}
}
if (bCalc) {
if (Node_SpringBone.Get() == nullptr) {
Node_SpringBone = MakeShareable(new FAnimNode_VrmSpringBone());
}
if (Node_SpringBone.Get()) {
#if UE_VERSION_OLDER_THAN(4,22,0)
#else
if(animInstance->PendingDynamicResetTeleportType != ETeleportType::None)
{
Node_SpringBone->ResetDynamics(animInstance->PendingDynamicResetTeleportType);
}
#endif
auto& springBone = *Node_SpringBone.Get();
springBone.VrmMetaObject_Internal = const_cast<UVrmMetaObject*>(dstMeta);
springBone.bCallByAnimInstance = true;
springBone.CurrentDeltaTime = CurrentDeltaTime;
FAnimationInitializeContext InitContext(this);
if (springBone.IsSpringInit() == false) {
springBone.Initialize_AnyThread_local(InitContext);
springBone.ComponentPose.SetLinkNode(&springBone);
CalcCount = 0;
springBone.CurrentDeltaTime = 1.f / 20.f;
}
if (CalcCount < 3) {
FVector bak = springBone.gravityAdd;
++CalcCount;
FComponentSpacePoseContext InputCSPose(this);
for (int i = 0; i < 20; ++i) {
InputCSPose.Pose.InitPose(Output.Pose);
springBone.EvaluateComponentSpace_AnyThread(InputCSPose);
ConvertToLocalPoses(InputCSPose.Pose, Output.Pose);
}
springBone.gravityAdd = bak;
} else {
FComponentSpacePoseContext InputCSPose(this);
InputCSPose.Pose.InitPose(Output.Pose);
springBone.EvaluateComponentSpace_AnyThread(InputCSPose);
ConvertToLocalPoses(InputCSPose.Pose, Output.Pose);
}
}
}
} else {
Node_SpringBone = nullptr;
}
if (bUseAnimStop) {
CachedPose.CopyBonesFrom(Output.Pose);
}
return true;
}
#if UE_VERSION_OLDER_THAN(4,24,0)
void FVrmAnimInstanceCopyProxy::UpdateAnimationNode(float DeltaSeconds) {
CurrentDeltaTime = DeltaSeconds;
}
#else
void FVrmAnimInstanceCopyProxy::UpdateAnimationNode(const FAnimationUpdateContext& InContext) {
CurrentDeltaTime = InContext.GetDeltaTime();
}
#endif
/////
UVrmAnimInstanceCopy::UVrmAnimInstanceCopy(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
FAnimInstanceProxy* UVrmAnimInstanceCopy::CreateAnimInstanceProxy() {
myProxy = new FVrmAnimInstanceCopyProxy(this);
myProxy->bIgnoreVRMSwingBone = bIgnoreVRMSwingBone;
myProxy->bIgnoreWindDirectionalSource = bIgnoreWindDirectionalSource;
return myProxy;
}
void UVrmAnimInstanceCopy::NativeInitializeAnimation() {
for (int i = 0; i < FMath::Min(InitialMorphValue.Num(), InitialMorphName.Num()); ++i) {
SetMorphTarget(InitialMorphName[i], InitialMorphValue[i]);
}
}
void UVrmAnimInstanceCopy::NativeUpdateAnimation(float DeltaSeconds) {
}
void UVrmAnimInstanceCopy::NativePostEvaluateAnimation() {
myProxy->bUseAnimStop = bUseAnimStop;
myProxy->bAnimStop = bAnimStop;
myProxy->bIgnoreCenterLocation = bIgnoreCenterLocation;
myProxy->CenterLocationScaleByHeightScale = CenterLocationScaleByHeightScale;
myProxy->CenterLocationOffset= CenterLocationOffset;
myProxy->bCopyStop = bCopyStop;
}
void UVrmAnimInstanceCopy::NativeUninitializeAnimation() {
if (GetOwningComponent()) {
GetOwningComponent()->ClearMorphTargets();
}
if (!SrcSkeletalMeshComponent && bUseAttachedParent)
{
USkeletalMeshComponent* TargetMesh = GetOwningComponent();
// Walk up the attachment chain until we find a skeletal mesh component
USkeletalMeshComponent* ParentMeshComponent = nullptr;
for (USceneComponent* AttachParentComp = TargetMesh->GetAttachParent(); AttachParentComp != nullptr; AttachParentComp = AttachParentComp->GetAttachParent())
{
ParentMeshComponent = Cast<USkeletalMeshComponent>(AttachParentComp);
if (ParentMeshComponent)
{
break;
}
}
if (ParentMeshComponent == nullptr) {
AActor *targetActor = nullptr;
AActor *myActor = TargetMesh->GetOwner();
for (USceneComponent* AttachParentComp = TargetMesh->GetAttachParent(); AttachParentComp != nullptr; AttachParentComp = AttachParentComp->GetAttachParent()) {
targetActor = AttachParentComp->GetOwner();
if (targetActor != myActor) {
break;
}
targetActor = nullptr;
}
if (targetActor) {
TArray<USkeletalMeshComponent*> c;
targetActor->GetComponents<USkeletalMeshComponent>(c);
if (c.IsValidIndex(0)) {
ParentMeshComponent = c[0];
}
}
}
if (ParentMeshComponent)
{
SrcSkeletalMeshComponent = ParentMeshComponent;
}
}
if (SrcAsSkinnedMeshComponent == nullptr) {
SrcAsSkinnedMeshComponent = SrcSkeletalMeshComponent;
}
}
void UVrmAnimInstanceCopy::NativeBeginPlay() {
if (GetOwningComponent()) {
GetOwningComponent()->ClearMorphTargets();
}
}
void UVrmAnimInstanceCopy::SetSkeletalMeshCopyData(UVrmAssetListObject *dstAssetList,
USkeletalMeshComponent *srcSkeletalMesh, USkinnedMeshComponent* srcSkinnedMesh, UVrmAssetListObject *srcAssetList, UVrmMetaObject* srcVrmMeta) {
SrcSkeletalMeshComponent = srcSkeletalMesh;
SrcAsSkinnedMeshComponent = srcSkinnedMesh;
SrcVrmAssetList = srcAssetList;
DstVrmAssetList = dstAssetList;
SrcVrmMetaOverride = srcVrmMeta;
if (SrcAsSkinnedMeshComponent == nullptr) {
SrcAsSkinnedMeshComponent = SrcSkeletalMeshComponent;
}
}
void UVrmAnimInstanceCopy::SetSkeletalMeshCopyDataForCustomSpring(UVrmMetaObject *dstMetaForCustomSpring) {
DstVrmMetaForCustomSpring = dstMetaForCustomSpring;
}
void UVrmAnimInstanceCopy::SetVrmSpringBoneParam(float gravityScale, FVector gravityAdd, float stiffnessScale, float stiffnessAdd, float randomWindRange) {
if (myProxy == nullptr) return;
auto a = myProxy->Node_SpringBone.Get();
if (a == nullptr) return;
a->gravityScale = gravityScale;
a->gravityAdd = gravityAdd;
a->stiffnessScale = stiffnessScale;
a->stiffnessAdd = stiffnessAdd;
a->randomWindRange = randomWindRange;
}
void UVrmAnimInstanceCopy::SetVrmSpringBoneBool(bool bIgnoreVrmSpringBone, bool bIgnorePhysicsCollision, bool bIgnoreVRMCollision, bool bIgnoreWind) {
if (myProxy == nullptr) return;
auto a = myProxy->Node_SpringBone.Get();
if (a == nullptr) return;
this->bIgnoreVRMSwingBone = bIgnoreVrmSpringBone;
myProxy->bIgnoreVRMSwingBone = bIgnoreVrmSpringBone;
a->bIgnorePhysicsCollision = bIgnorePhysicsCollision;
a->bIgnoreVRMCollision = bIgnoreVRMCollision;
a->bIgnoreWindDirectionalSource = bIgnoreWind;
}
void UVrmAnimInstanceCopy::SetVrmSpringBoneIgnoreWingBone(const TArray<FName> &boneNameList) {
if (myProxy == nullptr) return;
auto a = myProxy->Node_SpringBone.Get();
if (a == nullptr) return;
a->NoWindBoneNameList = boneNameList;
}
@@ -0,0 +1,442 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmAnimInstanceRetargetFromMannequin.h"
#if UE_VERSION_OLDER_THAN(5,2,0)
#else
#include "VrmMetaObject.h"
#include "VrmAssetListObject.h"
#include "VrmUtil.h"
#include "VrmBPFunctionLibrary.h"
#include "Animation/AnimNodeBase.h"
//#include "BoneControllers/AnimNode_Fabrik.h"
//#include "BoneControllers/AnimNode_TwoBoneIK.h"
//#include "BoneControllers/AnimNode_SplineIK.h"
#include "AnimNode_VrmSpringBone.h"
#include "AnimNode_VrmConstraint.h"
#include "AnimNodes/AnimNode_RetargetPoseFromMesh.h"
#include "VrmRigHeader.h"
#if UE_VERSION_OLDER_THAN(5,4,0)
#include "Animation/Rig.h"
#endif
namespace {
template<class BaseType, class PoseType>
static void ConvertToLocalPoses2(const BaseType &basePose, PoseType& OutPose)
{
checkSlow(basePose.GetPose().IsValid());
OutPose = basePose.GetPose();
// now we need to convert back to local bases
// only convert back that has been converted to mesh base
// if it was local base, and if it hasn't been modified
// that is still okay even if parent is changed,
// that doesn't mean this local has to change
// go from child to parent since I need parent inverse to go back to local
// root is same, so no need to do Index == 0
const FCSPose<FCompactPose>::BoneIndexType RootBoneIndex(0);
if (basePose.GetComponentSpaceFlags()[RootBoneIndex])
{
OutPose[RootBoneIndex] = basePose.GetPose()[RootBoneIndex];
}
const int32 NumBones = basePose.GetPose().GetNumBones();
for (int32 Index = NumBones - 1; Index > 0; Index--)
{
const FCSPose<FCompactPose>::BoneIndexType BoneIndex(Index);
if (basePose.GetComponentSpaceFlags()[BoneIndex])
{
const FCSPose<FCompactPose>::BoneIndexType ParentIndex = basePose.GetPose().GetParentBoneIndex(BoneIndex);
OutPose[BoneIndex].SetToRelativeTransform(OutPose[ParentIndex]);
OutPose[BoneIndex].NormalizeRotation();
}
}
}
}
FVrmAnimInstanceRetargetFromMannequinProxy::FVrmAnimInstanceRetargetFromMannequinProxy()
{
}
FVrmAnimInstanceRetargetFromMannequinProxy::FVrmAnimInstanceRetargetFromMannequinProxy(UAnimInstance* InAnimInstance)
: FAnimInstanceProxy(InAnimInstance)
{
}
void FVrmAnimInstanceRetargetFromMannequinProxy::Initialize(UAnimInstance* InAnimInstance) {
Super::Initialize(InAnimInstance);
}
void FVrmAnimInstanceRetargetFromMannequinProxy::CustomInitialize() {
if (Node_SpringBone.Get() == nullptr) {
Node_SpringBone = MakeShareable(new FAnimNode_VrmSpringBone());
}
if (Node_Constraint.Get() == nullptr) {
Node_Constraint = MakeShareable(new FAnimNode_VrmConstraint());
}
if (Node_Retarget.Get() == nullptr) {
Node_Retarget = MakeShareable(new FAnimNode_RetargetPoseFromMesh());
FAnimationInitializeContext InitContext(this);
Node_Retarget->Initialize_AnyThread(InitContext);
}
}
bool FVrmAnimInstanceRetargetFromMannequinProxy::Evaluate(FPoseContext& Output) {
//Output.Pose.CopyBonesFrom(CachedPose);
UVrmAnimInstanceRetargetFromMannequin* animInstance = Cast<UVrmAnimInstanceRetargetFromMannequin>(GetAnimInstanceObject());
if (animInstance == nullptr) {
return false;
}
if (animInstance->DstVrmAssetList == nullptr) {
if (IsInGameThread())
{
//FMessageLog("AnimBlueprintLog").Warning(
// FText::Format(LOCTEXT("AnimInstance_SlotNode", "SLOTNODE: '{0}' in animation instance class {1} already exists. Remove duplicates from the animation graph for this class."),
// FText::FromString(SlotNodeName.ToString()), FText::FromString(ClassNameString)));
//FMessageLog("AnimBlueprintLog").Warning(FText::Format("UVrmAnimInstanceRetargetFromMannequin")));
}
else
{
//UE_LOG(LogAnimation, Warning, TEXT("SLOTNODE: '%s' in animation instance class %s already exists. Remove duplicates from the animation graph for this class."), *SlotNodeName.ToString(), *ClassNameString);
}
UE_LOG(LogAnimation, Warning, TEXT("UVrmAnimInstanceRetargetFromMannequin:: no DestVrmAssetList"));
return false;
}
const UVrmMetaObject *dstMeta = animInstance->DstVrmAssetList->VrmMetaObject;
if (dstMeta) {
if (animInstance->DstVrmMetaForCustomSpring) {
dstMeta = animInstance->DstVrmMetaForCustomSpring;
}
}
if (dstMeta == nullptr) {
UE_LOG(LogAnimation, Warning, TEXT("UVrmAnimInstanceRetargetFromMannequin:: no DstMeta"));
return false;
}
// morph copy
if (animInstance->SrcSkeletalMeshComponent){
if (animInstance->SrcSkeletalMeshComponent->GetAnimInstance()) {
EAnimCurveType types[] = {
EAnimCurveType::AttributeCurve,
EAnimCurveType::MaterialCurve,
EAnimCurveType::MorphTargetCurve,
};
for (int i = 0; i < 3; ++i) {
const TMap<FName, float>& t = animInstance->SrcSkeletalMeshComponent->GetAnimInstance()->GetAnimationCurveList(types[i]);
for (auto& a : t) {
GetSkelMeshComponent()->SetMorphTarget(a.Key, a.Value, true);
}
}
}
}
#if UE_VERSION_OLDER_THAN(5,2,0)
#else
//retarget
if (bUseRetargeter && Retargeter && Node_Retarget.Get()) {
if (Node_Retarget.Get()) {
auto node = Node_Retarget.Get();
FAnimationCacheBonesContext c(this);
node->CacheBones_AnyThread(c);
node->Evaluate_AnyThread(Output);
}
} else {
Node_Retarget = nullptr;
}
#endif
// constraint
if (bIgnoreVRMConstraint == false) {
bool bCalc = true;
{
bool bPlay, bSIE, bEditor;
bPlay = bSIE = bEditor = true;
UVrmBPFunctionLibrary::VRMGetPlayMode(bPlay, bSIE, bEditor);
if (bPlay == false) {
bCalc = false;
}
}
if (bCalc) {
if (Node_Constraint.Get() == nullptr) {
Node_Constraint = MakeShareable(new FAnimNode_VrmConstraint());
}
if (Node_Constraint.Get()) {
if (animInstance->PendingDynamicResetTeleportType != ETeleportType::None)
{
Node_Constraint->ResetDynamics(animInstance->PendingDynamicResetTeleportType);
}
auto& constraint = *Node_Constraint.Get();
constraint.VrmMetaObject_Internal = const_cast<UVrmMetaObject*>(dstMeta);
constraint.bCallByAnimInstance = true;
FAnimationInitializeContext InitContext(this);
if (constraint. bCallInitialized == false) {
constraint.Initialize_AnyThread(InitContext);
constraint.ComponentPose.SetLinkNode(&constraint);
}
{
FComponentSpacePoseContext InputCSPose(this);
InputCSPose.Pose.InitPose(Output.Pose);
constraint.EvaluateComponentSpace_AnyThread(InputCSPose);
ConvertToLocalPoses2(InputCSPose.Pose, Output.Pose);
}
}
}
}
else {
Node_Constraint = nullptr;
}
if (bIgnoreVRMSwingBone == false) {
//if (0){
bool bCalc = true;
{
bool bPlay, bSIE, bEditor;
bPlay = bSIE = bEditor = true;
UVrmBPFunctionLibrary::VRMGetPlayMode(bPlay, bSIE, bEditor);
if (bPlay == false) {
bCalc = false;
}
}
if (bCalc) {
if (Node_SpringBone.Get() == nullptr) {
Node_SpringBone = MakeShareable(new FAnimNode_VrmSpringBone());
}
if (Node_SpringBone.Get()) {
if(animInstance->PendingDynamicResetTeleportType != ETeleportType::None)
{
Node_SpringBone->ResetDynamics(animInstance->PendingDynamicResetTeleportType);
}
auto& springBone = *Node_SpringBone.Get();
springBone.VrmMetaObject_Internal = const_cast<UVrmMetaObject*>(dstMeta);
springBone.bCallByAnimInstance = true;
springBone.CurrentDeltaTime = CurrentDeltaTime;
FAnimationInitializeContext InitContext(this);
if (springBone.IsSpringInit() == false) {
springBone.Initialize_AnyThread_local(InitContext);
springBone.ComponentPose.SetLinkNode(&springBone);
CalcCount = 0;
springBone.CurrentDeltaTime = 1.f / 20.f;
}
if (CalcCount < 3) {
FVector bak = springBone.gravityAdd;
++CalcCount;
FComponentSpacePoseContext InputCSPose(this);
for (int i = 0; i < 20; ++i) {
InputCSPose.Pose.InitPose(Output.Pose);
springBone.EvaluateComponentSpace_AnyThread(InputCSPose);
ConvertToLocalPoses2(InputCSPose.Pose, Output.Pose);
}
springBone.gravityAdd = bak;
} else {
FComponentSpacePoseContext InputCSPose(this);
InputCSPose.Pose.InitPose(Output.Pose);
springBone.EvaluateComponentSpace_AnyThread(InputCSPose);
ConvertToLocalPoses2(InputCSPose.Pose, Output.Pose);
}
}
}
} else {
Node_SpringBone = nullptr;
}
return true;
}
void FVrmAnimInstanceRetargetFromMannequinProxy::UpdateAnimationNode(const FAnimationUpdateContext& InContext) {
CurrentDeltaTime = InContext.GetDeltaTime();
CustomInitialize();
}
void FVrmAnimInstanceRetargetFromMannequinProxy::PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) {
Super::PreUpdate(InAnimInstance, DeltaSeconds);
if (Node_Retarget.Get()) {
auto node = Node_Retarget.Get();
node->IKRetargeterAsset = Retargeter.Get();
//node->SourceMeshComponent = InAnimInstance->SrcSkeletalMeshComponent; // null ok
FAnimationInitializeContext InitContext(this);
if (node->GetRetargetProcessor() == nullptr) {
node->Initialize_AnyThread(InitContext);
}
node->PreUpdate(InAnimInstance);
}
}
/////
UVrmAnimInstanceRetargetFromMannequin::UVrmAnimInstanceRetargetFromMannequin(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
bUsingCopyPoseFromMesh = true;
bUseMultiThreadedAnimationUpdate = false;
}
FAnimInstanceProxy* UVrmAnimInstanceRetargetFromMannequin::CreateAnimInstanceProxy() {
myProxy = new FVrmAnimInstanceRetargetFromMannequinProxy(this);
myProxy->bIgnoreVRMSwingBone = bIgnoreVRMSwingBone;
myProxy->bIgnoreWindDirectionalSource = bIgnoreWindDirectionalSource;
return myProxy;
}
void UVrmAnimInstanceRetargetFromMannequin::NativeInitializeAnimation() {
for (int i = 0; i < FMath::Min(InitialMorphValue.Num(), InitialMorphName.Num()); ++i) {
SetMorphTarget(InitialMorphName[i], InitialMorphValue[i]);
}
}
void UVrmAnimInstanceRetargetFromMannequin::NativeUpdateAnimation(float DeltaSeconds) {
}
void UVrmAnimInstanceRetargetFromMannequin::NativePostEvaluateAnimation() {
}
void UVrmAnimInstanceRetargetFromMannequin::NativeUninitializeAnimation() {
if (GetOwningComponent()) {
GetOwningComponent()->ClearMorphTargets();
}
if (!SrcSkeletalMeshComponent && bUseAttachedParent)
{
USkeletalMeshComponent* TargetMesh = GetOwningComponent();
// Walk up the attachment chain until we find a skeletal mesh component
USkeletalMeshComponent* ParentMeshComponent = nullptr;
for (USceneComponent* AttachParentComp = TargetMesh->GetAttachParent(); AttachParentComp != nullptr; AttachParentComp = AttachParentComp->GetAttachParent())
{
ParentMeshComponent = Cast<USkeletalMeshComponent>(AttachParentComp);
if (ParentMeshComponent)
{
break;
}
}
if (ParentMeshComponent == nullptr) {
AActor *targetActor = nullptr;
AActor *myActor = TargetMesh->GetOwner();
for (USceneComponent* AttachParentComp = TargetMesh->GetAttachParent(); AttachParentComp != nullptr; AttachParentComp = AttachParentComp->GetAttachParent()) {
targetActor = AttachParentComp->GetOwner();
if (targetActor != myActor) {
break;
}
targetActor = nullptr;
}
if (targetActor) {
TArray<USkeletalMeshComponent*> c;
targetActor->GetComponents<USkeletalMeshComponent>(c);
if (c.IsValidIndex(0)) {
ParentMeshComponent = c[0];
}
}
}
if (ParentMeshComponent)
{
SrcSkeletalMeshComponent = ParentMeshComponent;
}
}
if (SrcAsSkinnedMeshComponent == nullptr) {
SrcAsSkinnedMeshComponent = SrcSkeletalMeshComponent;
}
}
void UVrmAnimInstanceRetargetFromMannequin::NativeBeginPlay() {
if (GetOwningComponent()) {
GetOwningComponent()->ClearMorphTargets();
}
}
void UVrmAnimInstanceRetargetFromMannequin::PreUpdateAnimation(float DeltaSeconds) {
Super::PreUpdateAnimation(DeltaSeconds);
}
void UVrmAnimInstanceRetargetFromMannequin::SetRetargetData(bool bUseRetargeter, UIKRetargeter* IKRetargeter) {
myProxy->Retargeter = IKRetargeter;
myProxy->bUseRetargeter = bUseRetargeter;
}
void UVrmAnimInstanceRetargetFromMannequin::SetVrmAssetList(UVrmAssetListObject *dstAssetList) {
DstVrmAssetList = dstAssetList;
}
void UVrmAnimInstanceRetargetFromMannequin::SetSkeletalMeshCopyDataForCustomSpring(UVrmMetaObject *dstMetaForCustomSpring) {
DstVrmMetaForCustomSpring = dstMetaForCustomSpring;
}
void UVrmAnimInstanceRetargetFromMannequin::SetVrmSpringBoneParam(float gravityScale, FVector gravityAdd, float stiffnessScale, float stiffnessAdd, float randomWindRange) {
if (myProxy == nullptr) return;
auto a = myProxy->Node_SpringBone.Get();
if (a == nullptr) return;
a->gravityScale = gravityScale;
a->gravityAdd = gravityAdd;
a->stiffnessScale = stiffnessScale;
a->stiffnessAdd = stiffnessAdd;
a->randomWindRange = randomWindRange;
}
void UVrmAnimInstanceRetargetFromMannequin::SetVrmSpringBoneBool(bool bIgnoreVrmSpringBone, bool bIgnorePhysicsCollision, bool bIgnoreVRMCollision, bool bIgnoreWind) {
if (myProxy == nullptr) return;
auto a = myProxy->Node_SpringBone.Get();
if (a == nullptr) return;
this->bIgnoreVRMSwingBone = bIgnoreVrmSpringBone;
myProxy->bIgnoreVRMSwingBone = bIgnoreVrmSpringBone;
a->bIgnorePhysicsCollision = bIgnorePhysicsCollision;
a->bIgnoreVRMCollision = bIgnoreVRMCollision;
a->bIgnoreWindDirectionalSource = bIgnoreWind;
}
void UVrmAnimInstanceRetargetFromMannequin::SetVrmSpringBoneIgnoreWingBone(const TArray<FName> &boneNameList) {
if (myProxy == nullptr) return;
auto a = myProxy->Node_SpringBone.Get();
if (a == nullptr) return;
a->NoWindBoneNameList = boneNameList;
}
#endif // 5.3
@@ -0,0 +1,26 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmAnimInstanceTemplate.h"
#include "Animation/AnimNodeBase.h"
FVrmAnimInstanceTemplateProxy::FVrmAnimInstanceTemplateProxy()
{
}
FVrmAnimInstanceTemplateProxy::FVrmAnimInstanceTemplateProxy(UAnimInstance* InAnimInstance)
: FAnimInstanceProxy(InAnimInstance)
{
}
/////
UVrmAnimInstanceTemplate::UVrmAnimInstanceTemplate(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
FAnimInstanceProxy* UVrmAnimInstanceTemplate::CreateAnimInstanceProxy() {
myProxy = new FVrmAnimInstanceTemplateProxy(this);
return myProxy;
}
@@ -0,0 +1,105 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmAssetListObject.h"
#include "EditorFramework/AssetImportData.h"
#include "UObject/AssetRegistryTagsContext.h"
//#include "LoaderBPFunctionLibrary.h"
UVrmAssetListObject::UVrmAssetListObject(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
Package = GetTransientPackage();
//Result = new FReturnedData();
}
void UVrmAssetListObject::CopyMember(UVrmAssetListObject *dst) const {
dst->bAssetSave = bAssetSave;
dst->bSkipMorphTarget = bSkipMorphTarget;
dst->MtoonLitSet = MtoonLitSet;
dst->MtoonUnlitSet = MtoonUnlitSet;
dst->SSSSet = SSSSet;
dst->SSSProfileSet = SSSProfileSet;
dst->UnlitSet = UnlitSet;
dst->GLTFSet = GLTFSet;
dst->UEFNUnlitSet = UEFNUnlitSet;
dst->UEFNLitSet = UEFNLitSet;
dst->UEFNSSSProfileSet = UEFNSSSProfileSet;
dst->CustomSet = CustomSet;
dst->BaseMToonLitOpaqueMaterial = BaseMToonLitOpaqueMaterial;
dst->BaseMToonLitTranslucentMaterial = BaseMToonLitTranslucentMaterial;
dst->OptMToonLitOpaqueMaterial = OptMToonLitOpaqueMaterial;
dst->OptMToonLitOpaqueTwoSidedMaterial = OptMToonLitOpaqueTwoSidedMaterial;
dst->OptMToonLitTranslucentMaterial = OptMToonLitTranslucentMaterial;
dst->OptMToonLitTranslucentTwoSidedMaterial = OptMToonLitTranslucentTwoSidedMaterial;
dst->BaseMToonUnlitOpaqueMaterial = BaseMToonUnlitOpaqueMaterial;
dst->BaseMToonUnlitTranslucentMaterial = BaseMToonUnlitTranslucentMaterial;
dst->OptMToonUnlitOpaqueMaterial = OptMToonUnlitOpaqueMaterial;
dst->OptMToonUnlitOpaqueTwoSidedMaterial = OptMToonUnlitOpaqueTwoSidedMaterial;
dst->OptMToonUnlitTranslucentMaterial = OptMToonUnlitTranslucentMaterial;
dst->OptMToonUnlitTranslucentTwoSidedMaterial = OptMToonUnlitTranslucentTwoSidedMaterial;
dst->OptMToonOutlineMaterial = OptMToonOutlineMaterial;
dst->BaseUnlitOpaqueMaterial = BaseUnlitOpaqueMaterial;
dst->BaseUnlitTranslucentMaterial = BaseUnlitTranslucentMaterial;
dst->BasePBROpaqueMaterial = BasePBROpaqueMaterial;
dst->BaseSkeletalMesh = BaseSkeletalMesh;
dst->VrmMetaObject = VrmMetaObject;
dst->VrmLicenseObject = VrmLicenseObject;
dst->Vrm1LicenseObject = Vrm1LicenseObject;
dst->SkeletalMesh = SkeletalMesh;
dst->Textures = Textures;
dst->Materials = Materials;
dst->HumanoidRig = HumanoidRig;
dst->Package = Package;
dst->FileFullPathName = FileFullPathName;
dst->OrigFileName = OrigFileName;
dst->BaseFileName = BaseFileName;
dst->HumanoidSkeletalMesh = HumanoidSkeletalMesh;
}
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(5,4,0)
void UVrmAssetListObject::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const
{
if (AssetImportData)
{
OutTags.Add(FAssetRegistryTag(SourceFileTagName(), AssetImportData->GetSourceData().ToJson(), FAssetRegistryTag::TT_Hidden));
OutTags.Add(FAssetRegistryTag("VRM4U", SourceFileTagName().ToString(), FAssetRegistryTag::TT_Hidden));
}
Super::GetAssetRegistryTags(OutTags);
}
#else
void UVrmAssetListObject::GetAssetRegistryTags(FAssetRegistryTagsContext Context) const
{
if (AssetImportData)
{
Context.AddTag(FAssetRegistryTag(SourceFileTagName(), AssetImportData->GetSourceData().ToJson(), FAssetRegistryTag::TT_Hidden));
Context.AddTag(FAssetRegistryTag("VRM4U", SourceFileTagName().ToString(), FAssetRegistryTag::TT_Hidden));
}
Super::GetAssetRegistryTags(Context);
}
#endif
void UVrmAssetListObject::WaitUntilAsyncPropertyReleased() const {
if (IsValid(SkeletalMesh) == false) {
return;
}
//SkeletalMesh->WaitUntilAsyncPropertyReleased(AsyncProperties);
}
#endif
@@ -0,0 +1,8 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmAssetUserData.h"
#include "VrmAssetListObject.h"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmCameraCheckComponent.h"
#if WITH_EDITOR
#include "Editor.h"
#include "EditorViewportClient.h"
#include "LevelEditorViewport.h"
#endif
UVrmCameraCheckComponent::UVrmCameraCheckComponent(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
void UVrmCameraCheckComponent::OnRegister() {
Super::OnRegister();
SetCameraCheck(true);
}
void UVrmCameraCheckComponent::OnUnregister() {
SetCameraCheck(false);
Super::OnUnregister();
}
#if WITH_EDITOR
void UVrmCameraCheckComponent::OnCameraTransformChanged(const FVector&, const FRotator&, ELevelViewportType, int32) {
OnCameraMove.Broadcast();
}
#endif
void UVrmCameraCheckComponent::SetCameraCheck(bool bCheckOn) {
#if WITH_EDITOR
if (bCheckOn) {
if (handle.IsValid()) {
FEditorDelegates::OnEditorCameraMoved.Remove(handle);
}
handle = FEditorDelegates::OnEditorCameraMoved.AddUObject(this, &UVrmCameraCheckComponent::OnCameraTransformChanged);
} else {
if (handle.IsValid()) {
FEditorDelegates::OnEditorCameraMoved.Remove(handle);
handle.Reset();
}
}
#endif
}
@@ -0,0 +1,17 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmCineCameraActor.h"
#include "VrmCineCameraComponent.h"
#include "Misc/EngineVersionComparison.h"
AVrmCineCameraActor::AVrmCineCameraActor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer
.SetDefaultSubobjectClass<UVrmCineCameraComponent>(TEXT("CameraComponent"))
)
{
}
UVrmCineCameraComponent* AVrmCineCameraActor::GetVrmCineCameraComponent() const {
return Cast<UVrmCineCameraComponent>(GetCineCameraComponent());
}
@@ -0,0 +1,54 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmCineCameraComponent.h"
#include "VrmDrawFrustumComponent.h"
#include "Misc/EngineVersionComparison.h"
void UVrmCineCameraComponent::GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView) {
Super::GetCameraView(DeltaTime, DesiredView);
DesiredView.OffCenterProjectionOffset = OffCenterProjectionOffset;
}
void UVrmCineCameraComponent::OnRegister()
{
#if WITH_EDITORONLY_DATA
AActor* MyOwner = GetOwner();
if ((MyOwner != nullptr) && !IsRunningCommandlet())
{
if (DrawFrustum == nullptr)
{
DrawFrustum = NewObject<UVrmDrawFrustumComponent>(MyOwner, NAME_None, RF_Transactional | RF_TextExportTransient);
DrawFrustum->SetupAttachment(this);
DrawFrustum->CreationMethod = CreationMethod;
DrawFrustum->RegisterComponentWithWorld(GetWorld());
#if UE_VERSION_OLDER_THAN(4,21,0)
#else
DrawFrustum->SetIsVisualizationComponent(true);
#endif
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
DrawFrustum->bFrustumEnabled = bDrawFrustumAllowed;
#endif
}
}
RefreshVisualRepresentation();
#endif // WITH_EDITORONLY_DATA
Super::OnRegister();
}
#if WITH_EDITORONLY_DATA
void UVrmCineCameraComponent::RefreshVisualRepresentation()
{
if (DrawFrustum != nullptr)
{
UVrmDrawFrustumComponent* v = Cast< UVrmDrawFrustumComponent>(DrawFrustum);
v->OffCenterProjectionOffset = OffCenterProjectionOffset;
}
Super::RefreshVisualRepresentation();
}
#endif
@@ -0,0 +1,10 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmCustomStruct.h"
#include "VRM4U.h"
#include "Modules/ModuleManager.h"
//#include "ISettingsModule.h"
@@ -0,0 +1,172 @@
// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DrawFrsutumComponent.cpp: UDrawFrsutumComponent implementation.
=============================================================================*/
#include "VrmDrawFrustumComponent.h"
#include "PrimitiveViewRelevance.h"
#include "PrimitiveSceneProxy.h"
#include "Engine/CollisionProfile.h"
#include "SceneManagement.h"
#include "SceneView.h"
#include "Misc/EngineVersionComparison.h"
/** Represents a draw frustum to the scene manager. */
class FVrmDrawFrustumSceneProxy final : public FPrimitiveSceneProxy
{
public:
SIZE_T GetTypeHash() const override
{
static size_t UniquePointer;
return reinterpret_cast<size_t>(&UniquePointer);
}
/**
* Initialization constructor.
* @param InComponent - game component to draw in the scene
*/
FVrmDrawFrustumSceneProxy(const UVrmDrawFrustumComponent* InComponent)
: FPrimitiveSceneProxy(InComponent)
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
, bFrustumEnabled(InComponent->bFrustumEnabled)
#endif
, FrustumColor(InComponent->FrustumColor)
, FrustumAngle(InComponent->FrustumAngle)
, FrustumAspectRatio(InComponent->FrustumAspectRatio)
, FrustumStartDist(InComponent->FrustumStartDist)
, FrustumEndDist(InComponent->FrustumEndDist)
, OffCenterProjectionOffset(InComponent->OffCenterProjectionOffset)
{
bWillEverBeLit = false;
}
// FPrimitiveSceneProxy interface.
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
{
QUICK_SCOPE_CYCLE_COUNTER( STAT_DrawFrustumSceneProxy_DrawDynamicElements );
FVector Direction(1,0,0);
FVector LeftVector(0,1,0);
FVector UpVector(0,0,1);
FVector Verts[8];
// FOVAngle controls the horizontal angle.
const float HozHalfAngleInRadians = FMath::DegreesToRadians(FrustumAngle * 0.5f);
float HozLength = 0.0f;
float VertLength = 0.0f;
if (FrustumAngle > 0.0f)
{
HozLength = FrustumStartDist * FMath::Tan(HozHalfAngleInRadians);
VertLength = HozLength / FrustumAspectRatio;
}
else
{
const float OrthoWidth = (FrustumAngle == 0.0f) ? 1000.0f : -FrustumAngle;
HozLength = OrthoWidth * 0.5f;
VertLength = HozLength / FrustumAspectRatio;
}
FVector Offset(0, OffCenterProjectionOffset.X, OffCenterProjectionOffset.Y);
// near plane verts
Verts[0] = (Direction * FrustumStartDist) + (UpVector * VertLength) + (LeftVector * HozLength) + (Offset * VertLength);
Verts[1] = (Direction * FrustumStartDist) + (UpVector * VertLength) - (LeftVector * HozLength) + (Offset * VertLength);
Verts[2] = (Direction * FrustumStartDist) - (UpVector * VertLength) - (LeftVector * HozLength) + (Offset * VertLength);
Verts[3] = (Direction * FrustumStartDist) - (UpVector * VertLength) + (LeftVector * HozLength) + (Offset * VertLength);
if (FrustumAngle > 0.0f)
{
HozLength = FrustumEndDist * FMath::Tan(HozHalfAngleInRadians);
VertLength = HozLength / FrustumAspectRatio;
}
// far plane verts
Verts[4] = (Direction * FrustumEndDist) + (UpVector * VertLength) + (LeftVector * HozLength) + (Offset * VertLength);
Verts[5] = (Direction * FrustumEndDist) + (UpVector * VertLength) - (LeftVector * HozLength) + (Offset * VertLength);
Verts[6] = (Direction * FrustumEndDist) - (UpVector * VertLength) - (LeftVector * HozLength) + (Offset * VertLength);
Verts[7] = (Direction * FrustumEndDist) - (UpVector * VertLength) + (LeftVector * HozLength) + (Offset * VertLength);
for (int32 X = 0; X < 8; ++X)
{
Verts[X] = GetLocalToWorld().TransformPosition(Verts[X]);
}
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
if (VisibilityMap & (1 << ViewIndex))
{
FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
const FSceneView* View = Views[ViewIndex];
const uint8 DepthPriorityGroup = GetDepthPriorityGroup(View);
PDI->DrawLine( Verts[0], Verts[1], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[1], Verts[2], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[2], Verts[3], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[3], Verts[0], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[4], Verts[5], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[5], Verts[6], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[6], Verts[7], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[7], Verts[4], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[0], Verts[4], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[1], Verts[5], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[2], Verts[6], FrustumColor, DepthPriorityGroup );
PDI->DrawLine( Verts[3], Verts[7], FrustumColor, DepthPriorityGroup );
}
}
}
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
{
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsShown(View) && View->Family->EngineShowFlags.CameraFrustums && bFrustumEnabled;
Result.bDynamicRelevance = true;
Result.bShadowRelevance = IsShadowCast(View);
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
return Result;
}
virtual uint32 GetMemoryFootprint( void ) const override { return( sizeof( *this ) + GetAllocatedSize() ); }
uint32 GetAllocatedSize( void ) const { return( FPrimitiveSceneProxy::GetAllocatedSize() ); }
#if RHI_RAYTRACING
virtual ERayTracingPrimitiveFlags GetCachedRayTracingInstance(FRayTracingInstance& OutRayTracingInstance) override
{
return ERayTracingPrimitiveFlags::UnsupportedProxyType;
}
#endif
private:
bool bFrustumEnabled;
FColor FrustumColor;
float FrustumAngle;
float FrustumAspectRatio;
float FrustumStartDist;
float FrustumEndDist;
FVector2D OffCenterProjectionOffset;
};
UVrmDrawFrustumComponent::UVrmDrawFrustumComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
FPrimitiveSceneProxy* UVrmDrawFrustumComponent::CreateSceneProxy()
{
return new FVrmDrawFrustumSceneProxy(this);
}
FBoxSphereBounds UVrmDrawFrustumComponent::CalcBounds(const FTransform& LocalToWorld) const
{
return FBoxSphereBounds( LocalToWorld.TransformPosition(FVector::ZeroVector), FVector(FrustumEndDist), FrustumEndDist );
}
@@ -0,0 +1,96 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
// ApplicationLifecycleComponent.cpp: Component to handle receiving notifications from the OS about application state (activated, suspended, termination, etc)
#include "VrmDropFiles.h"
#include "Misc/CoreDelegates.h"
#if PLATFORM_WINDOWS
#include "Windows/AllowWindowsPlatformTypes.h"
#include "commdlg.h"
#include "Windows/HideWindowsPlatformTypes.h"
#endif
UVrmDropFilesComponent::FStaticOnDropFiles UVrmDropFilesComponent::StaticOnDropFilesDelegate;
UVrmDropFilesComponent *UVrmDropFilesComponent::s_LatestActiveComponent = nullptr;
UVrmDropFilesComponent::UVrmDropFilesComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UVrmDropFilesComponent::OnRegister()
{
Super::OnRegister();
/*
FCoreDelegates::ApplicationWillDeactivateDelegate.AddUObject(this, &UApplicationLifecycleComponent::ApplicationWillDeactivateDelegate_Handler);
FCoreDelegates::ApplicationHasReactivatedDelegate.AddUObject(this, &UApplicationLifecycleComponent::ApplicationHasReactivatedDelegate_Handler);
FCoreDelegates::ApplicationWillEnterBackgroundDelegate.AddUObject(this, &UApplicationLifecycleComponent::ApplicationWillEnterBackgroundDelegate_Handler);
FCoreDelegates::ApplicationHasEnteredForegroundDelegate.AddUObject(this, &UApplicationLifecycleComponent::ApplicationHasEnteredForegroundDelegate_Handler);
FCoreDelegates::ApplicationWillTerminateDelegate.AddUObject(this, &UApplicationLifecycleComponent::ApplicationWillTerminateDelegate_Handler);
FCoreDelegates::ApplicationShouldUnloadResourcesDelegate.AddUObject(this, &UApplicationLifecycleComponent::ApplicationShouldUnloadResourcesDelegate_Handler);
FCoreDelegates::ApplicationReceivedStartupArgumentsDelegate.AddUObject(this, &UApplicationLifecycleComponent::ApplicationReceivedStartupArgumentsDelegate_Handler);
FCoreDelegates::OnTemperatureChange.AddUObject(this, &UApplicationLifecycleComponent::OnTemperatureChangeDelegate_Handler);
FCoreDelegates::OnLowPowerMode.AddUObject(this, &UApplicationLifecycleComponent::OnLowPowerModeDelegate_Handler);
*/
StaticOnDropFilesDelegate.AddUObject(this, &UVrmDropFilesComponent::OnDropFilesDelegate_Handler);
s_LatestActiveComponent = this;
}
void UVrmDropFilesComponent::OnUnregister()
{
Super::OnUnregister();
/*
FCoreDelegates::ApplicationWillDeactivateDelegate.RemoveAll(this);
FCoreDelegates::ApplicationHasReactivatedDelegate.RemoveAll(this);
FCoreDelegates::ApplicationWillEnterBackgroundDelegate.RemoveAll(this);
FCoreDelegates::ApplicationHasEnteredForegroundDelegate.RemoveAll(this);
FCoreDelegates::ApplicationWillTerminateDelegate.RemoveAll(this);
FCoreDelegates::ApplicationShouldUnloadResourcesDelegate.RemoveAll(this);
FCoreDelegates::ApplicationReceivedStartupArgumentsDelegate.RemoveAll(this);
FCoreDelegates::OnTemperatureChange.RemoveAll(this);
FCoreDelegates::OnLowPowerMode.RemoveAll(this);
*/
StaticOnDropFilesDelegate.RemoveAll(this);
if (s_LatestActiveComponent == this) {
s_LatestActiveComponent = nullptr;
}
}
bool UVrmDropFilesComponent::VRMGetOpenFileName(FString &FileName) {
FileName = "";
#if PLATFORM_WINDOWS
OPENFILENAME ofn = {};
TCHAR filename[MAX_PATH] = {};
filename[0] = '\0';
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
//ofn.hwndOwner = hWnd;
ofn.lpstrFilter =
TEXT("VRM file(*.vrm)\0*.vrm\0")
TEXT("all file(*.*)\0*.*\0\0");
ofn.lpstrFile = filename;
ofn.nMaxFile = sizeof(filename);
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
//ofn.lpstrDefExt = TEXT("*");
ofn.lpstrTitle = TEXT("Model");
if (GetOpenFileName(&ofn)) {
FileName = filename;
return true;
}
#endif
return false;
}
@@ -0,0 +1,215 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmEditorEventComponent.h"
#include "Misc/EngineVersionComparison.h"
#if WITH_EDITOR
#include "Editor.h"
#include "EditorViewportClient.h"
#include "LevelEditorViewport.h"
#include "Engine/Selection.h"
//#include "MovieSceneTrackEditor.h"
#if UE_VERSION_OLDER_THAN(4,26,0)
#elif UE_VERSION_OLDER_THAN(4,27,0)
#include "ILevelSequenceEditorToolkit.h"
#include "LevelSequenceEditor/Private/LevelSequenceEditorBlueprintLibrary.h"
#elif UE_VERSION_OLDER_THAN(5,0,0)
#include "ILevelSequenceEditorToolkit.h"
#include "LevelSequenceEditor/Public/LevelSequenceEditorBlueprintLibrary.h"
#elif UE_VERSION_OLDER_THAN(5,3,0)
#include "ILevelSequenceEditorToolkit.h"
#include "LevelSequenceEditor/Public/LevelSequenceEditorBlueprintLibrary.h"
#else
#include "ILevelSequenceEditorToolkit.h"
#include "LevelSequenceEditorBlueprintLibrary.h"
#endif
#if UE_VERSION_OLDER_THAN(5,5,0)
#else
#include "MovieSceneSequencePlayer.h"
#endif
#include "LevelSequence.h"
#include "ISequencer.h"
#endif
UVrmEditorEventComponent::UVrmEditorEventComponent(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
void UVrmEditorEventComponent::OnRegister() {
Super::OnRegister();
}
void UVrmEditorEventComponent::OnUnregister() {
Super::OnUnregister();
}
void UVrmEditorEventComponent::OnSelectionChangeFunc(UObject *obj) {
#if WITH_EDITOR
if (GEditor == nullptr) return;
bool bFound = false;
USelection* Selection = Cast<USelection>(obj);
if (Selection == GEditor->GetSelectedComponents() || Selection == GEditor->GetSelectedActors()){
for (int32 Idx = 0; Idx < Selection->Num(); Idx++)
{
const auto *a = Selection->GetSelectedObject(Idx);
if (a == this->GetOwner()) {
bFound = true;
break;
}
}
if (bFound && Selection->Num() == 1) {
OnSelectionChange.Broadcast(false);
}
}
#endif
}
void UVrmEditorEventComponent::OnSelectionObjectFunc(UObject *obj) {
#if WITH_EDITOR
if (GEditor == nullptr) return;
bool bFound = false;
USelection* Selection = Cast<USelection>(obj);
if (Selection == GEditor->GetSelectedComponents() || Selection == GEditor->GetSelectedActors()) {
for (int32 Idx = 0; Idx < Selection->Num(); Idx++)
{
if (Selection->GetSelectedObject(Idx) == this->GetOwner()) {
bFound = true;
break;
}
}
}
if (bFound) {
OnSelectionObject.Broadcast(false);
}
#endif
}
void UVrmEditorEventComponent::SetSelectCheck(bool bCheckOn) {
#if WITH_EDITOR
USelection::SelectionChangedEvent.AddUObject(this, &UVrmEditorEventComponent::OnSelectionChangeFunc);
USelection::SelectObjectEvent.AddUObject(this, &UVrmEditorEventComponent::OnSelectionObjectFunc);
//SelectObjectEvent
if (bCheckOn) {
//GEditor->OnEndCameraMovement.Assign(OnCameraMove)
//if (GEditor->GetActiveViewport()) {
// FEditorViewportClient* ViewportClient = StaticCast<FEditorViewportClient*>(GEditor->GetActiveViewport()->GetClient());
// if (ViewportClient) {
// ViewportClient->SetActorLock(this->GetOwner());
// }
//}
//GCurrentLevelEditingViewportClient->SetActorLock(this->GetOwner());
//GEditor->OnEndCameraMovement().AddUObject(this, &UVrmCameraCheckComponent::OnCameraTransformChanged);
//GEditor->OnBeginCameraMovement().AddUObject(this, &UVrmCameraCheckComponent::OnCameraTransformChanged);
//handle = FEditorDelegates::OnEditorCameraMoved.AddUObject(this, &UVrmCameraCheckComponent::OnCameraTransformChanged);
} else {
//if (handle.IsValid()) {
//FEditorDelegates::OnEditorCameraMoved.Remove(handle);
// }
//GEditor->OnEndCameraMovement().Remove
}
//FOnEndTransformCamera& () { return OnEndCameraTransformEvent; }
#endif
}
void UVrmEditorEventComponent::OnGlobalTimeChangeFunc() {
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(4,26,0)
#elif UE_VERSION_OLDER_THAN(5,5,0)
int32 t = ULevelSequenceEditorBlueprintLibrary::GetCurrentTime();
OnGlobalTimeChange.Broadcast((float)t);
#else
//int32 t = ULevelSequenceEditorBlueprintLibrary::GetCurrentTime();
auto mm = ULevelSequenceEditorBlueprintLibrary::GetGlobalPosition();
int32 t = mm.Timecode.Frames;
OnGlobalTimeChange.Broadcast((float)t);
#endif
#endif
}
void UVrmEditorEventComponent::SetGlobalTimeCheck(bool bCheckOn) {
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(4,26,0)
#else
{
if (GEditor == nullptr) return;
auto *LevelSeq = ULevelSequenceEditorBlueprintLibrary::GetCurrentLevelSequence();
if (LevelSeq == nullptr) return;
IAssetEditorInstance* AssetEditor = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->FindEditorForAsset(LevelSeq, false);
if (AssetEditor == nullptr) return;
ILevelSequenceEditorToolkit* LevelSequenceEditor = static_cast<ILevelSequenceEditorToolkit*>(AssetEditor);
if (LevelSequenceEditor == nullptr){
return;
}
TWeakPtr<ISequencer> seq = LevelSequenceEditor->GetSequencer();
if (seq.IsValid()) {
seq.Pin()->OnGlobalTimeChanged().AddUObject(this, &UVrmEditorEventComponent::OnGlobalTimeChangeFunc);
}
}
/*
ALevelSequenceActor* LevelSequenceActor = nullptr;
for (ALevelSequenceActor* ExistingLevelSequenceActor : TActorRange<ALevelSequenceActor>(MeshActor->GetWorld()))
{
LevelSequenceActor = ExistingLevelSequenceActor;
break;
}
*/
//auto *seq = ULevelSequenceEditorBlueprintLibrary::GetCurrentLevelSequence();
//if (seq = nullptr) {
//USelection::SelectionChangedEvent.AddUObject(this, &UVrmEditorEventComponent::OnSelectionChangeFunc);
//USelection::SelectObjectEvent.AddUObject(this, &UVrmEditorEventComponent::OnSelectionObjectFunc);
//}
//seq->OnGlobalTimeChanged().AddRaw(this, &UVrmEditorEventComponent::OnGlobalTimeChangeFunc);
//USelection::SelectionChangedEvent.AddUObject(this, &UVrmEditorEventComponent::OnSelectionChangeFunc);
//USelection::SelectObjectEvent.AddUObject(this, &UVrmEditorEventComponent::OnSelectionObjectFunc);
#endif
#endif
}
void UVrmEditorEventComponent::OnPIEEventFunc(EVRM4U_PIEEvent e) {
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(4,26,0)
#else
OnPIEEvent.Broadcast(e);
#endif
#endif
}
void UVrmEditorEventComponent::OnBeginPIE(const bool bIsSimulating) {
OnPIEEventFunc(EVRM4U_PIEEvent::BeginPIE);
}
void UVrmEditorEventComponent::OnEndPIE(const bool bIsSimulating) {
OnPIEEventFunc(EVRM4U_PIEEvent::EndPIE);
}
void UVrmEditorEventComponent::SetPIEEventCheck(bool bCheckOn) {
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(4,26,0)
#else
{
FEditorDelegates::BeginPIE.AddUObject(this, &UVrmEditorEventComponent::OnBeginPIE);
FEditorDelegates::EndPIE.AddUObject(this, &UVrmEditorEventComponent::OnEndPIE);
}
#endif
#endif
}
@@ -0,0 +1,196 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmHMDTrackingComponent.h"
#if WITH_VRM4U_HMD_TRACKER
#include "Misc/EngineVersionComparison.h"
#include "../Private/OculusHMDModule.h"
#include "../Private/OculusHMD.h"
#include "../Private/OculusHMD_Settings.h"
namespace VRM4ULocal {
FORCEINLINE FQuat ToFQuat(const ovrpQuatf& InQuat)
{
return FQuat(-InQuat.z, InQuat.x, InQuat.y, -InQuat.w);
}
/** Converts FQuat to ovrpQuatf */
FORCEINLINE ovrpQuatf ToOvrpQuatf(const FQuat& InQuat)
{
return ovrpQuatf{ InQuat.Y, InQuat.Z, -InQuat.X, -InQuat.W };
}
/** Converts vector from Oculus to Unreal */
FORCEINLINE FVector ToFVector(const ovrpVector3f& InVec)
{
return FVector(-InVec.z, InVec.x, InVec.y);
}
}
#endif
UVrmHMDTrackingComponent::UVrmHMDTrackingComponent(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
//PrimaryComponentTick.TickGroup;
PrimaryComponentTick.bStartWithTickEnabled = true;
PrimaryComponentTick.bCanEverTick = true;
bAutoActivate = true;
}
void UVrmHMDTrackingComponent::OnRegister() {
Super::OnRegister();
}
void UVrmHMDTrackingComponent::OnUnregister() {
Super::OnUnregister();
}
void UVrmHMDTrackingComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) {
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
#if WITH_VRM4U_HMD_TRACKER
bEnableLeft = false;
bEnableRight = false;
bEnableHead = false;
float WoldToMetersScale = 100.f;
{
OculusHMD::FOculusHMD* OculusHMD = (OculusHMD::FOculusHMD*)(GEngine->XRSystem.Get());
if (!OculusHMD)
return;
OculusHMD::FSettings* s = OculusHMD->GetSettings();
ovrpPoseStatef PoseState;
OculusHMD::FPose Pose;
WoldToMetersScale = OculusHMD->GetWorldToMetersScale();
if (OVRP_FAILURE(FOculusHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, ovrpNode_Head, &PoseState)) ||
!OculusHMD->ConvertPose_Internal(PoseState.Pose, Pose, s, WoldToMetersScale))
{
return;
}
HeadPos = Pose.Position;
HeadRot = Pose.Orientation.Rotator();
bEnableHead = true;
}
{
ovrpHand eHandState[] = {
ovrpHand_Left,
ovrpHand_Right,
};
ovrpSkeletonType eSkeletonType[] = {
ovrpSkeletonType_HandLeft,
ovrpSkeletonType_HandRight,
};
TArray<FTransform>* handTrans[] = {
&leftHand,
&rightHand,
};
TArray<FTransform>* handReferenceTrans[] = {
&leftHandReference,
&rightHandReference,
};
TArray<float>* pinch[] = {
&leftPinch,
&rightPinch,
};
{
ovrpControllerState4 OvrpControllerState;
if (OVRP_SUCCESS(FOculusHMDModule::GetPluginWrapper().GetControllerState4((ovrpController)(ovrpController_LHand | ovrpController_RHand | ovrpController_Hands), &OvrpControllerState))) {
OvrpControllerState.ConnectedControllerTypes++;
}
}
for (int handCount = 0; handCount < 2; ++handCount) {
ovrpHandState handState;
if (OVRP_SUCCESS(FOculusHMDModule::GetPluginWrapper().GetHandState(ovrpStep_Render, eHandState[handCount], &handState)) == false) {
continue;
}
if (handCount == 0) {
bEnableLeft = true;
} else {
bEnableRight = true;
}
rootScale = handState.HandScale;
(*(pinch[handCount])).SetNum(ovrpHandFinger_Max);
for (int i = 0; i < leftPinch.Num(); ++i) {
(*(pinch[handCount]))[i] = handState.PinchStrength[i];
}
#if UE_VERSION_OLDER_THAN(4,27,0)
ovrpSkeleton skeleton;
if (FOculusHMDModule::GetPluginWrapper().GetSkeleton(eSkeletonType[handCount], &skeleton) == 0) {
#elif UE_VERSION_OLDER_THAN(5,0,0)
ovrpSkeleton2 skeleton;
if (FOculusHMDModule::GetPluginWrapper().GetSkeleton2(eSkeletonType[handCount], &skeleton) == 0) {
#else
ovrpSkeleton skeleton;
if (FOculusHMDModule::GetPluginWrapper().GetSkeleton(eSkeletonType[handCount], &skeleton) == 0) {
#endif
handTrans[handCount]->SetNum(skeleton.NumBones);
handReferenceTrans[handCount]->SetNum(skeleton.NumBones);
for (uint32_t i = 0; i < skeleton.NumBones; ++i) {
int boneID = skeleton.Bones[i].BoneId;
//auto aa = VRM4ULocal::ToFQuat(handState.BoneRotations[boneID]);
auto curRot = VRM4ULocal::ToFQuat(handState.BoneRotations[boneID]);
auto skeletonRot = VRM4ULocal::ToFQuat(skeleton.Bones[i].Pose.Orientation);
auto skeletonPos = VRM4ULocal::ToFVector(skeleton.Bones[i].Pose.Position) * WoldToMetersScale;
auto t = FTransform(curRot, skeletonPos);
auto t_ref = FTransform(skeletonRot, skeletonPos);
int parentBone = skeleton.Bones[i].ParentBoneIndex;
if (parentBone >= 0) {
t = t * (*(handTrans[handCount]))[parentBone];
t_ref = t_ref * (*(handReferenceTrans[handCount]))[parentBone];
} else {
{
auto q1 = VRM4ULocal::ToFQuat(handState.RootPose.Orientation);
auto p1 = VRM4ULocal::ToFVector(handState.RootPose.Position) * WoldToMetersScale;
t = t * FTransform(q1, p1);
}
{
auto q2 = VRM4ULocal::ToFQuat(skeleton.Bones[i].Pose.Orientation);
auto p2 = VRM4ULocal::ToFVector(skeleton.Bones[i].Pose.Position) * WoldToMetersScale;
t_ref = t_ref * FTransform(q2, p2);
}
}
(*(handTrans[handCount]))[i] = t;
(*(handReferenceTrans[handCount]))[i] = t_ref;
}
}
}
}
bEnableTracking = true;
//ovrpBool handTrackingEnabled = false;
//auto res = FOculusHMDModule::GetPluginWrapper().GetHandTrackingEnabled(&handTrackingEnabled);
//str2 = FString::Printf(TEXT("%d"), handTrackingEnabled);
//str2 = handTrackingEnabled;
#endif
}
@@ -0,0 +1,69 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "VrmHMDTrackingComponent.generated.h"
/**
*
*/
UCLASS(meta=(BlueprintSpawnableComponent))
class VRM4U_API UVrmHMDTrackingComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
float rootScale;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
TArray<FTransform> rightHand;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
TArray<FTransform> leftHand;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
TArray<FTransform> rightHandReference;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
TArray<FTransform> leftHandReference;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
TArray<float> rightPinch;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
TArray<float> leftPinch;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
FVector HeadPos;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
FRotator HeadRot;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
FString dummyForLog;
UPROPERTY(BlueprintReadOnly, Category = Character)
bool bEnableLeft;
UPROPERTY(BlueprintReadOnly, Category = Character)
bool bEnableRight;
UPROPERTY(BlueprintReadOnly, Category = Character)
bool bEnableHead;
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (DynamicOutputParam = "OutVrmAsset"))
bool IsEnable() const {
return bEnableTracking;
};
public:
void OnRegister() override;
void OnUnregister() override;
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
bool bEnableTracking = false;;
};
@@ -0,0 +1,7 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmImportMaterialSet.h"
//UVrmImportMaterialSet::UVrmImportMaterialSet() {
//}
@@ -0,0 +1,6 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmLicenseObject.h"
@@ -0,0 +1,8 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmMetaObject.h"
@@ -0,0 +1,28 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmModelActor.h"
// Sets default values
AVrmModelActor::AVrmModelActor(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AVrmModelActor::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AVrmModelActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
@@ -0,0 +1,47 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmNetworkBPFunctionLibrary.h"
#include "VRM4U.h"
#include "Engine/Engine.h"
#include "Logging/MessageLog.h"
#include "Misc/EngineVersionComparison.h"
#if PLATFORM_WINDOWS
#include "Windows/AllowWindowsPlatformTypes.h"
#include <windows.h>
#include <iphlpapi.h>
#include <winsock.h>
#include "Windows/HideWindowsPlatformTypes.h"
#endif
void UVrmNetworkBPFunctionLibrary::VRMGetIPAddressTable(TArray<FString> &AddressTable) {
AddressTable.Empty();
#if PLATFORM_WINDOWS
DWORD dwSize = 0;
TArray<uint8> IPAddrTableBuffer;
IPAddrTableBuffer.SetNum(sizeof(MIB_IPADDRTABLE));
if (GetIpAddrTable(nullptr, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
IPAddrTableBuffer.SetNum(dwSize);
}
auto dwRetVal = GetIpAddrTable(reinterpret_cast<MIB_IPADDRTABLE*>(IPAddrTableBuffer.GetData()), &dwSize, 0);
if ( dwRetVal != NO_ERROR ) {
UE_LOG(LogVRM4U, Warning, TEXT("GetIpAddrTable call failed with %d\n"), dwRetVal);
}
{
MIB_IPADDRTABLE* pIPAddrTable = reinterpret_cast<MIB_IPADDRTABLE*>(IPAddrTableBuffer.GetData());
for (DWORD i = 0; i < pIPAddrTable->dwNumEntries; ++i) {
AddressTable.Add(inet_ntoa(*(struct in_addr*)&pIPAddrTable->table[i].dwAddr));
}
}
#endif
}
@@ -0,0 +1,103 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmPoseableMeshComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "VrmAnimInstance.h"
#include "VrmUtil.h"
UVrmPoseableMeshComponent::UVrmPoseableMeshComponent(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
PrimaryComponentTick.bCanEverTick = true;
// for morph curve copy
bTickInEditor = true;
}
void UVrmPoseableMeshComponent::OnRegister() {
Super::OnRegister();
if (bUseDefaultMaterial) {
this->OverrideMaterials.Empty();
}
Init();
UpdateLeader();
}
#if WITH_EDITOR
void UVrmPoseableMeshComponent::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) {
Super::PostEditChangeProperty(PropertyChangedEvent);
UpdateLeader();
}
void UVrmPoseableMeshComponent::PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) {
Super::PostEditChangeChainProperty(PropertyChangedEvent);
}
#endif
void UVrmPoseableMeshComponent::OnAttachmentChanged() {
Super::OnAttachmentChanged();
}
void UVrmPoseableMeshComponent::InitializeComponent() {
Super::InitializeComponent();
}
void UVrmPoseableMeshComponent::UpdateLeader() {
if (bUseParentAsLeader) {
USkinnedMeshComponent* skin = Cast<USkinnedMeshComponent>(this->GetAttachParent());
USkeletalMeshComponent* skel = Cast<USkeletalMeshComponent>(skin);
#if UE_VERSION_OLDER_THAN(5,1,0)
SetMasterPoseComponent(skin);
#else
SetLeaderPoseComponent(skin);
#endif
VRMCopyPoseAndMorphFromSkeletalComponent(skel);
}
}
void UVrmPoseableMeshComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) {
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
#if UE_VERSION_OLDER_THAN(4,20,0)
#else
#if UE_VERSION_OLDER_THAN(5,1,0)
USkinnedMeshComponent* MPCPtr = MasterPoseComponent.Get();
#else
USkinnedMeshComponent* MPCPtr = LeaderPoseComponent.Get();
#endif
if (MPCPtr) {
MorphTargetWeights = MPCPtr->MorphTargetWeights;
ActiveMorphTargets = MPCPtr->ActiveMorphTargets;
}
#endif
}
void UVrmPoseableMeshComponent::VRMCopyPoseAndMorphFromSkeletalComponent(USkeletalMeshComponent* InComponentToCopy) {
if (InComponentToCopy && VRMGetSkinnedAsset(InComponentToCopy)) {
Super::CopyPoseFromSkeletalComponent(InComponentToCopy);
MorphTargetWeights = InComponentToCopy->MorphTargetWeights;
ActiveMorphTargets = InComponentToCopy->ActiveMorphTargets;
}
}
void UVrmPoseableMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* TickFunction)
{
Super::RefreshBoneTransforms(TickFunction);
#if UE_VERSION_OLDER_THAN(5,1,0)
USkinnedMeshComponent* MPCPtr = MasterPoseComponent.Get();
#else
USkinnedMeshComponent* MPCPtr = LeaderPoseComponent.Get();
#endif
if (MPCPtr) {
MorphTargetWeights = MPCPtr->MorphTargetWeights;
ActiveMorphTargets = MPCPtr->ActiveMorphTargets;
}
}
@@ -0,0 +1,38 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmRuntimeSettings.h"
#if WITH_EDITOR
#include "Editor/EditorEngine.h"
#include "Misc/MessageDialog.h"
#include "UnrealEdMisc.h"
#include "Misc/ConfigCacheIni.h"
#include "HAL/PlatformFileManager.h"
#endif
#define LOCTEXT_NAMESPACE "VRM4U"
UVrmRuntimeSettings::UVrmRuntimeSettings(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bDropVRMFileEnable = false;
AssetListObject.SetPath(TEXT("/VRM4U/VrmAssetListObjectBP.VrmAssetListObjectBP"));
}
#if WITH_EDITOR
void UVrmRuntimeSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) {
Super::PostEditChangeProperty(PropertyChangedEvent);
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UVrmRuntimeSettings, bAllowAllAssimpFormat)
&& bAllowAllAssimpFormat)
{
FString FullPath = FPaths::ConvertRelativePathToFull(GetDefaultConfigFilename());
FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*FullPath, false);
auto DialogText(LOCTEXT("VRM4UImportWarning", "Please check the license of the model before using it.\n\nAssImp対応フォーマットのインポートを有効化しました。\nモデルのライセンスに従ってご利用ください。"));
FMessageDialog::Open(EAppMsgType::Ok, DialogText);
}
}
#endif
@@ -0,0 +1,915 @@
#include "VrmSpringBone.h"
#include "VrmAssetListObject.h"
#include "Engine/World.h"
VrmSpringBone::VrmSpringBone()
{
}
VrmSpringBone::~VrmSpringBone()
{
}
namespace VRMSpringBone {
void VRMSpring::Update(const FAnimNode_VrmSpringBone* animNode, float DeltaTime, FTransform ComponentToLocal,
const TArray<VRMSpringColliderGroup>& colliderGroup,
FComponentSpacePoseContext& Output) {
if (skeletalMesh == nullptr) {
return;
}
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
// モデルローカル座標
ComponentToLocal = ComponentTransform.Inverse();
//
// x10 adjust?
FVector ue4grav(-gravityDir.X, gravityDir.Z, gravityDir.Y);
const int MAX_LOOP = FMath::Max(1, animNode->loopc);
for (int i = 0; i < MAX_LOOP; ++i) {
//const float stiffnessForce = stiffness * DeltaTime * 10.f * animNode->stiffnessScale + animNode->stiffinessAdd;
//FVector external = ComponentToLocal.TransformVector(ue4grav) * (gravityPower * DeltaTime) * animNode->gravityScale + ComponentToLocal.TransformVector(animNode->gravityAdd) * DeltaTime;
//external *= 100.f; // to unreal scale
float CurrentDeltaTime = DeltaTime / (float)MAX_LOOP;
const float stiffnessForce = stiffness * CurrentDeltaTime * 10.f * animNode->stiffnessScale + animNode->stiffnessAdd;
FVector external = ComponentToLocal.TransformVector(ue4grav) * (gravityPower * CurrentDeltaTime) * animNode->gravityScale + ComponentToLocal.TransformVector(animNode->gravityAdd) * CurrentDeltaTime;
//wind
if (animNode->bIgnoreWindDirectionalSource == false) {
const USkeletalMeshComponent* SkelComp = Output.AnimInstanceProxy->GetSkelMeshComponent();
//InAnimInstance->GetSkelMeshComponent();
const UWorld* World = nullptr;
if (SkelComp) {
World = SkelComp->GetWorld();
}
FSceneInterface* Scene = nullptr;
if (World) {
Scene = World->Scene;
}
if (Scene)
{
// Unused by our simulation but needed for the call to GetWindParameters below
float WindMinGust;
float WindMaxGust;
FVector WindDirection;
float WindSpeed;
// Setup wind data
//Body->bWindEnabled = true;
//Scene->GetWindParameters_GameThread(SkelComp->GetComponentTransform().TransformPosition(Body->Pose.Position), Body->WindData.WindDirection, Body->WindData.WindSpeed, WindMinGust, WindMaxGust);
Scene->GetWindParameters_GameThread(SkelComp->GetComponentTransform().GetLocation(), WindDirection, WindSpeed, WindMinGust, WindMaxGust);
WindDirection = SkelComp->GetComponentTransform().Inverse().TransformVector(WindDirection);
// from AnimPhysicsSolver
const float WindUnitScale = 0.5f * 250.0f * FMath::FRandRange(1.f - animNode->randomWindRange, 1.f + animNode->randomWindRange) * animNode->windScale;
//
// Wind velocity in body space
FVector WindVelocity = WindDirection * WindSpeed * WindUnitScale;// *BodyWindScale;
WindVelocity *= CurrentDeltaTime;
//Body->WindData.WindDirection = SkelComp->GetComponentTransform().Inverse().TransformVector(Body->WindData.WindDirection);
//Body->WindData.WindAdaption = FMath::FRandRange(0.0f, 2.0f);
//Body->WindData.BodyWindScale = WindScale;
//if (CVarEnableWind.GetValueOnAnyThread() == 1 && bEnableWind)
external += WindVelocity / 100.f;
}
}// wind end
external *= 100.f; // to unreal scale
FVector external_noAdd = ComponentToLocal.TransformVector(ue4grav) * (gravityPower * CurrentDeltaTime) * animNode->gravityScale;
external_noAdd *= 100.f; // to unreal scale
const auto WorldContext = Output.AnimInstanceProxy->GetSkelMeshComponent();
for (int springCount = 0; springCount < SpringDataChain.Num(); ++springCount) {
auto& ChainRoot = SpringDataChain[springCount];
FTransform currentTransform = FTransform::Identity;
bool bSkipGravAdd = false;
for (int chainCount = 0; chainCount < ChainRoot.Num(); ++chainCount) {
auto& sData = ChainRoot[chainCount];
FVector currentTail = ComponentToLocal.TransformPosition(sData.m_currentTail);
FVector prevTail = ComponentToLocal.TransformPosition(sData.m_prevTail);
int myBoneIndex = RefSkeleton.FindBoneIndex(sData.boneName);
if (myBoneIndex < 0) {
continue;
}
if (animNode->NoWindBoneNameList.Contains(sData.boneName)) {
bSkipGravAdd = true;
}
int myParentBoneIndex = RefSkeleton.GetParentIndex(myBoneIndex);
//currentTransform = FTransform::Identity;
FQuat ParentRotation = FQuat::Identity;
if (chainCount == 0) {
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(myBoneIndex);
//FCompactPoseBoneIndex uu(myBoneIndex);
if (Output.Pose.GetPose().IsValidIndex(uu) == false) {
continue;
}
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(uu);
ParentRotation = NewBoneTM.GetRotation();
currentTransform = NewBoneTM;
}
else {
auto c = RefSkeletonTransform[sData.boneIndex];
auto t = c * currentTransform;
ParentRotation = t.GetRotation();
currentTransform = t;
}
FQuat m_localRotation = FQuat::Identity;
// verlet積分で次の位置を計算
FVector nextTail = currentTail
+ (currentTail - prevTail) * (1.0f - dragForce) // 前フレームの移動を継続する(減衰もあるよ)
+ ParentRotation * m_localRotation * sData.m_boneAxis * stiffnessForce // 親の回転による子ボーンの移動目標
;
if (bSkipGravAdd) {
nextTail += external_noAdd; // 外力による移動量
}
else {
nextTail += external; // 外力による移動量
}
// 長さをboneLengthに強制
//nextTail = sData.m_transform.GetLocation() + (nextTail - sData.m_transform.GetLocation()).GetSafeNormal() * sData.m_length;
nextTail = currentTransform.GetLocation() + (nextTail - currentTransform.GetLocation()).GetSafeNormal() * sData.m_length;
// Collisionで移動
// vrm <-> physics collision
if (animNode->bIgnorePhysicsCollision == false) {
const int ColCount = animNode->collisionCheckLoopCount;
for (int colc = 0; colc < ColCount; ++colc) {
FVector Start = ComponentToLocal.InverseTransformPosition(nextTail);
FVector End = Start + FVector(0.001f);
//* WorldContextObject
float Radius = hitRadius * 100.f;
ETraceTypeQuery TraceChannel = ETraceTypeQuery::TraceTypeQuery1;
bool bTraceComplex = false;
TArray<AActor*> ActorsToIgnore;
EDrawDebugTrace::Type DrawDebugType = EDrawDebugTrace::None;
TArray<FHitResult> OutHits;
bool bIgnoreSelf = true;
FLinearColor TraceColor(EForceInit::ForceInit);
FLinearColor TraceHitColor(EForceInit::ForceInit);
float DrawTime = 0.f;
bool b = UKismetSystemLibrary::SphereTraceMulti(WorldContext, Start, End, hitRadius * 100.f,
TraceChannel, false, ActorsToIgnore,
DrawDebugType,
OutHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime);
if (b == false) {
break;
}
for (auto hit : OutHits) {
{
//WorldContext->GetOwner
//hit.BoneName
}
float r = hit.PenetrationDepth; // hitRadius * 100.f + hit.Distance;
auto normal = hit.Normal;
auto posFromCollider = nextTail + normal * r; // (float)ColCount;
// 長さをboneLengthに強制
nextTail = currentTransform.GetLocation() + (posFromCollider - currentTransform.GetLocation()).GetSafeNormal() * sData.m_length;
}
}
}
// vrm <-> vrm collision
if (animNode->bIgnoreVRMCollision == false) {
for (auto ind : ColliderGroupIndexArray) {
if (ind >= colliderGroup.Num()) {
continue;
}
const auto& cg = colliderGroup[ind];
int ii = RefSkeleton.FindBoneIndex(cg.node_name);
if (ii < 0) {
continue;
}
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(ii);
//FCompactPoseBoneIndex uu(ii);
if (uu == INDEX_NONE) {
continue;
}
FTransform collisionBoneTrans = Output.Pose.GetComponentSpaceTransform(uu);
for (auto c : cg.colliders) {
float r = (hitRadius + c.radius) * 100.f;
//FVector v = collisionBoneTrans.TransformPosition(c.offset*100);
auto offs = c.offset;
//offs.Set(offs.X, -offs.Z, offs.Y); // 本来はこれが正しいが、VRM0の座標が間違っている
offs.Set(-offs.X, offs.Z, offs.Y); // VRM0の仕様としては これ
offs *= 100;
FVector v = collisionBoneTrans.TransformPosition(offs);
if ((v - nextTail).SizeSquared() > r * r) {
continue;
}
// ヒット。Colliderの半径方向に押し出す
auto normal = (nextTail - v).GetSafeNormal();
auto posFromCollider = v + normal * (r);
// 長さをboneLengthに強制
nextTail = currentTransform.GetLocation() + (posFromCollider - currentTransform.GetLocation()).GetSafeNormal() * sData.m_length;
}
}
}
sData.m_prevTail = ComponentToLocal.InverseTransformPosition(currentTail);
sData.m_currentTail = ComponentToLocal.InverseTransformPosition(nextTail);
FQuat rotation = ParentRotation * m_localRotation;
sData.m_resultQuat = FQuat::FindBetween((rotation * sData.m_boneAxis).GetSafeNormal(),
(nextTail - currentTransform.GetLocation()).GetSafeNormal()) * rotation;
currentTransform.SetRotation(sData.m_resultQuat);
}
}// chain loop
}// delta time loop
}
void VRMSpringManager::reset() {
spring.Empty();
bInit = false;
}
void VRMSpringManager::init(const UVrmMetaObject* meta, FComponentSpacePoseContext& Output) {
if (meta == nullptr) return;
if (bInit) return;
if (meta->GetVRMVersion() == 1) return;
if (meta->VrmAssetListObject == nullptr) return;
skeletalMesh = VRMGetSkinnedAsset(Output.AnimInstanceProxy->GetSkelMeshComponent());
//skeletalMesh = meta->SkeletalMesh;
const FReferenceSkeleton& RefSkeleton = VRMGetRefSkeleton(skeletalMesh);
const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
spring.SetNum(meta->VRMSpringMeta.Num());
for (int i = 0; i < spring.Num(); ++i) {
auto& s = spring[i];
const auto& metaS = meta->VRMSpringMeta[i];
s.skeletalMesh = skeletalMesh;// meta->SkeletalMesh;
s.stiffness = metaS.stiffness;
s.gravityPower = metaS.gravityPower;
s.gravityDir = meta->VrmAssetListObject->model_root_transform.TransformVector(metaS.gravityDir);
s.dragForce = metaS.dragForce;
s.hitRadius = metaS.hitRadius;
s.RootSpringData.SetNum(metaS.bones.Num());
for (int scount = 0; scount < s.RootSpringData.Num(); ++scount) {
s.RootSpringData[scount].boneName = *metaS.boneNames[scount];
s.RootSpringData[scount].boneIndex = RefSkeleton.FindBoneIndex(*metaS.boneNames[scount]);
}
// TODO add child
s.SpringDataChain.SetNum(metaS.bones.Num());
for (int scount = 0; scount < s.RootSpringData.Num(); ++scount) {
auto& chain = s.SpringDataChain[scount];
//root
{
auto index = VRMGetRefSkeleton(skeletalMesh).FindBoneIndex(*metaS.boneNames[scount]);
if (index == INDEX_NONE) {
continue;
}
auto& sData = chain.AddDefaulted_GetRef();
sData.boneName = *metaS.boneNames[scount];
sData.boneIndex = index;
TArray<int32> Children;
VRMUtil::GetDirectChildBones(VRMGetRefSkeleton(skeletalMesh), sData.boneIndex, Children);
if (Children.Num() > 0) {
sData.m_boneAxis = RefSkeletonTransform[Children[0]].GetLocation();
}
else {
sData.m_boneAxis = RefSkeletonTransform[sData.boneIndex].GetLocation() * 0.7f;
}
}
// child
if (1) {
for (int chainCount = 0; chainCount < 100; ++chainCount) {
bool bLast = false;
TArray<int32> Children;
VRMUtil::GetDirectChildBones(VRMGetRefSkeleton(skeletalMesh), chain[chainCount].boneIndex, Children);
if (Children.Num() <= 0) {
break;
}
auto& sData = chain.AddDefaulted_GetRef();
sData.boneIndex = Children[0];
sData.boneName = *RefSkeleton.GetBoneName(sData.boneIndex).ToString();
VRMUtil::GetDirectChildBones(VRMGetRefSkeleton(skeletalMesh), sData.boneIndex, Children);
if (Children.Num() > 0) {
sData.m_boneAxis = RefSkeletonTransform[Children[0]].GetLocation();
}
else {
sData.m_boneAxis = RefSkeletonTransform[sData.boneIndex].GetLocation() * 0.7f;
}
}
}
}
s.ColliderGroupIndexArray.SetNum(metaS.ColliderIndexArray.Num());
for (int c = 0; c < s.ColliderGroupIndexArray.Num(); ++c) {
s.ColliderGroupIndexArray[c] = metaS.ColliderIndexArray[c];
}
}
// init default transform
{
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
for (auto& s : spring) {
for (auto& root : s.SpringDataChain) {
FTransform currentTransform = FTransform::Identity;
for (int ChildCount = 0; ChildCount < root.Num(); ++ChildCount) {
//for (auto& sData : root) {
auto& sData = root[ChildCount];
sData.m_length = sData.m_boneAxis.Size();
int myBoneIndex = RefSkeleton.FindBoneIndex(sData.boneName);
#if UE_VERSION_OLDER_THAN(5,0,0)
if (sData.boneIndex >= Output.Pose.GetPose().GetBoneContainer().GetSkeletonToPoseBoneIndexArray().Num()) {
continue;
}
#else
if (Output.Pose.GetPose().GetBoneContainer().GetMeshPoseIndexFromSkeletonPoseIndex(FSkeletonPoseBoneIndex(sData.boneIndex)) == FMeshPoseBoneIndex(INDEX_NONE)) {
continue;
}
#endif
{
FQuat ParentRotation = FQuat::Identity;
if (ChildCount == 0) {
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(myBoneIndex);
if (Output.Pose.GetPose().IsValidIndex(uu) == false) {
continue;
}
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(uu);
ParentRotation = NewBoneTM.GetRotation();
currentTransform = NewBoneTM;
}
else {
auto c = RefSkeletonTransform[sData.boneIndex];
auto t = c * currentTransform;
ParentRotation = t.GetRotation();
currentTransform = t;
}
}
FVector v = currentTransform.GetLocation() + sData.m_boneAxis;
sData.m_currentTail = sData.m_prevTail = ComponentTransform.TransformPosition(v);
}
}
}
}
// collider
colliderGroup.SetNum(meta->VRMColliderMeta.Num());
for (int i = 0; i < colliderGroup.Num(); ++i) {
auto& cg = colliderGroup[i];
const auto& cmeta = meta->VRMColliderMeta[i];
cg.node = cmeta.bone;
cg.node_name = *cmeta.boneName;
cg.colliders.SetNum(cmeta.collider.Num());
for (int c = 0; c < cg.colliders.Num(); ++c) {
cg.colliders[c].offset = cmeta.collider[c].offset;
cg.colliders[c].radius = cmeta.collider[c].radius;
}
TArray<VRMSpringCollider> colliders;
}
bInit = true;
}
void VRMSpringManager::update(const FAnimNode_VrmSpringBone* animNode, float DeltaTime, FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) {
for (int i = 0; i < spring.Num(); ++i) {
FTransform c;
//c = Output.AnimInstanceProxy->GetComponentTransform();
c = Output.AnimInstanceProxy->GetActorTransform();
spring[i].Update(animNode, DeltaTime, c, colliderGroup, Output);
}
}
void VRMSpringManager::applyToComponent(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) {
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
VRMSpringManager* SpringManager = this;
for (auto& springRoot : SpringManager->spring) {
for (auto& sChain : springRoot.SpringDataChain) {
int BoneChain = 0;
FTransform CurrentTransForm = FTransform::Identity;
for (auto& sData : sChain) {
//FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(sData.boneIndex);
FCompactPoseBoneIndex uu(sData.boneIndex);
if (Output.Pose.GetPose().IsValidIndex(uu) == false) {
continue;
}
FTransform NewBoneTM;
if (BoneChain == 0) {
NewBoneTM = Output.Pose.GetComponentSpaceTransform(uu);
NewBoneTM.SetRotation(sData.m_resultQuat);
CurrentTransForm = NewBoneTM;
}
else {
NewBoneTM = CurrentTransForm;
auto c = RefSkeletonTransform[sData.boneIndex];
NewBoneTM = c * NewBoneTM;
NewBoneTM.SetRotation(sData.m_resultQuat);
//const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
//NewBoneTM.SetLocation(ComponentTransform.TransformPosition(sData.m_currentTail));
CurrentTransForm = NewBoneTM;
}
FBoneTransform a(uu, NewBoneTM);
bool bFirst = true;
for (auto& t : OutBoneTransforms) {
if (t.BoneIndex == a.BoneIndex) {
bFirst = false;
break;
}
}
if (bFirst) {
OutBoneTransforms.Add(a);
}
BoneChain++;
}
}
}
OutBoneTransforms.Sort(FCompareBoneTransformIndex());
}
}
////////////////////////////
namespace VRM1Spring {
void VRM1SpringManager::reset() {
for (auto &j : JointStateMap) {
j.Value.currentTail = j.Value.prevTail = j.Value.initialTail;
}
}
void VRM1SpringManager::init(const UVrmMetaObject* meta, FComponentSpacePoseContext& Output) {
if (meta == nullptr) return;
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
FTransform ComponentToLocal = ComponentTransform.Inverse();
vrmMetaObject = meta;
skeletalMesh = VRMGetSkinnedAsset(Output.AnimInstanceProxy->GetSkelMeshComponent());
const FReferenceSkeleton& RefSkeleton = VRMGetRefSkeleton(skeletalMesh);
//const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
const auto& RefSkeletonTransform = RefSkeleton.GetRefBonePose();
for (auto& s : vrmMetaObject->VRM1SpringBoneMeta.Springs) {
for (int jointNo = 0; jointNo < s.joints.Num(); jointNo++) {
auto &j1 = s.joints[jointNo];
if (j1.boneNo == INDEX_NONE) {
continue;
}
int parentBoneIndex = RefSkeleton.GetParentIndex(j1.boneNo);
if (parentBoneIndex < 0) continue;
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(parentBoneIndex);
if (Output.Pose.GetPose().IsValidIndex(uu) == false) {
continue;
}
FTransform parentTransform = Output.Pose.GetComponentSpaceTransform(uu);
auto& state = JointStateMap.FindOrAdd(j1.boneNo);
if (RefSkeletonTransform.IsValidIndex(j1.boneNo) == false) {
continue;
}
state.initialLocalMatrix = RefSkeletonTransform[j1.boneNo];
state.initialLocalRotation = RefSkeletonTransform[j1.boneNo].GetRotation();
#if UE_VERSION_OLDER_THAN(5,0,0)
state.boneLength = RefSkeletonTransform[parentBoneIndex].GetLocation().Size();
#else
state.boneLength = RefSkeletonTransform[j1.boneNo].GetLocation().Length();
#endif
state.boneAxis = RefSkeletonTransform[j1.boneNo].TransformPosition(FVector::ZeroVector).GetSafeNormal();
{
FCompactPoseBoneIndex u = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(j1.boneNo);
auto t = Output.Pose.GetComponentSpaceTransform(u);
state.prevTail =
state.currentTail =
state.initialTail = ComponentToLocal.InverseTransformPosition(t.GetLocation());
state.resultQuat = t.GetRotation();
}
}
}
bInit = true;
}
void VRM1SpringManager::update(const FAnimNode_VrmSpringBone* animNode, float DeltaTime, FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) {
if (skeletalMesh == nullptr) {
return;
}
if (FMath::IsNearlyZero(DeltaTime)) {
return;
}
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
//const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
const auto& RefSkeletonTransform = RefSkeleton.GetRefBonePose();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
// モデルローカル座標
// FTransform c;
//c = Output.AnimInstanceProxy->GetComponentTransform();
//c = Output.AnimInstanceProxy->GetActorTransform();
const FTransform ComponentToLocal = ComponentTransform.Inverse();
// 計算した揺れ骨、または揺れ骨の親
TMap<int, FTransform> calcTransform;
// 揺れ骨一覧
TArray<int> springBoneNoList;
{
for (auto& s : vrmMetaObject->VRM1SpringBoneMeta.Springs) {
for (auto& j : s.joints) {
springBoneNoList.AddUnique(j.boneNo);
}
}
}
for (auto& s : vrmMetaObject->VRM1SpringBoneMeta.Springs) {
for (int jointNo = 0; jointNo < s.joints.Num(); ++jointNo) {
FTransform parentTransform = FTransform::Identity;
FTransform currentTransform = FTransform::Identity;
auto& j1 = s.joints[jointNo];
auto* state = JointStateMap.Find(j1.boneNo);
if (state == nullptr) {
init(vrmMetaObject, Output);
continue;
}
if (RefSkeletonTransform.IsValidIndex(j1.boneNo) == false) {
continue;
}
int parentBoneIndex = RefSkeleton.GetParentIndex(j1.boneNo);
if (parentBoneIndex < 0) {
continue;
}
if (springBoneNoList.Find(parentBoneIndex) < 0) {
// 親が揺れ骨ではない。通常骨から参照
// 親
{
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(parentBoneIndex);
if (Output.Pose.GetPose().IsValidIndex(uu) == false) {
continue;
}
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(uu);
parentTransform = NewBoneTM;
}
{
// 自分
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(j1.boneNo);
if (Output.Pose.GetPose().IsValidIndex(uu) == false) {
continue;
}
FTransform NewBoneTM = Output.Pose.GetComponentSpaceTransform(uu);
currentTransform = NewBoneTM;
}
} else {
// 親が揺れ骨。揺れ骨計算結果から参照
// 親
//parentTransform = currentTransform;
auto* p = calcTransform.Find(parentBoneIndex);
if (p) {
parentTransform = *p;
}
auto c = RefSkeletonTransform[j1.boneNo];
auto t = c * parentTransform;
// 自分
currentTransform = t;
}
FQuat m_localRotation = state->initialLocalMatrix.GetRotation();
const FVector currentTail = ComponentToLocal.TransformPosition(state->currentTail);
const FVector prevTail = ComponentToLocal.TransformPosition(state->prevTail);
const FVector inertia = (currentTail - prevTail) * (1.0f - j1.dragForce);
const FVector stiffness = currentTransform.GetRotation() * state->boneAxis * 1.f * DeltaTime
* 100.f * j1.stiffness * animNode->stiffnessScale + animNode->stiffnessAdd;
FVector ue4grav(-j1.gravityDir.X, j1.gravityDir.Z, j1.gravityDir.Y);
ue4grav = vrmMetaObject->VrmAssetListObject->model_root_transform.Inverse().TransformVector(ue4grav);
FVector external = ComponentToLocal.TransformVector(ue4grav) * (j1.gravityPower * DeltaTime) * animNode->gravityScale
+ ComponentToLocal.TransformVector(animNode->gravityAdd) * DeltaTime;
FVector nextTailTarget = currentTail + inertia + stiffness + external;
//FVector nextTailTarget = currentTail + stiffness * 10;
// 長さをboneLengthに強制
FVector nextTailDirection = (nextTailTarget - currentTransform.GetLocation()).GetSafeNormal();
FVector nextTailPosition = currentTransform.GetLocation() + nextTailDirection * state->boneLength;
// vrm <-> vrm collision
if (animNode->bIgnoreVRMCollision == false) {
// このSpringが参照するコライダのインデックス
TArray<int> checkcolliderIndexArray;
for (auto colg : s.colliderGroups) {
checkcolliderIndexArray.Append(vrmMetaObject->VRM1SpringBoneMeta.ColliderGroups[colg].colliders);
}
// 全てのコライダ
auto& AllColliderArray = vrmMetaObject->VRM1SpringBoneMeta.Colliders;
for (auto colNo : checkcolliderIndexArray){
if (colNo >= AllColliderArray.Num()) {
continue;
}
const auto& collider = AllColliderArray[colNo];
FTransform collisionBoneTrans;
{
int boneNo = RefSkeleton.FindBoneIndex(*collider.boneName);
if (boneNo < 0) {
continue;
}
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(boneNo);
//FCompactPoseBoneIndex uu(ii);
if (uu == INDEX_NONE) {
continue;
}
collisionBoneTrans = Output.Pose.GetComponentSpaceTransform(uu);
}
auto offs = collider.offset;
offs.Set(offs.X, -offs.Z, offs.Y);
offs *= 100;
//offs = collisionBoneTrans.TransformVector(offs);
auto tail = collider.tail;
tail.Set(tail.X, -tail.Z, tail.Y);
tail *= 100;
//tail = collisionBoneTrans.TransformVector(tail);
float r = (j1.hitRadius + collider.radius) * 100.f;
if (collider.shapeType == TEXT("sphere")) {
FVector v = collisionBoneTrans.TransformPosition(offs);
if ((v - nextTailPosition).SizeSquared() > r * r) {
continue;
}
// ヒット。Colliderの半径方向に押し出す
auto normal = (nextTailPosition - v).GetSafeNormal();
auto posFromCollider = v + normal * r;
// 長さをboneLengthに強制
nextTailPosition = currentTransform.GetLocation() + (posFromCollider - currentTransform.GetLocation()).GetSafeNormal() * state->boneLength;
nextTailDirection = (posFromCollider - currentTransform.GetLocation()).GetSafeNormal();
}
else {
FTransform t1 = collisionBoneTrans;
auto v1 = t1.TransformPosition(offs);
FTransform t2 = collisionBoneTrans;
auto v2 = t2.TransformPosition(tail);
FVector nearestPoint = FMath::ClosestPointOnSegment(nextTailPosition, v1, v2);
float dif = (nearestPoint - nextTailPosition).SizeSquared();
if (dif > r * r) {
continue;
}
auto normal = (nextTailPosition - nearestPoint).GetSafeNormal();
auto posFromCollider = nearestPoint + normal * r;
// 長さをboneLengthに強制
nextTailPosition = currentTransform.GetLocation() + (posFromCollider - currentTransform.GetLocation()).GetSafeNormal() * state->boneLength;
nextTailDirection = (posFromCollider - currentTransform.GetLocation()).GetSafeNormal();
}
}
}
state->prevTail = ComponentToLocal.InverseTransformPosition(currentTail);
state->currentTail = ComponentToLocal.InverseTransformPosition(nextTailPosition);
{
FVector from = currentTransform.TransformVector(state->boneAxis).GetSafeNormal();
FVector to = nextTailDirection;
state->resultQuat = FQuat::FindBetween(from, to) * parentTransform.GetRotation() * state->initialLocalMatrix.GetRotation();
}
// initial rot
{
//state->resultQuat = currentTransform.GetRotation();
}
{
//state->resultQuat = (state->initialLocalMatrix * parentTransform).GetRotation();
}
{
//state->resultQuat = parentTransform.GetRotation() * state->initialLocalRotation;
}
currentTransform.SetRotation(state->resultQuat);
// 揺れ骨計算結果を保持。これの子の揺れ骨のため。
calcTransform.Add(j1.boneNo, currentTransform);
}
}
}
void VRM1SpringManager::applyToComponent(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) {
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const auto& RefSkeletonTransform = Output.Pose.GetPose().GetBoneContainer().GetRefPoseArray();
// 計算した揺れ骨、または揺れ骨の親
TMap<int, FTransform> calcTransform;
// 揺れ骨一覧
TArray<int> springBoneNoList;
{
for (auto& s : vrmMetaObject->VRM1SpringBoneMeta.Springs) {
for (auto& j : s.joints) {
springBoneNoList.AddUnique(j.boneNo);
}
}
}
for (auto& s : vrmMetaObject->VRM1SpringBoneMeta.Springs) {
FTransform CurrentTransForm;
for (int jointNo = 0; jointNo < s.joints.Num(); ++jointNo) {
auto& j = s.joints[jointNo];
auto* state = JointStateMap.Find(j.boneNo);
if (state == nullptr) continue;
FCompactPoseBoneIndex uu = Output.Pose.GetPose().GetBoneContainer().GetCompactPoseIndexFromSkeletonIndex(j.boneNo);
//FCompactPoseBoneIndex uu(j.boneNo);
if (Output.Pose.GetPose().IsValidIndex(uu) == false) {
continue;
}
FTransform NewBoneTM;
int parentBoneIndex = RefSkeleton.GetParentIndex(j.boneNo);
if (springBoneNoList.Find(parentBoneIndex) < 0) {
// 親は揺れ骨でない。
// 現在値
NewBoneTM = Output.Pose.GetComponentSpaceTransform(uu);
// 差分
NewBoneTM.SetRotation(state->resultQuat);
CurrentTransForm = NewBoneTM;
}
else {
// 親は揺れ骨。計算結果から参照する
auto* p = calcTransform.Find(parentBoneIndex);
if (p) {
NewBoneTM = *p;
}
auto c = RefSkeletonTransform[j.boneNo];
NewBoneTM = c * NewBoneTM;
NewBoneTM.SetRotation(state->resultQuat);
CurrentTransForm = NewBoneTM;
}
FBoneTransform a(uu, NewBoneTM);
bool bFirst = true;
for (auto& t : OutBoneTransforms) {
if (t.BoneIndex == a.BoneIndex) {
bFirst = false;
break;
}
}
if (bFirst) {
OutBoneTransforms.Add(a);
}
calcTransform.Add(j.boneNo, CurrentTransForm);
// update rotation
//FVector to = (state->currentTail * (node.parent.worldMatrix * state->initialLocalMatrix).inverse).normalized;
//node.rotation = initialLocalRotation * Quaternion.fromToQuaternion(boneAxis, to);
}
}
OutBoneTransforms.Sort(FCompareBoneTransformIndex());
}
} //spring1
@@ -0,0 +1,173 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
/*
// VRMSpringBone.cs
MIT License
Copyright (c) 2018 DWANGO Co., Ltd. for UniVRM
Copyright (c) 2018 ousttrue for UniGLTF, UniHumanoid
Copyright (c) 2018 Masataka SUMI for MToon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "AnimNode_VrmSpringBone.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "SceneInterface.h"
#include "DrawDebugHelpers.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
class VRM4U_API VrmSpringBone{
public:
VrmSpringBone();
~VrmSpringBone();
};
namespace VRMSpringBone {
class VRMSpringManagerBase {
public:
VRMSpringManagerBase() {}
virtual ~VRMSpringManagerBase() {}
bool bInit = false;
USkeletalMesh* skeletalMesh = nullptr;
const UVrmMetaObject* vrmMetaObject = nullptr;
virtual void init(const UVrmMetaObject* meta, FComponentSpacePoseContext& Output) {}
virtual void update(const FAnimNode_VrmSpringBone* animNode, float DeltaTime, FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) {}
virtual void reset() {}
virtual void applyToComponent(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) {}
};
}
namespace VRMSpringBone {
class VRMSpringCollider {
public:
FVector offset = FVector::ZeroVector;
float radius = 0.f;
};
class VRMSpringColliderGroup {
public:
int node = 0;
FName node_name;
TArray<VRMSpringCollider> colliders;
};
class VRMSpringData {
public:
int boneIndex = -1;
FName boneName;
FVector m_currentTail = FVector::ZeroVector;
FVector m_prevTail = FVector::ZeroVector;
//FTransform m_transform = FTransform::Identity;
FVector m_boneAxis = FVector::ForwardVector;
float m_length = 1.f;
FQuat m_resultQuat = FQuat::Identity;
};
class VRMSpring {
public:
float stiffness = 0.f;
float gravityPower = 0.f;
FVector gravityDir = { 0,0,0 };
float dragForce = 0.f;
float hitRadius = 0.f;
//int boneNum = 0;
//int *bones;
//FString bones_name;
//int colliderGourpNum = 0;
//int* colliderGroups = nullptr;
TArray<int> ColliderGroupIndexArray;
TArray< TArray<VRMSpringData> > SpringDataChain;
TArray<VRMSpringData> RootSpringData;
USkeletalMesh* skeletalMesh = nullptr;
~VRMSpring() {
skeletalMesh = nullptr;
}
void Update(const FAnimNode_VrmSpringBone* animNode, float DeltaTime, FTransform center,
const TArray<VRMSpringColliderGroup>& colliderGroup,
FComponentSpacePoseContext& Output);
};
class VRMSpringManager : public VRMSpringManagerBase {
public:
virtual void init(const UVrmMetaObject* meta, FComponentSpacePoseContext& Output) override;
virtual void update(const FAnimNode_VrmSpringBone* animNode, float DeltaTime, FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void reset() override;
virtual void applyToComponent(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
TArray<VRMSpring> spring;
TArray<VRMSpringColliderGroup> colliderGroup;
};
}
namespace VRM1Spring {
class SpringBoneJointState {
public:
FVector prevTail;
FVector currentTail;
FVector initialTail;
FVector boneAxis;
float boneLength = 0.f;
FTransform initialLocalMatrix;
FQuat initialLocalRotation;
FQuat resultQuat;
};
class VRM1SpringManager : public VRMSpringBone::VRMSpringManagerBase {
public:
TMap< int, SpringBoneJointState > JointStateMap;
virtual void init(const UVrmMetaObject* meta, FComponentSpacePoseContext& Output) override;
virtual void update(const FAnimNode_VrmSpringBone* animNode, float DeltaTime, FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void reset() override;
virtual void applyToComponent(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
};
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,145 @@
// VRM4U Copyright (c) 2021-2022 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmUtil.h"
#include "VRM4U.h"
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/UObjectHash.h"
#include "UObject/UObjectIterator.h"
#include "Misc/EngineVersionComparison.h"
#if UE_VERSION_OLDER_THAN(5,3,0)
#else
#include "InterchangeHelper.h"
#endif
#include "Modules/ModuleManager.h"
namespace {
//same as URigHierarchy
void LocalSanitizeName(FString& InOutName)
{
// Sanitize the name
for (int32 i = 0; i < InOutName.Len(); ++i)
{
TCHAR& C = InOutName[i];
const bool bGoodChar = FChar::IsAlpha(C) || // Any letter
//(C == '_') || (C == '-') || (C == '.') || // _ - . anytime
(FChar::IsDigit(C));// || // 0-9 anytime
//((i > 0) && (C == ' ')); // Space after the first character to support virtual bones
/*
const bool bGoodChar =
((C >= 'A') && (C <= 'Z')) || ((C >= 'a') && (C <= 'z')) || // A-Z (upper and lowercase) anytime
(C == '_') || // _ anytime
((i > 0) && (C >= '0') && (C <= '9')); // 0-9 after the first character
*/
if (!bGoodChar)
{
C = '_';
}
}
//if (InOutName.Len() > GetMaxNameLength())
//{
// InOutName.LeftChopInline(InOutName.Len() - GetMaxNameLength());
//}
}
FString LocalGetSanitizedName(const FString& InName)
{
FString Name = InName;
LocalSanitizeName(Name);
return Name;
}
FString LocalGetSafeNewName(const FString& InName, TFunction<bool(const FString&)> IsNameAvailableFunction)
{
check(IsNameAvailableFunction);
FString SanitizedName = InName;
LocalSanitizeName(SanitizedName);
FString Name = SanitizedName;
int32 Suffix = 1;
while (!IsNameAvailableFunction(Name))
{
FString BaseString = SanitizedName;
//if (BaseString.Len() > GetMaxNameLength() - 4)
//{
// BaseString.LeftChopInline(BaseString.Len() - (GetMaxNameLength() - 4));
//}
Name = *FString::Printf(TEXT("%s_%d"), *BaseString, ++Suffix);
}
return Name;
}
bool LocalIsNameAvailable(const FString& InName)// , ERigElementType InElementType, FString* OutErrorMessage)
{
FString UnsanitizedName = InName;
FString SanitizedName = UnsanitizedName;
LocalSanitizeName(SanitizedName);
if (SanitizedName != UnsanitizedName)
{
return false;
}
return true;
}
FString LocalGetSafeNewName(const FString& InPotentialNewName)
{
return LocalGetSafeNewName(InPotentialNewName, [](const FString& InName) -> bool {
return LocalIsNameAvailable(InName);
});
}
}
bool VRMUtil::IsNoSafeName(const FString& str) {
for (int i = 0; i < str.Len(); ++i) {
if ((str[i] != '_') && (FString::Chr(str[i]).IsNumeric()==false)) {
return false;
}
}
return true;
}
FString VRMUtil::GetSafeNewName(const FString& str) {
return LocalGetSafeNewName(str);
}
FString VRMUtil::MakeName(const FString& str, bool IsJoint) {
#if UE_VERSION_OLDER_THAN(4,22,0)
return GetSafeNewName(str);
#elif UE_VERSION_OLDER_THAN(5,3,0)
const TCHAR* InvalidChar = IsJoint ? INVALID_OBJECTNAME_CHARACTERS TEXT("+ ") : INVALID_OBJECTNAME_CHARACTERS;
FString TmpName = str;
while (*InvalidChar)
{
TmpName.ReplaceCharInline(*InvalidChar, TCHAR('_'), ESearchCase::CaseSensitive);
++InvalidChar;
}
return TmpName;
#elif UE_VERSION_OLDER_THAN(5,7,0)
return UE::Interchange::MakeName(str, IsJoint);
#else
return UE::Interchange::MakeSanitizedName(str, IsJoint);
#endif
}
FName VRMUtil::GetSanitizedName(const FString& str) {
return *LocalGetSanitizedName(str);
}
@@ -0,0 +1,69 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "Misc/EngineVersionComparison.h"
#include "AnimNode_VrmConstraint.generated.h"
class UVrmMetaObject;
class UVrmAssetListObject;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmConstraint : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool EnableAutoSearchMetaData = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
const UVrmMetaObject *VrmMetaObject = nullptr;
#if UE_VERSION_OLDER_THAN(5,0,0)
TAssetPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TAssetPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
#else
TSoftObjectPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TSoftObjectPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
#endif
bool bCallInitialized = false;
bool bCallByAnimInstance = false;
FAnimNode_VrmConstraint();
void UpdateCache(FComponentSpacePoseContext& Output);
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
// virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
virtual void UpdateInternal(const FAnimationUpdateContext& Context)override;
// End of FAnimNode_SkeletalControlBase interface
virtual void ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground = false) const;
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,49 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "AnimNode_VrmCopyHandBone.generated.h"
class USkeletalMeshComponent;
class UVrmMetaObject;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmCopyHandBone : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Skeleton, meta=(PinShownByDefault))
USkeletalMeshComponent *SkeletalMeshComponentLeft = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Skeleton, meta=(PinShownByDefault))
USkeletalMeshComponent *SkeletalMeshComponentRight = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinShownByDefault))
UVrmMetaObject *VrmMetaObject = nullptr;
FAnimNode_VrmCopyHandBone();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,81 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "AnimNode_VrmModifyBoneDynamic.generated.h"
class USkeletalMeshComponent;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmModifyBoneDynamic : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
/** Name of bone to control. This is the main bone chain to modify from. **/
//UPROPERTY(EditAnywhere, Category=SkeletalControl)
//FBoneReference BoneToModify;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SkeletalControl, meta=(PinShownByDefault))
FName BoneNameToModify;
/** New translation of bone to apply. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Translation, meta=(PinShownByDefault))
FVector Translation;
/** New rotation of bone to apply. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Rotation, meta=(PinShownByDefault))
FRotator Rotation;
/** New Scale of bone to apply. This is only worldspace. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Scale, meta=(PinShownByDefault))
FVector Scale;
/** Whether and how to modify the translation of this bone. */
UPROPERTY(EditAnywhere, Category=Translation)
TEnumAsByte<EBoneModificationMode> TranslationMode;
/** Whether and how to modify the translation of this bone. */
UPROPERTY(EditAnywhere, Category=Rotation)
TEnumAsByte<EBoneModificationMode> RotationMode;
/** Whether and how to modify the translation of this bone. */
UPROPERTY(EditAnywhere, Category=Scale)
TEnumAsByte<EBoneModificationMode> ScaleMode;
/** Reference frame to apply Translation in. */
UPROPERTY(EditAnywhere, Category=Translation)
TEnumAsByte<enum EBoneControlSpace> TranslationSpace;
/** Reference frame to apply Rotation in. */
UPROPERTY(EditAnywhere, Category=Rotation)
TEnumAsByte<enum EBoneControlSpace> RotationSpace;
/** Reference frame to apply Scale in. */
UPROPERTY(EditAnywhere, Category=Scale)
TEnumAsByte<enum EBoneControlSpace> ScaleSpace;
FAnimNode_VrmModifyBoneDynamic();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,54 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "Misc/EngineVersionComparison.h"
#include "AnimNode_VrmModifyBoneList.generated.h"
class USkeletalMeshComponent;
class UVrmMetaObject;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmModifyBoneList : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
TMap<FString, FTransform> BoneTrans;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
TArray<FString> UseInputTransBoneList;
FAnimNode_VrmModifyBoneList();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
// virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
virtual void UpdateInternal(const FAnimationUpdateContext& Context)override;
// End of FAnimNode_SkeletalControlBase interface
virtual void ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground = false) const;
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,60 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "Misc/EngineVersionComparison.h"
#include "AnimNode_VrmModifyBoneListRetarget.generated.h"
class USkeletalMeshComponent;
class UVrmMetaObject;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmModifyBoneListRetarget : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
const UVrmMetaObject *VrmMetaObject = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
TMap<FString, FTransform> BoneTrans;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
bool bUseRemoteCenterPos = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
float ModelRelativeScale = 1.f;
FAnimNode_VrmModifyBoneListRetarget();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
// virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
virtual void UpdateInternal(const FAnimationUpdateContext& Context)override;
// End of FAnimNode_SkeletalControlBase interface
virtual void ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground = false) const;
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,88 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "AnimNode_VrmModifyHumanoidBone.generated.h"
class UVrmAssetListObject;
class USkeletalMeshComponent;
USTRUCT(BlueprintType)
struct FVRMBoneTransform
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TArray<FTransform> Transform;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TArray<bool> bEnableRotation;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TArray<bool> bEnableTranslation;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TArray<FName> VRMHumanoidBoneName;
};
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmModifyHumanoidBone : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
/** Name of bone to control. This is the main bone chain to modify from. **/
//UPROPERTY(EditAnywhere, Category=SkeletalControl)
//FBoneReference BoneToModify;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmAssetListObject *VrmAssetList = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalControl, meta = (PinShownByDefault))
FVRMBoneTransform HumanoidBoneTransform;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalControl, meta = (PinShownByDefault))
FVRMBoneTransform ExtBoneTransform;
/** Whether and how to modify the translation of this bone. */
//UPROPERTY(EditAnywhere, Category=Translation)
//TEnumAsByte<EBoneModificationMode> TranslationMode;
/** Whether and how to modify the translation of this bone. */
//UPROPERTY(EditAnywhere, Category=Rotation)
//TEnumAsByte<EBoneModificationMode> RotationMode;
/** Reference frame to apply Translation in. */
//UPROPERTY(EditAnywhere, Category=Translation)
//TEnumAsByte<enum EBoneControlSpace> TranslationSpace;
/** Reference frame to apply Rotation in. */
//UPROPERTY(EditAnywhere, Category=Rotation)
TEnumAsByte<enum EBoneControlSpace> RotationSpace;
FAnimNode_VrmModifyHumanoidBone();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,61 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "AnimNodes/AnimNode_PoseBlendNode.h"
#include "Misc/EngineVersionComparison.h"
#include "AnimNode_VrmPoseBlendNode.generated.h"
class UVrmMetaObject;
class UVrmAssetListObject;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmPoseBlendNode : public FAnimNode_PoseBlendNode
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool EnableAutoSearchMetaData = true;
//UPROPERTY(EditAnywhere, EditFixedSize, BlueprintReadWrite, Category = Links)
//FPoseLink SourcePose;
//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
//const UVrmMetaObject *VrmMetaObject = nullptr;
#if UE_VERSION_OLDER_THAN(5,0,0)
TAssetPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TAssetPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
//TAssetPtr<FPoseLink> SourcePose_Internal = nullptr;
#else
TSoftObjectPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TSoftObjectPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
//TSoftObjectPtr<FPoseLink> SourcePose_Internal = nullptr;
#endif
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool bRemovePoseCurve = false;
bool bCallInitialized = false;
bool bCallByAnimInstance = false;
FAnimNode_VrmPoseBlendNode();
// FAnimNode_SkeletalControlBase interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void Evaluate_AnyThread(FPoseContext& Output) override;
private:
};
@@ -0,0 +1,66 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "AnimNode_VrmQuestHandBone.generated.h"
class USkeletalMeshComponent;
class UVrmMetaObject;
USTRUCT(BlueprintType)
struct FVRMQuestHandBone
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TArray<FTransform> HandLeft;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TArray<FTransform> HandRight;
};
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmQuestHandBone : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
UVrmMetaObject* VrmMetaObject = nullptr;
//UPROPERTY(EditAnywhere, Category = Rotation, meta = (PinHiddenByDefault))
//TEnumAsByte<enum EBoneControlSpace> TransformSpace;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
FVRMQuestHandBone HandTransform;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
FVRMQuestHandBone HandReferenceTransform;
FAnimNode_VrmQuestHandBone();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,89 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "Misc/EngineVersionComparison.h"
#include "AnimNode_VrmRetargetFromMannequin.generated.h"
class USkeletalMeshComponent;
class UVrmMetaObject;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmRetargetFromMannequin : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
/* If SourceMeshComponent is not valid, and if this is true, it will look for attached parent as a source */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category= Skeleton, meta = (NeverAsPin))
bool bUseAttachedParent = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
TWeakObjectPtr<USkeletalMeshComponent> srcMannequinMesh= nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
UVrmMetaObject *VrmMetaObject = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool bIgnoreCenterLocation = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
FVector CenterLocationScaleByHeightScale = { 1.0f, 1.0f, 1.0f }; // FVector(1.0f, 1.0f, 1.0f);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
FVector CenterLocationOffset = { 0.0f, 0.0f, 0.0f }; // FVector(1.0f, 1.0f, 1.0f);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
UVrmMetaObject *MannequinVrmMetaObject = nullptr;
FAnimNode_VrmRetargetFromMannequin();
UPROPERTY()
USkeletalMesh *srcSkeletalMesh = nullptr;
UPROPERTY()
USkeletalMesh *dstSkeletalMesh = nullptr;
TArray<FTransform> srcRefSkeletonCompTransform;
TArray<FTransform> dstRefSkeletonCompTransform;
TArray<FTransform> dstCurrentSkeletonCompTransform;
void UpdateCache(FComponentSpacePoseContext& Output);
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
// virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
virtual bool NeedsDynamicReset() const override { return true; }
#if UE_VERSION_OLDER_THAN(4,20,0)
#else
virtual void ResetDynamics(ETeleportType InTeleportType) override;
#endif
virtual bool HasPreUpdate() const override { return true; }
virtual void PreUpdate(const UAnimInstance* InAnimInstance) override;
virtual void UpdateInternal(const FAnimationUpdateContext& Context)override;
// End of FAnimNode_SkeletalControlBase interface
virtual void ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground = false) const;
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,123 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "Misc/EngineVersionComparison.h"
#include "AnimNode_VrmSpringBone.generated.h"
class USkeletalMeshComponent;
class UVrmMetaObject;
class UVrmAssetListObject;
namespace VRMSpringBone {
class VRMSpringManagerBase;
}
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4U_API FAnimNode_VrmSpringBone : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool EnableAutoSearchMetaData = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
const UVrmMetaObject *VrmMetaObject = nullptr;
#if UE_VERSION_OLDER_THAN(5,0,0)
TAssetPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TAssetPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
#else
TSoftObjectPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TSoftObjectPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
#endif
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
float gravityScale = 1.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
FVector gravityAdd = FVector::ZeroVector;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
float stiffnessScale = 1.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
float stiffnessAdd = 0.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
float randomWindRange = 0.2f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
float windScale = 1.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
int loopc = 1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
int collisionCheckLoopCount = 2;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool bIgnorePhysicsResetOnTeleport = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
bool bIgnorePhysicsCollision = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
bool bIgnoreVRMCollision = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool bIgnoreWindDirectionalSource = false;
//
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
TArray<FName> NoWindBoneNameList;
TSharedPtr<VRMSpringBone::VRMSpringManagerBase> SpringManager;
float CurrentDeltaTime = 0.f;
bool bCallByAnimInstance = false;
TArray<FBoneTransform> BoneTransformsSpring;
bool IsSpringInit() const;
FAnimNode_VrmSpringBone();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void Initialize_AnyThread_local(const FAnimationInitializeContext& Context);
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
// virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
virtual bool NeedsDynamicReset() const override { return true; }
#if UE_VERSION_OLDER_THAN(4,20,0)
#else
virtual void ResetDynamics(ETeleportType InTeleportType) override;
#endif
virtual void UpdateInternal(const FAnimationUpdateContext& Context)override;
// End of FAnimNode_SkeletalControlBase interface
virtual void ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground = false) const;
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,108 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Units/RigUnit.h"
#include "ControlRigDefines.h"
#include "RigUnit_VrmDynamicHierarchy.generated.h"
/**
* get curve list
*/
USTRUCT(meta = (DisplayName = "VRM4U GetCurveNameFromMesh", Keywords = "VRM4U", Varying))
struct FRigUnit_VRMGetCurveNameFromMesh : public FRigUnitMutable
{
GENERATED_BODY()
FRigUnit_VRMGetCurveNameFromMesh()
{
}
RIGVM_METHOD()
virtual void Execute() override;
UPROPERTY(meta = (Output))
TArray<FName> Items_Morph;
UPROPERTY(meta = (Output))
TArray<FName> Items_Curve;
};
/**
* add morph and curve
*/
USTRUCT(meta=(DisplayName="VRM4U AddCurveFromMesh", Keywords="AddCurve,Spawn", Varying))
struct FRigUnit_VRMAddCurveFromMesh : public FRigUnitMutable
{
GENERATED_BODY()
FRigUnit_VRMAddCurveFromMesh()
{
}
RIGVM_METHOD()
virtual void Execute() override;
UPROPERTY(meta = (Input))
FString Prefix = TEXT("");
UPROPERTY(meta = (Input))
FString Suffix = TEXT("_c");
UPROPERTY(meta = (Input))
bool bIncludeMorphs = true;
UPROPERTY(meta = (Input))
bool bIncludeCurves = true;
UPROPERTY(meta = (Output))
TArray<FRigElementKey> Items_Morph;
UPROPERTY(meta = (Output))
TArray<FRigElementKey> Items_Curve;
};
/**
* generate contorl to bone table
*/
USTRUCT(meta = (DisplayName = "VRM4U GenerateTable", Keywords = "Table", Varying))
struct FRigUnit_VRMGenerateBoneToControlTable: public FRigUnitMutable
{
GENERATED_BODY()
FRigUnit_VRMGenerateBoneToControlTable()
{
}
RIGVM_METHOD()
virtual void Execute() override;
UPROPERTY(meta = (Output))
TArray<FName> Items_MannequinBone;
UPROPERTY(meta = (Output))
TArray<FName> Items_VRMBone;
};
/**
* init controller transform
*/
USTRUCT(meta = (DisplayName = "VRM4U InitController Transform", Keywords = "Table", Varying))
struct FRigUnit_VRMInitControllerTransform: public FRigUnitMutable
{
GENERATED_BODY()
FRigUnit_VRMInitControllerTransform()
{
}
RIGVM_METHOD()
virtual void Execute() override;
};
+24
View File
@@ -0,0 +1,24 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
//#include "Engine.h"
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
DECLARE_LOG_CATEGORY_EXTERN(LogVRM4U, Verbose, All);
#define SPRITER_IMPORT_ERROR(FormatString, ...) \
if (!bSilent) { UE_LOG(LogVRM4U, Warning, FormatString, __VA_ARGS__); }
#define SPRITER_IMPORT_WARNING(FormatString, ...) \
if (!bSilent) { UE_LOG(LogVRM4U, Warning, FormatString, __VA_ARGS__); }
class FVRM4UModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
@@ -0,0 +1,70 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/EngineSubsystem.h"
#include "Misc/EngineVersionComparison.h"
#include "VRM4U_AnimSubsystem.generated.h"
#if UE_VERSION_OLDER_THAN(4,22,0)
//Couldn't find parent type for 'VRM4U_AnimSubsystem' named 'UEngineSubsystem'
#error "please remove VRM4U_AnimSubsystem.h/cpp for <=UE4.21"
#endif
USTRUCT()
struct FVrmTransformData {
GENERATED_USTRUCT_BODY()
public:
int port = 0;
// UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = VRM4U)
UPROPERTY()
TMap<FString, FTransform> BoneTransform;
// UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = VRM4U)
UPROPERTY()
TMap<FString, FTransform> RawData;
};
UCLASS()
class VRM4U_API UVRM4U_AnimSubsystem : public UEngineSubsystem
{
GENERATED_BODY()
FCriticalSection cs;
public:
// TMap<FString, FTransform>;
TArray<FVrmTransformData> baseData;
UFUNCTION(BlueprintCallable, Category = VRM4U)
void Clear();
UFUNCTION(BlueprintCallable, Category = VRM4U)
void GetBoneByIndex(int index, TMap<FString, FTransform>&trans);
UFUNCTION(BlueprintCallable, Category = VRM4U)
void GetBoneByPort(int port, TMap<FString, FTransform>& trans);
UFUNCTION(BlueprintCallable, Category = VRM4U)
void GetRawdataByIndex(int index, TMap<FString, FTransform>& trans);
UFUNCTION(BlueprintCallable, Category = VRM4U)
void GetRawdataByPort(int port, TMap<FString, FTransform>& trans);
UFUNCTION(BlueprintCallable, Category = VRM4U)
void SetBoneTransform(int port, const TMap<FString, FTransform>& trans);
UFUNCTION(BlueprintCallable, Category = VRM4U)
void SetRawData(int port, const TMap<FString, FTransform>& trans);
};
@@ -0,0 +1,74 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
//#if WITH_EDITOR
//#include "UnrealEd.h"
//#include "AssetTypeActions_Base.h"
//#endif
#include "Vrm1LicenseObject.generated.h"
class UTexture2D;
/**
*
*/
USTRUCT(BlueprintType, meta = (AutoExpandCategories = "License"))
struct FLicenseStringDataPair {
GENERATED_USTRUCT_BODY()
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
FString key;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
FString value;
};
USTRUCT(BlueprintType, meta = (AutoExpandCategories = "License"))
struct FLicenseStringDataArray {
GENERATED_USTRUCT_BODY()
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
FString key;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
TArray<FString> value;
};
USTRUCT(BlueprintType, meta = (AutoExpandCategories = "License"))
struct FLicenseBoolDataPair {
GENERATED_USTRUCT_BODY()
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
FString key;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
bool value = false;
};
UCLASS(Blueprintable, BlueprintType, meta = (AutoExpandCategories = "License"))
class VRM4U_API UVrm1LicenseObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Information)
UTexture2D* thumbnail = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
TArray<FLicenseStringDataPair> LicenseString;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
TArray<FLicenseStringDataArray> LicenseStringArray;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License")
TArray<FLicenseBoolDataPair> LicenseBool;
};
@@ -0,0 +1,125 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "Animation/AnimInstanceProxy.h"
#include "Misc/EngineVersionComparison.h"
#include "VrmAnimInstance.generated.h"
class UVrmMetaObject;
class USkeleton;
UENUM(BlueprintType)
enum class EVRMBlendShapeGroup : uint8
{
BSG_Neutoral UMETA(DisplayName="00_Neutoral"),
BSG_A UMETA(DisplayName="01_A"),
BSG_I UMETA(DisplayName="02_I"),
BSG_U UMETA(DisplayName="03_U"),
BSG_E UMETA(DisplayName="04_E"),
BSG_O UMETA(DisplayName="05_O"),
BSG_Blink UMETA(DisplayName="06_Blink"),
BSG_Joy UMETA(DisplayName="07_Joy"),
BSG_Angry UMETA(DisplayName="08_Angry"),
BSG_Sorrow UMETA(DisplayName="09_Sorrow"),
BSG_Fun UMETA(DisplayName="10_Fun"),
BSG_LookUp UMETA(DisplayName="11_LookUp"),
BSG_LookDown UMETA(DisplayName="12_LookDown"),
BSG_LookLeft UMETA(DisplayName="13_LookLeft"),
BSG_LookRight UMETA(DisplayName="14_LookRight"),
BSG_Blink_L UMETA(DisplayName="15_Blink_L"),
BSG_Blink_R UMETA(DisplayName="16_Blink_R"),
Num UMETA(Hidden)
};
USTRUCT()
struct VRM4U_API FVrmAnimInstanceProxy : public FAnimInstanceProxy {
public:
GENERATED_BODY()
FVrmAnimInstanceProxy()
{
}
FVrmAnimInstanceProxy(UAnimInstance* InAnimInstance)
: FAnimInstanceProxy(InAnimInstance)
{
}
virtual void Initialize(UAnimInstance* InAnimInstance) override;
virtual bool Evaluate(FPoseContext& Output) override;
#if UE_VERSION_OLDER_THAN(4,24,0)
virtual void UpdateAnimationNode(float DeltaSeconds) override;
#else
virtual void UpdateAnimationNode(const FAnimationUpdateContext& InContext);
#endif
};
/**
*
*/
UCLASS(Blueprintable, BlueprintType)
class VRM4U_API UVrmAnimInstance : public UAnimInstance
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmMetaObject *MetaObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
USkeleton *BaseSkeleton;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
USkeletalMeshComponent *BaseSkeletalMeshComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
FTransform TransHandLeft;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
FTransform TransHandRight;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
FTransform TransHead;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
USceneComponent *ComponentHandLeft;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
USceneComponent *ComponentHandRight;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
USceneComponent *ComponentHead;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
USceneComponent *ComponentHandJointTargetLeft;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Tracking)
USceneComponent *ComponentHandJointTargetRight;
protected:
virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override;
public:
virtual void NativeInitializeAnimation()override;
// Native update override point. It is usually a good idea to simply gather data in this step and
// for the bulk of the work to be done in NativeUpdateAnimation.
virtual void NativeUpdateAnimation(float DeltaSeconds)override;
// Native Post Evaluate override point
virtual void NativePostEvaluateAnimation()override;
// Native Uninitialize override point
virtual void NativeUninitializeAnimation()override;
// Executed when begin play is called on the owning component
virtual void NativeBeginPlay()override;
//virtual USkeleton* GetTargetSkeleton() const override;
UFUNCTION(BlueprintCallable, Category="Animation")
void SetMorphTargetVRM(EVRMBlendShapeGroup type, float Value);
UFUNCTION(BlueprintCallable, Category = "Animation")
void SetVrmData(USkeletalMeshComponent *baseSkeletalMesh, UVrmMetaObject *meta);
};
@@ -0,0 +1,142 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "Animation/AnimInstanceProxy.h"
#include "Animation/AnimNodeBase.h"
#include "Misc/EngineVersionComparison.h"
#include "VrmAnimInstanceCopy.generated.h"
class UVrmAssetListObject;
struct FAnimNode_VrmSpringBone;
struct FAnimNode_VrmConstraint;
USTRUCT()
struct VRM4U_API FVrmAnimInstanceCopyProxy : public FAnimInstanceProxy {
public:
GENERATED_BODY()
float CurrentDeltaTime = 0.f;
bool bIgnoreVRMSwingBone = false;
bool bIgnoreVRMConstraint = false;
bool bIgnoreWindDirectionalSource = false;
int CalcCount = 0;
TSharedPtr<FAnimNode_VrmSpringBone> Node_SpringBone;
TSharedPtr<FAnimNode_VrmConstraint> Node_Constraint;
bool bUseAnimStop = false;
bool bAnimStop = false;
bool bIgnoreCenterLocation = false;
FVector CenterLocationScaleByHeightScale = { 1.f, 1.f, 1.f };
FVector CenterLocationOffset = {0.f, 0.f, 0.f};
bool bCopyStop = false;
FCompactHeapPose CachedPose;
FVrmAnimInstanceCopyProxy();
FVrmAnimInstanceCopyProxy(UAnimInstance* InAnimInstance);
virtual void Initialize(UAnimInstance* InAnimInstance) override;
virtual bool Evaluate(FPoseContext& Output) override;
#if UE_VERSION_OLDER_THAN(4,24,0)
virtual void UpdateAnimationNode(float DeltaSeconds) override;
#else
virtual void UpdateAnimationNode(const FAnimationUpdateContext& InContext);
#endif
};
/**
*
*/
UCLASS(Blueprintable, BlueprintType)
class VRM4U_API UVrmAnimInstanceCopy : public UAnimInstance
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category= Rendering, meta = (NeverAsPin))
bool bUseAttachedParent = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
USkeletalMeshComponent *SrcSkeletalMeshComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
USkinnedMeshComponent* SrcAsSkinnedMeshComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmAssetListObject *SrcVrmAssetList;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmMetaObject* SrcVrmMetaOverride;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmAssetListObject *DstVrmAssetList;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmMetaObject *DstVrmMetaForCustomSpring;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FName> InitialMorphName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<float> InitialMorphValue;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bUseAnimStop = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bAnimStop = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bCopyStop = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bIgnoreCenterLocation = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector CenterLocationScaleByHeightScale = {1.f, 1.f, 1.f};
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector CenterLocationOffset = { 0.f, 0.f, 0.f };
protected:
virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override;
FVrmAnimInstanceCopyProxy *myProxy = nullptr;
bool bIgnoreVRMSwingBone = false;
bool bIgnoreWindDirectionalSource = false;
public:
virtual void NativeInitializeAnimation()override;
// Native update override point. It is usually a good idea to simply gather data in this step and
// for the bulk of the work to be done in NativeUpdateAnimation.
virtual void NativeUpdateAnimation(float DeltaSeconds)override;
// Native Post Evaluate override point
virtual void NativePostEvaluateAnimation()override;
// Native Uninitialize override point
virtual void NativeUninitializeAnimation()override;
// Executed when begin play is called on the owning component
virtual void NativeBeginPlay()override;
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetSkeletalMeshCopyData(UVrmAssetListObject *dstAssetList, USkeletalMeshComponent *srcSkeletalMesh, USkinnedMeshComponent* srcSkinnedMesh, UVrmAssetListObject *srcAssetList, UVrmMetaObject* srcVrmMetaOption);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetSkeletalMeshCopyDataForCustomSpring(UVrmMetaObject *dstMetaForCustomSpring);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetVrmSpringBoneParam(float gravityScale = 1.f, FVector gravityAdd = FVector::ZeroVector, float stiffnessScale = 1.f, float stiffnessAdd = 0.f, float randomWindRange = 0.2f);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetVrmSpringBoneBool(bool bIgnoreVrmSpringBone = false, bool bIgnorePhysicsCollision = false, bool bIgnoreVRMCollision = false, bool bIgnoreWind = false);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetVrmSpringBoneIgnoreWingBone(const TArray<FName> &boneNameList);
FVrmAnimInstanceCopyProxy *GetProxy() { return myProxy; }
};
@@ -0,0 +1,151 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "Animation/AnimInstanceProxy.h"
#include "Animation/AnimNodeBase.h"
#include "Misc/EngineVersionComparison.h"
#if UE_VERSION_OLDER_THAN(5,2,0)
static_assert(0, "Available for UE5.2+. delete h/cpp files");
#endif
#include "Retargeter/IKRetargeter.h"
#include "VrmAnimInstanceRetargetFromMannequin.generated.h"
class UVrmAssetListObject;
struct FAnimNode_VrmSpringBone;
struct FAnimNode_VrmConstraint;
struct FAnimNode_RetargetPoseFromMesh;
USTRUCT()
struct VRM4U_API FVrmAnimInstanceRetargetFromMannequinProxy : public FAnimInstanceProxy {
public:
GENERATED_BODY()
float CurrentDeltaTime = 0.f;
bool bUseRetargeter = false;
bool bIgnoreVRMSwingBone = false;
bool bIgnoreVRMConstraint = false;
bool bIgnoreWindDirectionalSource = false;
int CalcCount = 0;
TSharedPtr<FAnimNode_VrmSpringBone> Node_SpringBone;
TSharedPtr<FAnimNode_VrmConstraint> Node_Constraint;
#if UE_VERSION_OLDER_THAN(5,2,0)
#else
//TWeakObjectPtr<USkeletalMeshComponent> RetargetSourceMeshComponent = nullptr;
TSoftObjectPtr<UIKRetargeter> Retargeter;
TSharedPtr<FAnimNode_RetargetPoseFromMesh> Node_Retarget;
void CustomInitialize();
#endif
FCompactHeapPose CachedPose;
FVrmAnimInstanceRetargetFromMannequinProxy();
FVrmAnimInstanceRetargetFromMannequinProxy(UAnimInstance* InAnimInstance);
virtual void Initialize(UAnimInstance* InAnimInstance) override;
virtual bool Evaluate(FPoseContext& Output) override;
virtual void UpdateAnimationNode(const FAnimationUpdateContext& InContext);
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds);
};
/**
*
*/
UCLASS(Blueprintable, BlueprintType)
class VRM4U_API UVrmAnimInstanceRetargetFromMannequin : public UAnimInstance
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category= Rendering, meta = (NeverAsPin))
bool bUseAttachedParent = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
USkeletalMeshComponent *SrcSkeletalMeshComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
USkinnedMeshComponent* SrcAsSkinnedMeshComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmAssetListObject *DstVrmAssetList;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UVrmMetaObject *DstVrmMetaForCustomSpring;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FName> InitialMorphName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<float> InitialMorphValue;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bUseAnimStop = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bAnimStop = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bCopyStop = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool bIgnoreCenterLocation = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector CenterLocationScaleByHeightScale = {1.f, 1.f, 1.f};
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector CenterLocationOffset = { 0.f, 0.f, 0.f };
protected:
virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override;
virtual bool CanRunParallelWork() const { return false; }
FVrmAnimInstanceRetargetFromMannequinProxy *myProxy = nullptr;
bool bIgnoreVRMSwingBone = false;
bool bIgnoreWindDirectionalSource = false;
public:
virtual void NativeInitializeAnimation()override;
// Native update override point. It is usually a good idea to simply gather data in this step and
// for the bulk of the work to be done in NativeUpdateAnimation.
virtual void NativeUpdateAnimation(float DeltaSeconds)override;
// Native Post Evaluate override point
virtual void NativePostEvaluateAnimation()override;
// Native Uninitialize override point
virtual void NativeUninitializeAnimation()override;
// Executed when begin play is called on the owning component
virtual void NativeBeginPlay()override;
virtual void PreUpdateAnimation(float DeltaSeconds) override;
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetRetargetData(bool bUseRetargeter, UIKRetargeter *IKRetargeter);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetVrmAssetList(UVrmAssetListObject *dstAssetList);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetSkeletalMeshCopyDataForCustomSpring(UVrmMetaObject *dstMetaForCustomSpring);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetVrmSpringBoneParam(float gravityScale = 1.f, FVector gravityAdd = FVector::ZeroVector, float stiffnessScale = 1.f, float stiffnessAdd = 0.f, float randomWindRange = 0.2f);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetVrmSpringBoneBool(bool bIgnoreVrmSpringBone = false, bool bIgnorePhysicsCollision = false, bool bIgnoreVRMCollision = false, bool bIgnoreWind = false);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetVrmSpringBoneIgnoreWingBone(const TArray<FName> &boneNameList);
FVrmAnimInstanceRetargetFromMannequinProxy*GetProxy() { return myProxy; }
};
@@ -0,0 +1,48 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "Animation/AnimInstanceProxy.h"
#include "Animation/AnimNodeBase.h"
#include "Misc/EngineVersionComparison.h"
#include "VrmAnimInstanceTemplate.generated.h"
class UIKRetargeter;
class UVrmMetaObject;
USTRUCT()
struct VRM4U_API FVrmAnimInstanceTemplateProxy : public FAnimInstanceProxy {
public:
GENERATED_BODY()
FVrmAnimInstanceTemplateProxy();
FVrmAnimInstanceTemplateProxy(UAnimInstance* InAnimInstance);
};
/**
*
*/
UCLASS(Blueprintable, BlueprintType)
class VRM4U_API UVrmAnimInstanceTemplate : public UAnimInstance
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = VRM4U)
UIKRetargeter *VrmRetargeter = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = VRM4U)
UVrmMetaObject* VrmMetaObject = nullptr;
protected:
virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override;
FVrmAnimInstanceTemplateProxy *myProxy = nullptr;
public:
FVrmAnimInstanceTemplateProxy *GetProxy() { return myProxy; }
};
@@ -0,0 +1,286 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Engine/SkeletalMesh.h"
#include "Animation/Skeleton.h"
#include "Misc/EngineVersionComparison.h"
#include "VrmImportMaterialSet.h"
#include "VrmUtil.h"
#include "VrmAssetListObject.generated.h"
class UMaterialInterface;
class UTexture2D;
class USkeletalMesh;
class USkeleton;
class UVrmMetaObject;
class UVrmLicenseObject;
class UVrm1LicenseObject;
struct FReturnedData;
class UNodeMappingContainer;
/**
*
*/
UCLASS(Blueprintable, BlueprintType)
class VRM4U_API UVrmAssetListObject : public UObject
{
GENERATED_UCLASS_BODY()
public:
void CopyMember(UVrmAssetListObject *dst) const;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InOption")
bool bAssetSave = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InOption")
bool bSkipMorphTarget=false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* MtoonLitSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* MtoonUnlitSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* SSSSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* SSSProfileSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* UnlitSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* GLTFSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* UEFNUnlitSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* UEFNLitSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* UEFNSSSProfileSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UVrmImportMaterialSet* CustomSet;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Lit")
UMaterialInterface* BaseMToonLitOpaqueMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Lit")
UMaterialInterface* BaseMToonLitTranslucentMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Lit")
UMaterialInterface* OptMToonLitOpaqueMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Lit")
UMaterialInterface* OptMToonLitOpaqueTwoSidedMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Lit")
UMaterialInterface* OptMToonLitTranslucentMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Lit")
UMaterialInterface* OptMToonLitTranslucentTwoSidedMaterial;
// unlit
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_unlit")
UMaterialInterface* BaseMToonUnlitOpaqueMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_unlit")
UMaterialInterface* BaseMToonUnlitTranslucentMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Unlit")
UMaterialInterface* OptMToonUnlitOpaqueMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Unlit")
UMaterialInterface* OptMToonUnlitOpaqueTwoSidedMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Unlit")
UMaterialInterface* OptMToonUnlitTranslucentMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon_Unlit")
UMaterialInterface* OptMToonUnlitTranslucentTwoSidedMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial_MToon")
UMaterialInterface* OptMToonOutlineMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UMaterialInterface* BaseUnlitOpaqueMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UMaterialInterface* BaseUnlitTranslucentMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "InMaterial")
UMaterialInterface* BasePBROpaqueMaterial;
//
//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
//USkeleton* BaseSkeleton;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
USkeletalMesh* BaseSkeletalMesh;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UVrmMetaObject* VrmMetaObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UVrmMetaObject* VrmHumanoidMetaObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UVrmMetaObject* VrmMannequinMetaObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UVrmLicenseObject* VrmLicenseObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UVrm1LicenseObject* Vrm1LicenseObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
USkeletalMesh* SkeletalMesh;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
TArray<UTexture2D*> Textures;
#if WITH_EDITORONLY_DATA
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UTexture2D* SmallThumbnailTexture;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UObject* SSSProfile;
#endif
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
EVRMImportMaterialType ImportMode;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
TArray<UMaterialInterface*> Materials;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
TArray<UMaterialInterface*> OutlineMaterials;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UNodeMappingContainer *HumanoidRig;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UPoseAsset *PoseBody;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
UPoseAsset *PoseFace;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
TArray<bool> MaterialFlag_Translucent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
TArray<bool> MaterialFlag_TwoSided;
// no uproperty
TArray<bool> MaterialFlag_Opaque;
TMap<FString, FTransform> Pose_bind;
TMap<FString, FTransform> Pose_tpose;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
FTransform model_root_transform;
//TArray<FTransform> poseGlobal_bindpose; // bone
//TArray<FTransform> poseGlobal_tpose; // node
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
EVRMImportTextureCompressType Texture_CompressType = EVRMImportTextureCompressType::VRMITC_Auto;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Out")
TArray<EVRMImportTextureCompressType> Texture_CompressTypeList;
UPROPERTY()
UPackage *Package;
UPROPERTY()
UVrmAssetListObject* ReimportBase;
UPROPERTY()
FString FileFullPathName;
UPROPERTY()
FString OrigFileName;
UPROPERTY()
FString BaseFileName;
UPROPERTY()
USkeletalMesh* UE4SkeletalMesh;
UPROPERTY()
USkeletalMesh* HumanoidSkeletalMesh;
TMap<int, int> MaterialMergeTable;
TMap<FString, FString> MaterialNameOrigToAsset;
TMap<FString, int> MaterialNameAssetToMatNo;
TArray<bool> MaterialHasAlphaCutoff;
TArray<bool> MaterialHasMToon;
TSharedPtr<FReturnedData> MeshReturnedData;
//FReturnedData *Result;
#if WITH_EDITORONLY_DATA
//#if UE_VERSION_OLDER_THAN(5,0,0)
// typedef LocalImportData UAssetImportData;
//#else
// typedef LocalImportData TObjectPtr<class UAssetImportData>
//#endif
// VRM4U_PRECOMPILE_500
UPROPERTY(VisibleAnywhere, Instanced, Category = ImportSettings)
class UAssetImportData *AssetImportData = nullptr;
//TObjectPtr<class UAssetImportData> AssetImportData;
#if UE_VERSION_OLDER_THAN(5,0,0)
//class UAssetImportData* AssetImportData = nullptr;
#else
//TObjectPtr<class UAssetImportData> AssetImportData;
#endif
#endif
#if WITH_EDITOR
#if UE_VERSION_OLDER_THAN(5,4,0)
virtual void GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const override;
#else
virtual void GetAssetRegistryTags(FAssetRegistryTagsContext Context) const override;
#endif
// Import data for this
void WaitUntilAsyncPropertyReleased() const;
class UAssetImportData* GetAssetImportData() const
{
//WaitUntilAsyncPropertyReleased(ESkeletalMeshAsyncProperties::AssetImportData);
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return AssetImportData;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void SetAssetImportData(class UAssetImportData* InAssetImportData)
{
//WaitUntilAsyncPropertyReleased(ESkeletalMeshAsyncProperties::AssetImportData);
PRAGMA_DISABLE_DEPRECATION_WARNINGS
AssetImportData = InAssetImportData;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
#endif
};
@@ -0,0 +1,20 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "Engine/AssetUserData.h"
#include "VrmAssetUserData.generated.h"
class UVrmAssetListObject;
UCLASS(BlueprintType)
class VRM4U_API UVrmAssetUserData : public UAssetUserData
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TObjectPtr<UVrmAssetListObject> VrmAssetListObject = nullptr;
};
@@ -0,0 +1,271 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Engine/EngineTypes.h"
#include "Engine/TextureRenderTarget2D.h"
#include "Misc/EngineVersionComparison.h"
#include "Engine/Scene.h"
#include "LiveLinkTypes.h"
#include "Components/SkeletalMeshComponent.h"
#include "VrmUtil.h"
#if UE_VERSION_OLDER_THAN(4,26,0)
#else
#include "AssetRegistry/AssetData.h"
#endif
#if UE_VERSION_OLDER_THAN(4,20,0)
struct FCameraTrackingFocusSettings {
int dummy;
};
#elif UE_VERSION_OLDER_THAN(5,3,0)
#include "CinematicCamera/Public/CineCameraComponent.h"
#else
#include "CineCameraComponent.h"
#endif
#include "VrmBPFunctionLibrary.generated.h"
class UTextureRenderTarget2D;
class UMaterialInstanceConstant;
class UAnimationAsset;
class USkeleton;
#if UE_VERSION_OLDER_THAN(4,20,0)
struct FCameraFilmbackSettings {
public:
int dummy = 0;
};
#endif
UENUM(BlueprintType)
enum class EVRMWidgetMode : uint8
{
WM_Translate,
WM_Rotate,
WM_Scale,
};
/**
*
*/
UCLASS()
class VRM4U_API UVrmBPFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable,Category="VRM4U")
static void VRMTransMatrix(const FTransform &transform, TArray<FLinearColor> &matrix, TArray<FLinearColor> &matrix_inv);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetMorphTargetList(const USkeletalMesh *target, TArray<FString> &morphTargetList);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static bool VRMGetRefBoneTransform(const USkeleton *target, const FName boneName, FTransform &boneTransform);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetHumanoidBoneNameList(TArray<FString> &BoneNameListString, TArray<FName> &BoneNameListName);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetEpicSkeletonBoneNameList(TArray<FString>& BoneNameListString, TArray<FName>& BoneNameListName);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMGetEpicSkeletonToHumanoid(TMap<FString, FString>& table);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static bool VRMGetHumanoidParentBone(const FName boneName, FName &parentBoneName);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMInitAnim(USkeletalMeshComponent *target);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMUpdateRefPose(USkeletalMeshComponent* target, bool bForceAlignGlobal, bool bForceUE4Humanoid);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetMaterialPropertyOverrides(const UMaterialInterface *Material, TEnumAsByte<EBlendMode> &BlendMode, TEnumAsByte<EMaterialShadingModel> &ShadingModel, bool &IsTwoSided, bool &IsMasked);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetMobileMode(bool &IsMobile, bool &IsAndroid, bool &IsIOS);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true"))
static void VRMDrawMaterialToRenderTarget(UObject* WorldContextObject, UTextureRenderTarget2D* TextureRenderTarget, UMaterialInterface* Material);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMUpdateTextureProperty(UTexture* Texture);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialParent(UMaterialInstanceConstant *dst, UMaterialInterface* NewParent, USkeletalMesh *UseSkeletalMesh);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialTexture(UMaterialInstanceConstant *dst, FName texName, UTexture *texture);
// mat begin
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialSkipEditChange(UMaterialInstanceConstant *material, USkeletalMesh *UseSkeletalMesh, bool bSkip);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialShadingModel(UMaterialInstanceConstant *material, EMaterialShadingModel ShadingModel, bool bOverride, bool bForce);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialBlendMode(UMaterialInstanceConstant *material, EBlendMode BlendMode, bool bOverride, bool bForce);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialScalarParameter(UMaterialInstanceConstant *material, FName paramName, float param, bool bEnable);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialVectorParameter(UMaterialInstanceConstant *material, FName paramName, FLinearColor param, bool bEnable);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMChangeMaterialStaticSwitch(UMaterialInstanceConstant *material, FName paramName, bool bEnable);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (DevelopmentOnly))
static void VRMGetMaterialStaticSwitch(UMaterialInstance* material, FName paramName, bool &bHasParam, bool &bEnable);
// mat end
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static UObject* VRMDuplicateAsset(UObject *src, FString name, UObject *thisOwner);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMSetMaterial(USkeletalMesh *target, int no, UMaterialInterface *material);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMSetImportedBounds(USkeletalMesh *target, FVector min, FVector max);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static bool VRMGetAssetsByPackageName(FName PackageName, TArray<FAssetData>& OutAssetData, bool bIncludeOnlyOnDiskAssets = false);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMSetIsDirty(UObject *obj);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static UTextureRenderTarget2D* VRMCreateRenderTarget2D(UObject* WorldContextObject, int32 Width = 256, int32 Height = 256, ETextureRenderTargetFormat Format = RTF_RGBA16f, FLinearColor ClearColor = FLinearColor::Black);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static bool VRMRenderingThreadEnable(bool bEnable);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static int VRMGetMeshSectionNum(const USkeletalMesh* mesh);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static bool VRMRemoveMeshSection(USkeletalMesh* mesh, int LODIndex, int SectionIndex);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static bool VRMGetShadowEnable(const USkeletalMesh *mesh, int MaterialIndex);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetLightingChannelPrim(UPrimitiveComponent *prim, bool channel0, bool channel1, bool channel2);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetLightingChannelLight(ULightComponent *light, bool channel0, bool channel1, bool channel2);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetCastRaytracedShadow(ULightComponent *light, bool bEnable);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetShadowSlopeBias(ULightComponent *light, float bias=0.5f);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetSpecularScale(ULightComponent* light, float scale=1.0f);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetPostProcessSettingAO(FPostProcessSettings& OutSettings, const FPostProcessSettings& InSettings, bool bOverride, float AOIntensity, float Radius, bool bRayTracing = true);
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (DynamicOutputParam = "filmback"))
static bool VRMGetCameraFilmback(UCineCameraComponent *CineCamera, FCameraFilmbackSettings &filmback);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static bool VRMSetCameraFilmback(UCineCameraComponent *CineCamera, const FCameraFilmbackSettings &filmback);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static bool VRMSetPostProcessSettingFromCineCamera(FPostProcessSettings &OutSettings, const FPostProcessSettings &InSettings, const UCineCameraComponent *CineCamera);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetPostProcessToneCurveAmount(FPostProcessSettings& OutSettings, const FPostProcessSettings& InSettings, bool bOverride, float Amount);
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (DynamicOutputParam = "Settings"))
static void VRMMakeCameraTrackingFocusSettings(AActor *ActorToTrack, FVector RelativeOffset, bool bDrawDebugTrackingFocusPoint, FCameraTrackingFocusSettings &Settings);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (DynamicOutputParam = "Settings"))
static void VRMSetActorLabel(AActor *Actor, const FString& NewActorLabel);
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (WorldContext = "WorldContextObject", DynamicOutputParam = "transform"))
static void VRMGetCameraTransform(const UObject* WorldContextObject, int32 PlayerIndex, bool bGameOnly, FTransform &transform, float &fovDegree);
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMGetPlayMode(bool &bPlay, bool &bSIE, bool &bIsEditor);
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (WorldContext = "WorldContextObject", DynamicOutputParam = "skeleton"))
static bool VRMGetAnimationAssetData(const UAnimationAsset *animAsset, USkeleton *&skeleton);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMExecuteConsoleCommand(UObject* WorldContextObject, const FString &cmd);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static bool VRMSetTransparentWindow(bool bEnable, FLinearColor crKey);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static bool VRMAddTickPrerequisite(UActorComponent *dst, UActorComponent *src, bool bRemove);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMAllowTranslucentSelection(bool bEnable);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject"))
static void VRMSetWidgetMode(const EVRMWidgetMode mode);
//UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (DynamicOutputParam = "PropertyNames|PropertyValues|FrameNo"))
//static bool VRMLiveLinkEvaluate(const FName Subject, TArray<FName> &PropertyNames, TArray<float> &PropertyValues, int &FrameNo);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (DevelopmentOnly))
static bool VRMBakeAnim(const USkeletalMeshComponent* skc, const FString& FilePath, const FString& AssetFileName);
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject", DeterminesOutputType = "UObjectClass", DynamicOutputParam = "OutActors"))
static void VRMGetAllActorsHasSceneComponent(const UObject* WorldContextObject, TSubclassOf<UObject> UObjectClass, TArray<AActor*>& OutActors);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetUEVersion(int& major, int& minor, int& patch) {
major = ENGINE_MAJOR_VERSION;
minor = ENGINE_MINOR_VERSION;
patch = ENGINE_PATCH_VERSION;
}
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (WorldContext = "WorldContextObject", DynamicOutputParam = "RigNodeName"))
static void VRMGetRigNodeNameFromBoneName(const USkeleton *skeleton, const FName &boneName, FName &RigNodeName);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMSetPerBoneMotionBlur(USkinnedMeshComponent* SkinnedMesh, bool bUsePerBoneMotionBlur);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMGetIKRigDefinition(UObject *retargeter, UObject *& src, UObject *& target);
//static void GetIKRigDefinition(UIKRetargeter, UIKRigDefinition * &src, UIKRigDefinition * &target)
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetPreviewMesh(UObject* target, USkeletalMesh*& mesh);
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (DynamicOutputParam = "skeletalmesh"))
static void VRMGetSkeletalMeshFromSkinnedMeshComponent(const USkinnedMeshComponent* target, USkeletalMesh*& skeletalmesh);
UFUNCTION(BlueprintPure, Category = "VRM4U", meta = (DynamicOutputParam = "AssetName"))
static void VRMGetTopLevelAssetName(const FAssetData& target, FName& AssetName);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static UVrmAssetListObject* VRMGetVrmAssetListObjectFromAsset(const UObject *Asset);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static bool VRMIsMovieRendering();
UFUNCTION(BlueprintPure, Category = "VRM4U")
static bool VRMIsTemporaryObject(const UObject *obj);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static bool VRMIsEditorPreviewObject(const UObject* obj);
UFUNCTION(BlueprintPure, Category = "VRM4U")
static void VRMGetViewportSize(FIntPoint &ViewportSize, FIntPoint &BufferSize);
};
@@ -0,0 +1,44 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Components/PoseableMeshComponent.h"
#include "Misc/CoreDelegates.h"
#if WITH_EDITOR
#include "Editor/UnrealEdTypes.h"
#endif
#include "VrmCameraCheckComponent.generated.h"
/**
*
*/
UCLASS(meta=(BlueprintSpawnableComponent))
class VRM4U_API UVrmCameraCheckComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FVrmCameraCheckDelegate);
UPROPERTY(BlueprintAssignable)
FVrmCameraCheckDelegate OnCameraMove;
UFUNCTION(BlueprintCallable, Category = "VRM4U", meta = (DynamicOutputParam = "OutVrmAsset"))
void SetCameraCheck(bool bCheckOn);
public:
void OnRegister() override;
void OnUnregister() override;
private:
#if WITH_EDITOR
void OnCameraTransformChanged(const FVector&, const FRotator&, ELevelViewportType, int32);
#endif
FDelegateHandle handle;
};
@@ -0,0 +1,25 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "CineCameraActor.h"
#include "VrmCineCameraActor.generated.h"
UCLASS(ClassGroup = Common, hideCategories = (Input, Rendering, AutoPlayerActivation), showcategories = ("Input|MouseInput", "Input|TouchInput"), Blueprintable)
class VRM4U_API AVrmCineCameraActor : public ACineCameraActor
{
GENERATED_BODY()
public:
// Ctor
AVrmCineCameraActor(const FObjectInitializer& ObjectInitializer);
UFUNCTION(BlueprintCallable, Category = "Camera")
UVrmCineCameraComponent* GetVrmCineCameraComponent() const;
public:
};
@@ -0,0 +1,30 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "CineCameraComponent.h"
#include "VrmCineCameraComponent.generated.h"
UCLASS(Blueprintable, ClassGroup = Camera, meta=(BlueprintSpawnableComponent))
class VRM4U_API UVrmCineCameraComponent : public UCineCameraComponent
{
GENERATED_BODY()
public:
virtual void OnRegister() override;
#if WITH_EDITORONLY_DATA
// Refreshes the visual components to match the component state
virtual void RefreshVisualRepresentation() override;
#endif
virtual void GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView) override;
UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Vrm Camera Settings")
FVector2D OffCenterProjectionOffset;
};
@@ -0,0 +1,24 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "VrmCustomStruct.generated.h"
USTRUCT(BlueprintType)
struct FVRMRetargetSrcAnimSequence
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
class UAnimSequenceBase *AnimSequence = nullptr;
};
namespace {
//bool operator<(const FBoneTransform &a, const FBoneTransform &b) {
// return a.BoneIndex < b.BoneIndex;
//}
}
@@ -0,0 +1,32 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Components/PrimitiveComponent.h"
#include "Components/DrawFrustumComponent.h"
#include "VrmDrawFrustumComponent.generated.h"
class FPrimitiveSceneProxy;
/**
* Utility component for drawing a view frustum. Origin is at the component location, frustum points down position X axis.
*/
UCLASS(collapsecategories, hidecategories=Object, editinlinenew, MinimalAPI)
class UVrmDrawFrustumComponent : public UDrawFrustumComponent
{
GENERATED_UCLASS_BODY()
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DrawFrustumComponent)
FVector2D OffCenterProjectionOffset;
};
@@ -0,0 +1,77 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
// ApplicationLifecycleComponent.: See FCoreDelegates for details
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Components/ActorComponent.h"
#include "Misc/CoreDelegates.h"
#include "VrmDropFiles.generated.h"
// A parallel enum to the temperature change severity enum in CoreDelegates
// Note if you change this, then you must change the one in CoreDelegates
/*
UENUM(BlueprintType)
enum class ETemperatureSeverityType : uint8
{
Unknown,
Good,
Bad,
Serious,
Critical,
NumSeverities,
};
*/
//static_assert((int)ETemperatureSeverityType::NumSeverities == (int)FCoreDelegates::ETemperatureSeverity::NumSeverities, "TemperatureSeverity enums are out of sync");
/** Component to handle receiving notifications from the OS about application state (activated, suspended, termination, etc). */
UCLASS(ClassGroup=Utility, HideCategories=(Activation, "Components|Activation", Collision), meta=(BlueprintSpawnableComponent))
class VRM4U_API UVrmDropFilesComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
//DECLARE_DYNAMIC_MULTICAST_DELEGATE(FApplicationLifetimeDelegate);
//DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTemperatureChangeDelegate , ETemperatureSeverityType, Severity);
//DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLowPowerModeDelegate, bool, bInLowPowerMode);
DECLARE_MULTICAST_DELEGATE_OneParam(FStaticOnDropFiles, FString);
static FStaticOnDropFiles StaticOnDropFilesDelegate;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnDropFiles, FString, FileName);
UPROPERTY(BlueprintAssignable)
FOnDropFiles OnDropFiles;
static UVrmDropFilesComponent *s_LatestActiveComponent;
public:
void OnRegister() override;
void OnUnregister() override;
static const UVrmDropFilesComponent* getLatestActiveComponent() {
return s_LatestActiveComponent;
};
UFUNCTION(BlueprintCallable, Category = "VRM4U")
bool VRMGetOpenFileName(FString &Filename);
private:
/** Native handlers that get registered with the actual FCoreDelegates, and then proceed to broadcast to the delegates above */
/*
void ApplicationWillDeactivateDelegate_Handler() { ApplicationWillDeactivateDelegate.Broadcast(); }
void ApplicationHasReactivatedDelegate_Handler() { ApplicationHasReactivatedDelegate.Broadcast(); }
void ApplicationWillEnterBackgroundDelegate_Handler() { ApplicationWillEnterBackgroundDelegate.Broadcast(); }
void ApplicationHasEnteredForegroundDelegate_Handler() { ApplicationHasEnteredForegroundDelegate.Broadcast(); }
void ApplicationWillTerminateDelegate_Handler() { ApplicationWillTerminateDelegate.Broadcast(); }
void ApplicationShouldUnloadResourcesDelegate_Handler() { ApplicationShouldUnloadResourcesDelegate.Broadcast(); }
void ApplicationReceivedStartupArgumentsDelegate_Handler(const TArray<FString>& StartupArguments) { ApplicationReceivedStartupArgumentsDelegate.Broadcast(StartupArguments); }
void OnTemperatureChangeDelegate_Handler(FCoreDelegates::ETemperatureSeverity Severity) { OnTemperatureChangeDelegate.Broadcast((ETemperatureSeverityType)Severity); }
void OnLowPowerModeDelegate_Handler(bool bInLowerPowerMode) { OnLowPowerModeDelegate.Broadcast(bInLowerPowerMode); }
*/
void OnDropFilesDelegate_Handler(FString FileName) { OnDropFiles.Broadcast(FileName); }
};
@@ -0,0 +1,94 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Components/PoseableMeshComponent.h"
#include "Misc/CoreDelegates.h"
#include "VrmEditorEventComponent.generated.h"
UENUM(BlueprintType)
enum class EVRM4U_PIEEvent : uint8
{
PreBeginPIE,
BeginPIE,
PrePIEEnded,
PostPIEStarted,
EndPIE,
PausePIE,
ResumePIE,
SingleStepPIE,
OnPreSwitchBeginPIEAndSIE,
OnSwitchBeginPIEAndSIE,
};
/**
*
*/
UCLASS(meta=(BlueprintSpawnableComponent))
class VRM4U_API UVrmEditorEventComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVrmSelectionChangedEventDelegate, bool, dummy);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVrmSelectionObjectEventDelegate, bool, dummy);
UPROPERTY(BlueprintAssignable)
FVrmSelectionChangedEventDelegate OnSelectionChange;
UPROPERTY(BlueprintAssignable)
FVrmSelectionObjectEventDelegate OnSelectionObject;
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetSelectCheck(bool bCheckOn);
//
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVrmPIEEventDelegate, EVRM4U_PIEEvent, dummy);
UPROPERTY(BlueprintAssignable)
FVrmPIEEventDelegate OnPIEEvent;
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetPIEEventCheck(bool bCheckOn);
//
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVrmGlobalTimeChangeEventDelegate, float, CurrentTime);
UPROPERTY(BlueprintAssignable)
FVrmGlobalTimeChangeEventDelegate OnGlobalTimeChange;
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetGlobalTimeCheck(bool bCheckOn);
public:
void OnRegister() override;
void OnUnregister() override;
private:
void OnSelectionObjectFunc(UObject *obj);
void OnSelectionChangeFunc(UObject *obj);
void OnGlobalTimeChangeFunc();
/*
PreBeginPIE,
BeginPIE,
PrePIEEnded,
PostPIEStarted,
EndPIE,
PausePIE,
ResumePIE,
SingleStepPIE,
OnPreSwitchBeginPIEAndSIE,
OnSwitchBeginPIEAndSIE,
*/
void OnBeginPIE(const bool bIsSimulating);
void OnEndPIE(const bool bIsSimulating);
void OnPIEEventFunc(EVRM4U_PIEEvent e);
FDelegateHandle handle;
};
@@ -0,0 +1,28 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "Engine/DataAsset.h"
#include "VrmImportMaterialSet.generated.h"
class UMaterialInterface;
UCLASS(BlueprintType)
class VRM4U_API UVrmImportMaterialSet : public UDataAsset{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material")
UMaterialInterface* Opaque;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material")
UMaterialInterface* OpaqueTwoSided;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material")
UMaterialInterface* Translucent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material")
UMaterialInterface* TranslucentTwoSided;
};
@@ -0,0 +1,73 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
//#if WITH_EDITOR
//#include "UnrealEd.h"
//#include "AssetTypeActions_Base.h"
//#endif
#include "VrmLicenseObject.generated.h"
class UTexture2D;
/**
*
*/
UCLASS(Blueprintable, BlueprintType)
class VRM4U_API UVrmLicenseObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Information)
FString title;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Information)
FString version;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Information)
FString author;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Information)
FString contactInformation;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Information)
FString reference;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Information)
UTexture2D *thumbnail;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License_Personation/CharacterizationPermission")
FString allowedUserName;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License_Personation/CharacterizationPermission")
FString violentUsageName;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License_Personation/CharacterizationPermission")
FString sexualUsageName;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License_Personation/CharacterizationPermission")
FString commercialUsageName;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License_Personation/CharacterizationPermission")
FString otherPermissionUrl;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License_Redistribution/ModificationsLicense")
FString licenseName;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "License_Redistribution/ModificationsLicense")
FString otherLicenseUrl;
};
/*
#if WITH_EDITOR
class FAssetTypeActions_VrmLicenseObject : public FAssetTypeActions_Base
{
public:
virtual FText GetName() const override
{ return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_MyAsset", "MyAsset"); }
virtual FColor GetTypeColor() const override { return FColor::White; }
virtual uint32 GetCategories() override { return EAssetTypeCategories::Misc; }
virtual UClass* GetSupportedClass() const override {
return UVrmLicenseObject::StaticClass();
};
virtual bool IsImportedAsset() const override { return false; }
};
#endif
*/
@@ -0,0 +1,405 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "VrmMetaObject.generated.h"
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMSpringMeta{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float stiffness = 0.2f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float gravityPower = 0.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector gravityDir = { 0,-1,0 };
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float dragForce = 0.4f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float hitRadius = 0.f;
//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
//int boneNum = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<int> bones;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FString> boneNames;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<int> ColliderIndexArray;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<int> ColliderGroupArrayVRM10; // for datacheck
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMSpringColliderData {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector offset = FVector::ZeroVector;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float radius = 0.f;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMColliderGroupMeta {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString groupName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<int> colliderGroup;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMColliderMeta {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int bone = -1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString boneName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRMSpringColliderData> collider;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRM1SpringJointMeta {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int boneNo = -1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString boneName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float hitRadius = 0.1f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float stiffness = 0.5f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float gravityPower = 1.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector gravityDir = { 0,-1,0 };
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float dragForce = 0.5f;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRM1SpringMeta {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRM1SpringJointMeta> joints;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<int> colliderGroups;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int center = 0;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRM1SpringCollider {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int boneNo = -1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString boneName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FName shapeType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector offset = FVector::ZeroVector;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float radius = 0.f;
// for capsule. offset-tail cylinder
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVector tail = FVector::ZeroVector;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRM1SpringColliderGroups {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString name;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<int> colliders;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRM1SpringBoneMeta {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRM1SpringMeta> Springs;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRM1SpringCollider> Colliders;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRM1SpringColliderGroups> ColliderGroups;
};
//////
// BlendShape
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVrmBlendShape{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString morphTargetName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString nodeName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString meshName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int meshID=0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int shapeIndex=0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int weight=100;
};
// BlendShape Material
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVrmBlendShapeMaterialList {
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString materialName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString propertyName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FLinearColor color = FLinearColor::Black;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVrmBlendShapeGroup {
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString name;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVrmBlendShape> BlendShape;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVrmBlendShapeMaterialList> MaterialList;
// vrm10
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
bool isBinary = false;
// none, block, blend
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString overrideBlink;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString overrideLookAt;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString overrideMouth;
};
//struct VRM4U_API FBVrmlendShapeGroup {
// TArray<FVrmBlendShape>
//};
UENUM(BlueprintType)
enum class EVRMConstraintType : uint8 {
None, Roll, Aim, Rotation,
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMConstraintRoll {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString sourceName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int source = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString rollAxis;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float weight = 1.f;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMConstraintAim {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString sourceName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int source = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString aimAxis;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float weight = 1.f;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMConstraintRotation {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString sourceName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int source = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
float weight = 1.f;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMAnimationLookAt {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int lookAtNode = -1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString lookAtNodeName;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMAnimationExpressionPreset {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString expressionName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int expressionNode = -1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FString expressionNodeName;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMAnimationMeta {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVRMAnimationLookAt lookAt;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRMAnimationExpressionPreset> expressionPreset;
};
USTRUCT(Blueprintable, BlueprintType)
struct VRM4U_API FVRMConstraint {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
EVRMConstraintType type = EVRMConstraintType::None;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVRMConstraintRoll constraintRoll;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVRMConstraintAim constraintAim;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVRMConstraintRotation constraintRotation;
};
UCLASS(Blueprintable, BlueprintType)
class VRM4U_API UVrmMetaObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
int Version = 0;
UFUNCTION(BlueprintPure, Category = "VRM4U")
int GetVRMVersion() const {
return Version;
}
// humanoid name -> model name
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TMap<FString, FString> humanoidBoneTable;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVrmBlendShapeGroup> BlendShapeGroup;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRMSpringMeta> VRMSpringMeta;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVRM1SpringBoneMeta VRM1SpringBoneMeta;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRMColliderMeta> VRMColliderMeta;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<FVRMColliderGroupMeta> VRMColliderGroupMeta;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TMap<FString, FVRMConstraint> VRMConstraintMeta;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
FVRMAnimationMeta VRMAnimationMeta;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
class USkeletalMesh *SkeletalMesh;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
class UVrmAssetListObject *VrmAssetListObject;
};
@@ -0,0 +1,44 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "VrmModelActor.generated.h"
class USkeletalMesh;
UCLASS()
class VRM4U_API AVrmModelActor : public AActor
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UMaterialInterface* BaseOpaqueMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
UMaterialInterface* BaseTransparentMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<UTexture2D*> Textures;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
TArray<UMaterialInterface*> Materials;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Rendering)
USkeletalMesh* SkeletalMesh;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//virtual void OnConstruction(const FTransform& Transform)override;
};
@@ -0,0 +1,19 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Engine/EngineTypes.h"
#include "VrmNetworkBPFunctionLibrary.generated.h"
UCLASS()
class VRM4U_API UVrmNetworkBPFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static void VRMGetIPAddressTable(TArray<FString> &AddressTable);
};
@@ -0,0 +1,48 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Components/PoseableMeshComponent.h"
#include "VrmPoseableMeshComponent.generated.h"
/**
*
*/
UCLASS(Blueprintable, meta=(BlueprintSpawnableComponent))
class VRM4U_API UVrmPoseableMeshComponent : public UPoseableMeshComponent
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
bool bUseParentAsLeader = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
bool bUseDefaultMaterial = false;
void OnRegister() override;
UFUNCTION(BlueprintImplementableEvent, Category = "VRM4U")
void Init();
virtual void RefreshBoneTransforms(FActorComponentTickFunction* TickFunction = NULL) override;
UFUNCTION(BlueprintCallable, Category = "Components|PoseableMesh")
void VRMCopyPoseAndMorphFromSkeletalComponent(USkeletalMeshComponent* InComponentToCopy);
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
virtual void UpdateLeader();
virtual void InitializeComponent() override;
virtual void OnAttachmentChanged() override;
#if WITH_EDITOR
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
virtual void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override;
#endif
};
@@ -0,0 +1,54 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#if UE_VERSION_OLDER_THAN(5,0,0)
#elif UE_VERSION_OLDER_THAN(5,2,0)
#include "UObject/UnrealTypePrivate.h"
#include "IKRigDefinition.h"
#include "IKRigSolver.h"
#include "Retargeter/IKRetargeter.h"
#if WITH_EDITOR
#include "RigEditor/IKRigController.h"
#include "RetargetEditor/IKRetargeterController.h"
#include "Solvers/IKRig_PBIKSolver.h"
#endif
#elif UE_VERSION_OLDER_THAN(5,3,0)
#include "UObject/UnrealTypePrivate.h"
#include "IKRigDefinition.h"
#include "IKRigSolver.h"
#include "Retargeter/IKRetargeter.h"
#if WITH_EDITOR
#include "RigEditor/IKRigController.h"
#include "RetargetEditor/IKRetargeterController.h"
#include "Solvers/IKRig_FBIKSolver.h"
#endif
#elif UE_VERSION_OLDER_THAN(5,6,0)
#include "UObject/UnrealTypePrivate.h"
#include "Rig/IKRigDefinition.h"
#include "Rig/Solvers/IKRigSolver.h"
#include "Retargeter/IKRetargeter.h"
#if WITH_EDITOR
#include "RigEditor/IKRigController.h"
#include "RetargetEditor/IKRetargeterController.h"
#include "Rig/Solvers/IKRig_FBIKSolver.h"
#endif
#else
#include "UObject/UnrealTypePrivate.h"
#include "Rig/IKRigDefinition.h"
#include "Rig/Solvers/IKRigFullBodyIK.h"
#include "Retargeter/IKRetargeter.h"
#if WITH_EDITOR
#include "RigEditor/IKRigController.h"
#include "RetargetEditor/IKRetargeterController.h"
#endif
#endif
@@ -0,0 +1,59 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
//#include "VrmAssetListObject.h"
#include "VrmRuntimeSettings.generated.h"
/**
*
*/
UCLASS(config=Engine, defaultconfig)
class VRM4U_API UVrmRuntimeSettings : public UObject
{
GENERATED_UCLASS_BODY()
// Enables experimental *incomplete and unsupported* texture atlas groups that sprites can be assigned to
//UPROPERTY(EditAnywhere, config, Category=Settings)
//bool bEnableSpriteAtlasGroups;
/** For runtime load sample map */
UPROPERTY(config, EditAnywhere, Category = Settings, meta = (
ConfigRestartRequired=true
))
uint32 bDropVRMFileEnable:1;
UPROPERTY(config, EditAnywhere, Category = Settings, meta = (
ConfigRestartRequired = true
))
bool bAllowAllAssimpFormat = false;
//UPROPERTY(config, EditAnywhere, Category = Settings, meta = (AllowedClasses = "VrmAssetListObject", ExactClass = false))
/** Default material set for runtimeload */
UPROPERTY(config, EditAnywhere, Category = Settings, meta = (
AllowedClasses = "/Script/CoreUObject.Object",
ExactClass = false
))
FSoftObjectPath AssetListObject;
/** priority<100 for VRM4U. Default plugins priority=100 */
UPROPERTY(config, EditAnywhere, Category = Settings, meta = (
ConfigRestartRequired = true
))
int32 ImportPriority = 90;
UPROPERTY(config, EditAnywhere, Category = Settings, meta = (
ConfigRestartRequired = true
))
TArray<FString> extList;
#if WITH_EDITOR
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent);
#endif
};
+589
View File
@@ -0,0 +1,589 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Misc/EngineVersionComparison.h"
#include "UObject/ObjectMacros.h"
#include "Engine/Texture.h"
#if UE_VERSION_OLDER_THAN(5,1,0)
#else
#include "Engine/SkinnedAssetCommon.h"
#include "Engine/SkinnedAsset.h"
#endif
#include "Components/SkeletalMeshComponent.h"
#include "Engine/SkeletalMesh.h"
#include "VrmUtil.generated.h"
class USkeleton;
struct FReferenceSkeleton;
class UMorphTarget;
class UPhysicsAsset;
struct FSkeletalMaterial;
// skeleton begin
template<typename T>
USkeleton* VRMGetSkeleton(T* t){
if (t == nullptr) return nullptr;
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->Skeleton;
#else
return t->GetSkeleton();
#endif
}
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
template<typename T>
USkeleton* VRMGetSkeleton(TObjectPtr<T> t) {
return t->GetSkeleton();
}
#endif
template<typename T>
const USkeleton* VRMGetSkeleton(const T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->Skeleton;
#else
return t->GetSkeleton();
#endif
}
template<typename T>
void VRMSetSkeleton(T* t, USkeleton *sk) {
#if UE_VERSION_OLDER_THAN(4,27,0)
t->Skeleton = sk;
#else
t->SetSkeleton(sk);
#endif
}
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
template<typename T>
void VRMSetSkeleton(TObjectPtr<T> t, USkeleton* sk) {
t->SetSkeleton(sk);
}
#endif
//skeleton end
// refskeleton begin
template<typename T>
FReferenceSkeleton& VRMGetRefSkeleton(T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->RefSkeleton;
#else
return t->GetRefSkeleton();
#endif
}
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
template<typename T>
FReferenceSkeleton& VRMGetRefSkeleton(TObjectPtr<T> t) {
return t->GetRefSkeleton();
}
#endif
template<typename T>
const FReferenceSkeleton& VRMGetRefSkeleton(const T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->RefSkeleton;
#else
return t->GetRefSkeleton();
#endif
}
template<typename T>
void VRMSetRefSkeleton(T* t, const FReferenceSkeleton& refsk) {
#if UE_VERSION_OLDER_THAN(4,27,0)
t->RefSkeleton = refsk;
#else
t->SetRefSkeleton(refsk);
#endif
}
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
template<typename T>
void VRMSetRefSkeleton(TObjectPtr<T> t, const FReferenceSkeleton& refsk) {
t->SetRefSkeleton(refsk);
}
#endif
//refskeleton end
// morph targets
#if UE_VERSION_OLDER_THAN(5,4,0)
template<typename T>
TArray<UMorphTarget*>& VRMGetMorphTargets(T* t) {
#else
template<typename T>
TArray<TObjectPtr<UMorphTarget>>& VRMGetMorphTargets(T * t) {
#endif
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->MorphTargets;
#else
return t->GetMorphTargets();
#endif
}
template<typename T>
const TArray<UMorphTarget*>& VRMGetMorphTargets(const T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->MorphTargets;
#else
return t->GetMorphTargets();
#endif
}
// materials
template<typename T>
TArray<FSkeletalMaterial>& VRMGetMaterials(T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->Materials;
#else
return t->GetMaterials();
#endif
}
// physics
template<typename T>
void VRMSetPhysicsAsset(T* t, UPhysicsAsset *pa) {
#if UE_VERSION_OLDER_THAN(4,27,0)
t->PhysicsAsset = pa;
#else
t->SetPhysicsAsset(pa);
#endif
}
template<typename T>
UPhysicsAsset* VRMGetPhysicsAsset(T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->PhysicsAsset;
#else
return t->GetPhysicsAsset();
#endif
}
// nodemappingdata
#if UE_VERSION_OLDER_THAN(5,4,0)
template<typename T>
TArray<class UNodeMappingContainer*>& VRMGetNodeMappingData(T* t) {
#else
template<typename T>
TArray<TObjectPtr<class UNodeMappingContainer>>& VRMGetNodeMappingData(T * t) {
#endif
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->NodeMappingData;
#else
return t->GetNodeMappingData();
#endif
}
template<typename T>
const TArray<class UNodeMappingContainer*>& VRMGetNodeMappingData(const T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->NodeMappingData;
#else
return t->GetNodeMappingData();
#endif
}
// retargetbase
template<typename T>
void VRMSetRetargetBasePose(T* t, TArray<FTransform>& pose) {
#if UE_VERSION_OLDER_THAN(4,27,0)
t->RetargetBasePose = pose;
#elif UE_VERSION_OLDER_THAN(5,3,0)
t->SetRetargetBasePose(pose);
#else
// no old retarget pose.
#endif
}
template<typename T>
TArray<FTransform>& VRMGetRetargetBasePose(T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->RetargetBasePose;
#else
return t->GetRetargetBasePose();
#endif
}
template<typename T>
const TArray<FTransform>& VRMGetRetargetBasePose(const T* t) {
#if UE_VERSION_OLDER_THAN(4,27,0)
return t->RetargetBasePose;
#else
return t->GetRetargetBasePose();
#endif
}
// key
template<typename T>
void VRMSetUseLegacyMeshDerivedDataKey(T* t, bool b) {
#if UE_VERSION_OLDER_THAN(4,27,0)
t->UseLegacyMeshDerivedDataKey = b;
#elif UE_VERSION_OLDER_THAN(5,4,0)
t->SetUseLegacyMeshDerivedDataKey(b);
#else
// ue5.4 no action
#endif
}
#if UE_VERSION_OLDER_THAN(5,0,0)
#else
VRM4U_API void VRMAddRetargetChain(class UIKRigController* con, FName name, FName begin, FName end);
#endif
//template<typename T>
FORCEINLINE USkeletalMesh *VRMGetSkeletalMeshAsset(USkeletalMeshComponent* t) {
#if UE_VERSION_OLDER_THAN(5,1,0)
return t->SkeletalMesh;
#else
return (t->GetSkeletalMeshAsset());
#endif
}
FORCEINLINE const USkeletalMesh* VRMGetSkeletalMeshAsset(const USkeletalMeshComponent* t) {
#if UE_VERSION_OLDER_THAN(5,1,0)
return t->SkeletalMesh;
#else
return (t->GetSkeletalMeshAsset());
#endif
}
FORCEINLINE USkeletalMesh *VRMGetSkeletalMeshAsset(TWeakObjectPtr<USkeletalMeshComponent> t) {
#if UE_VERSION_OLDER_THAN(5,1,0)
return t->SkeletalMesh;
#else
return (t->GetSkeletalMeshAsset());
#endif
}
FORCEINLINE const USkeletalMesh* VRMGetSkeletalMeshAsset(TWeakObjectPtr<const USkeletalMeshComponent> t) {
#if UE_VERSION_OLDER_THAN(5,1,0)
return t->SkeletalMesh;
#else
return (t->GetSkeletalMeshAsset());
#endif
}
//template<>
FORCEINLINE USkeletalMesh *VRMGetSkinnedAsset(USkinnedMeshComponent* t) {
#if UE_VERSION_OLDER_THAN(5,1,0)
return t->SkeletalMesh;
#else
return Cast<USkeletalMesh>(t->GetSkinnedAsset());
#endif
}
//template<>
FORCEINLINE USkeletalMesh *VRMGetSkinnedAsset(const USkinnedMeshComponent* t) {
#if UE_VERSION_OLDER_THAN(5,1,0)
return t->SkeletalMesh;
#else
return Cast<USkeletalMesh>(t->GetSkinnedAsset());
#endif
}
//
//
UENUM(BlueprintType)
enum class EVRMImportMaterialType : uint8
{
VRMIMT_Auto UMETA(DisplayName = "Auto(MToon Unlit)"),
VRMIMT_MToon UMETA(DisplayName = "MToon Lit"),
VRMIMT_MToonUnlit UMETA(DisplayName = "MToon Unlit"),
VRMIMT_SSS UMETA(DisplayName = "Subsurface"),
VRMIMT_SSSProfile UMETA(DisplayName = "Subsurface Profile"),
VRMIMT_Unlit UMETA(DisplayName = "Unlit"),
VRMIMT_glTF UMETA(DisplayName = "PBR(glTF2)"),
VRMIMT_UEFNLit UMETA(DisplayName = "UEFN(Lit)"),
VRMIMT_UEFNUnlit UMETA(DisplayName = "UEFN(Unlit)"),
VRMIMT_UEFNSSSProfile UMETA(DisplayName = "UEFN(SSSProfile)"),
VRMIMT_Custom UMETA(DisplayName = "Custom"),
VRMIMT_MAX,
};
UENUM(BlueprintType)
enum class EVRMImportTextureCompressType : uint8
{
VRMITC_Auto UMETA(DisplayName = "Auto(DXT1)"),
VRMITC_DXT1 UMETA(DisplayName = "DXT1"),
VRMITC_BC7 UMETA(DisplayName = "BC7"),
VRMITC_NoCompression UMETA(DisplayName = "NoCompression"),
VRMITC_MAX,
};
USTRUCT(BlueprintType)
struct VRM4U_API FImportOptionData {
public:
GENERATED_BODY()
#if UE_VERSION_OLDER_THAN(4,26,0)
static const bool VRM4U_UseBC7 = false;
#else
static const bool VRM4U_UseBC7 = true;
#endif
#if UE_VERSION_OLDER_THAN(5,2,0)
static const bool VRM4U_UseUE5Mat = false;
#else
static const bool VRM4U_UseUE5Mat = true;
#endif
void init();
bool bUEFN = false;
bool bAPoseRetarget = true;
bool bMobileBone = false;
int BoneWeightInfluenceNum = 8;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
EVRMImportMaterialType MaterialType = EVRMImportMaterialType::VRMIMT_Auto;
bool bForceOverride = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
float ModelScale = 1.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
float AnimationTranslateScale = 1.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
float PlayRateScale = 1.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bRemoveRootBoneRotation = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bRemoveRootBonePosition = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bVrm10RemoveLocalRotation = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bVrm10UseBindToRestPose = true;
bool bVrm10Bindpose = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bForceOriginalBoneName = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bGenerateHumanoidRenamedMesh = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bGenerateIKBone = false;
bool bGenerateRigIK = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bSkipPhysics = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bSkipRetargeter = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bSkipMorphTarget = false;
bool bEnableMorphTargetNormal = false;
bool bForceOriginalMorphTargetName = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bRemoveBlendShapeGroupPrefix = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bForceOpaque= false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bForceTwoSided = false;
bool bSingleUAssetFile = false;
bool bDefaultGridTextureMode = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bBC7Mode = VRM4U_UseBC7;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bMipmapGenerateMode = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bUseUE5Material = VRM4U_UseUE5Mat;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bGenerateOutlineMaterial = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bMergeMaterial = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bMergePrimitive = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bOptimizeVertex = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bRemoveDegenerateTriangles = false;
bool bSimpleRoot = true;
bool bActiveBone = true;
bool bSkipNoMeshBone = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bIgnoreVRMValidation = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bDebugOneBone = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bDebugNoMesh = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRM4U")
bool bDebugNoMaterial = false;
UPROPERTY()
class USkeleton* Skeleton = nullptr;
};
class VRM4U_API VRMUtil {
//GENERATED_UCLASS_BODY()
public:
struct VRMBoneTable {
FString BoneUE4;
FString BoneVRM;
};
static const TArray<VRMBoneTable> table_ue4_vrm;
static const TArray<VRMBoneTable> table_ue4_pmx;
static bool GetReplacedPMXBone(FString &replaced, const FString &base);
static const TArray<FString> vrm_humanoid_bone_list;
static const TArray<FName> vrm_humanoid_bone_list_name;
static const TArray<FString> vrm_humanoid_parent_list;
static const TArray<FString> ue4_humanoid_bone_list;
static const TArray<FName> ue4_humanoid_bone_list_name;
struct FImportImage
{
#if UE_VERSION_OLDER_THAN(4,23,0)
TArray<uint8> RawData;
#else
TArray64<uint8> RawData;
#endif
ETextureSourceFormat Format = TSF_Invalid;
TextureCompressionSettings CompressionSettings = TC_Default;
int32 NumMips;
int32 SizeX = 0;
int32 SizeY = 0;
bool SRGB = true;
static int32 GetBytesPerPixel(ETextureSourceFormat Format)
{
int32 BytesPerPixel = 0;
switch (Format)
{
case TSF_G8: BytesPerPixel = 1; break;
#if UE_VERSION_OLDER_THAN(4,24,0)
#else
case TSF_G16: BytesPerPixel = 2; break;
#endif
case TSF_BGRA8: BytesPerPixel = 4; break;
case TSF_BGRE8: BytesPerPixel = 4; break;
case TSF_RGBA16: BytesPerPixel = 8; break;
case TSF_RGBA16F: BytesPerPixel = 8; break;
default: BytesPerPixel = 0; break;
}
return BytesPerPixel;
}
void Init2DWithParams(int32 InSizeX, int32 InSizeY, ETextureSourceFormat InFormat, bool InSRGB);
void Init2DWithOneMip(int32 InSizeX, int32 InSizeY, ETextureSourceFormat InFormat, const void* InData = nullptr) {
SizeX = InSizeX;
SizeY = InSizeY;
NumMips = 1;
Format = InFormat;
RawData.AddUninitialized((int64)SizeX * SizeY * GetBytesPerPixel(Format));
if (InData)
{
FMemory::Memcpy(RawData.GetData(), InData, RawData.Num());
}
}
void Init2DWithMips(int32 InSizeX, int32 InSizeY, int32 InNumMips, ETextureSourceFormat InFormat, const void* InData = nullptr);
int64 GetMipSize(int32 InMipIndex) const;
void* GetMipData(int32 InMipIndex);
};
static bool IsNoSafeName(const FString& str);
static FString GetSafeNewName(const FString& str);
static FString MakeName(const FString& str, bool IsJoint = false);
static FName GetSanitizedName(const FString& str);
static int32 GetDirectChildBones(FReferenceSkeleton& refs, int32 ParentBoneIndex, TArray<int32>& Children);
static class UVrmAssetListObject* GetAssetListObjectAny(const UObject* obj);
static class UVrmAssetListObject* GetAssetListObject(const USkeletalMesh *);
static void CloseEditorWindowByFolderPath(const UObject* obj);
static int GetChildBone(const USkeleton* skeleton, const int32 ParentBoneIndex, bool recursive, TArray<int32>& Children);
static int GetChildBone(const USkeleton* skeleton, const int32 ParentBoneIndex, TArray<int32>& Children) {
return GetChildBone(skeleton, ParentBoneIndex, true, Children);
}
};
class VRM4U_API VRMRetargetData {
public:
struct RetargetParts {
FString BoneUE4;
FString BoneVRM;
FString BoneModel;
FRotator rot;
bool operator==(const RetargetParts& a) const{
return BoneUE4.Compare(a.BoneUE4, ESearchCase::IgnoreCase) == 0;
}
};
class UVrmAssetListObject* vrmAssetList = nullptr;
TArray<RetargetParts> retargetTable;
void Setup(class UVrmAssetListObject* vrmAssetList, bool bVRM, bool bBVH, bool bPMX);
void UpdateBoneName();
void Remove(FString BoneUE4);
};
+149
View File
@@ -0,0 +1,149 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
using UnrealBuildTool;
using System.IO;
public class VRM4U : ModuleRules
{
private string ModulePath
{
get { return ModuleDirectory; }
}
private string ThirdPartyPath
{
get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); }
}
public VRM4U(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
//"VRM4U/Public",
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
//"VRM4U/Private",
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"RHI",
"RenderCore",
"AnimGraphRuntime",
"LiveLinkInterface",
"CinematicCamera",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Slate",
"SlateCore",
"Engine",
"AssetRegistry",
"InputCore",
"ControlRig",
"AnimationCore",
// ... add private dependencies that you statically link with here ...
}
);
if (Target.bBuildEditor)
{
PrivateDependencyModuleNames.Add("UnrealEd");
PrivateDependencyModuleNames.Add("LevelEditor");
PrivateDependencyModuleNames.Add("LevelSequence");
PrivateDependencyModuleNames.Add("LevelSequenceEditor");
PrivateDependencyModuleNames.Add("Sequencer");
BuildVersion Version2;
if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version2))
{
if (Version2.MajorVersion == 5)
{
PrivateDependencyModuleNames.Add("MovieRenderPipelineEditor");
PrivateDependencyModuleNames.Add("ControlRigDeveloper");
}
}
}
{
BuildVersion Version2;
if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version2))
{
if (Version2.MajorVersion == 5)
{
PrivateDependencyModuleNames.Add("MovieRenderPipelineCore");
}
}
}
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
}
);
BuildVersion Version;
if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version))
{
//if (Version.MajorVersion == X && Version.MinorVersion == Y)
if (Version.MajorVersion == 5)
{
PrivateDependencyModuleNames.Add("RigVM");
PrivateDependencyModuleNames.Add("IKRig");
if (Target.bBuildEditor)
{
PrivateDependencyModuleNames.Add("IKRigEditor");
}
PrivateDependencyModuleNames.Add("InterchangeCore");
}
}
//(Target.Version.MinorVersion >= 25)
// warning: crash without OculusVR Plugin
bool bUseQuestTracking = false;
if (bUseQuestTracking)
{
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PrivateDependencyModuleNames.AddRange(new string[] {
"OculusHMD",
"OVRPlugin",
});
PublicDelayLoadDLLs.Add("OVRPlugin.dll");
RuntimeDependencies.Add("$(EngineDir)/Binaries/ThirdParty/Oculus/OVRPlugin/OVRPlugin/" + Target.Platform.ToString() + "/OVRPlugin.dll");
PublicDefinitions.Add("WITH_VRM4U_HMD_TRACKER=1");
}
else
{
PublicDefinitions.Add("WITH_VRM4U_HMD_TRACKER=0");
}
}
else {
PublicDefinitions.Add("WITH_VRM4U_HMD_TRACKER=0");
}
}
}
@@ -0,0 +1,317 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimNode_VrmVMC.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Engine/Engine.h"
#include "DrawDebugHelpers.h"
#include "VRM4U_VMCSubsystem.h"
#include "VrmAssetListObject.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
#include <algorithm>
/////////////////////////////////////////////////////
// FAnimNode_ModifyBone
FAnimNode_VrmVMC::FAnimNode_VrmVMC()
{
}
FAnimNode_VrmVMC::~FAnimNode_VrmVMC()
{
}
//void FAnimNode_VrmVMC::Update_AnyThread(const FAnimationUpdateContext& Context) {
// Super::Update_AnyThread(Context);
// //Context.GetDeltaTime();
//}
void FAnimNode_VrmVMC::Initialize_AnyThread(const FAnimationInitializeContext& Context) {
Super::Initialize_AnyThread(Context);
VrmMetaObject_Internal = const_cast<UVrmMetaObject*>(VrmMetaObject);
if (VrmMetaObject_Internal == nullptr && EnableAutoSearchMetaData) {
VrmAssetListObject_Internal = VRMUtil::GetAssetListObject(VRMGetSkinnedAsset(Context.AnimInstanceProxy->GetSkelMeshComponent()));
if (VrmAssetListObject_Internal) {
VrmMetaObject_Internal = VrmAssetListObject_Internal->VrmMetaObject;
}
}
UVRM4U_VMCSubsystem* subsystem = GEngine->GetEngineSubsystem<UVRM4U_VMCSubsystem>();
if (subsystem == nullptr) return;
{
auto *s = subsystem->FindOrAddServer(ServerAddress, Port);
if (s) {
s->bForceUpdate = bForceUpdate;
}
}
bCreateServer = true;
// init global reftransform
{
const auto Skeleton = Context.AnimInstanceProxy->GetSkeleton();
const auto RefSkeleton = Skeleton->GetReferenceSkeleton();
const auto& RefSkeletonTransform = RefSkeleton.GetRefBonePose();
RefSkeletonTransform_global = RefSkeletonTransform;
{
auto& g = RefSkeletonTransform_global;
for (int i = 0; i < RefSkeletonTransform.Num(); ++i) {
int parent = RefSkeleton.GetParentIndex(i);
if (parent < 0) continue;
g[i] = g[i] * g[parent];
}
}
}
}
void FAnimNode_VrmVMC::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {
Super::CacheBones_AnyThread(Context);
}
void FAnimNode_VrmVMC::UpdateInternal(const FAnimationUpdateContext& Context){
Super::UpdateInternal(Context);
}
void FAnimNode_VrmVMC::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneToModify.BoneName.ToString());
//DebugLine += FString::Printf(TEXT(" Target: %s)"), *BoneNameToModify.ToString());
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_VrmVMC::EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) {
Super::EvaluateComponentPose_AnyThread(Output);
}
void FAnimNode_VrmVMC::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
if (VrmMetaObject_Internal == nullptr) {
return;
}
UVRM4U_VMCSubsystem* subsystem = GEngine->GetEngineSubsystem<UVRM4U_VMCSubsystem>();
if (subsystem == nullptr) return;
const auto Skeleton = Output.AnimInstanceProxy->GetSkeleton();
const auto RefSkeleton = Output.AnimInstanceProxy->GetSkeleton()->GetReferenceSkeleton();
const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform();
const auto& RefSkeletonTransform = RefSkeleton.GetRefBonePose();
if (RefSkeletonTransform_global.Num() != RefSkeletonTransform.Num()) {
return;
}
TArray<int> boneIndexTable;
TArray<FBoneTransform> tmpOutTransform;
FVMCData VMCData;
if (subsystem->CopyVMCData(VMCData, ServerAddress, Port) == false) {
return;
}
if (VMCData.BoneData.Num() == 0 && VMCData.CurveData.Num() == 0) {
return;
}
if (bApplyPerfectSync) {
for (auto& c : VMCData.CurveData) {
if (c.Key.Contains(TEXT("BlendShape.")) == false) continue;
c.Key.RightChopInline(11); // [blendahape.]
}
}
TMap<FString, FTransform>& BoneTrans = VMCData.BoneData;
const auto &MorphList = Output.AnimInstanceProxy->GetSkelMeshComponent()->GetSkinnedAsset()->GetMorphTargets();
for (auto& c : VMCData.CurveData) {
#if UE_VERSION_OLDER_THAN(5,3,0)
{
SmartName::UID_Type NewUID;
FName NewName = *c.Key;
NewUID = Skeleton->GetUIDByName(USkeleton::AnimCurveMappingName, NewName);
Output.Curve.Set(NewUID, c.Value);
}
#else
auto m = MorphList.FindByPredicate([&c](const TObjectPtr<UMorphTarget> &m) {
FString s = c.Key;
if (m->GetName().Compare(s, ESearchCase::IgnoreCase)) {
return false;
}
return true;
});
if (m) {
Output.Curve.Set(*m->GetName(), c.Value);
} else {
Output.Curve.Set(*c.Key, c.Value);
}
#endif
}
{
bool bFirstBone = true;
for (const auto &t : VrmMetaObject_Internal->humanoidBoneTable) {
#if UE_VERSION_OLDER_THAN(4,27,0)
auto *tmpVal = BoneTrans.Find(t.Key.ToLower());
if (tmpVal == nullptr) continue;
auto modelBone = *tmpVal;
#else
auto filterList= BoneTrans.FilterByPredicate([&t](TPair<FString, FTransform> a) {
return a.Key.Compare(t.Key, ESearchCase::IgnoreCase) == 0;
}
);
if (filterList.Num() != 1) continue;
auto modelBone = filterList.begin()->Value;
#endif
int index = RefSkeleton.FindBoneIndex(*t.Value);
if (index < 0) continue;
FBoneTransform f(FCompactPoseBoneIndex(index), modelBone);
//f.Transform.SetRotation(FQuat::Identity);
if (bFirstBone) {
bFirstBone = false;
if (bUseRemoteCenterPos) {
auto v = f.Transform.GetLocation() * ModelRelativeScale;
f.Transform.SetTranslation(v);
} else {
auto v = RefSkeletonTransform[index].GetLocation();
f.Transform.SetTranslation(v);
}
// root bone
FTransform RootTrans;
for (auto& a : BoneTrans) {
if (a.Key.Compare(TEXT("root"), ESearchCase::IgnoreCase)) {
continue;
}
RootTrans = a.Value;
break;
}
if (index == 0) {
// hip == root
f.Transform.SetTranslation(f.Transform.GetLocation() + RootTrans.GetLocation());
} else {
// orig root
FBoneTransform bt(FCompactPoseBoneIndex(0), RootTrans);
tmpOutTransform.Add(bt);
boneIndexTable.Add(0);
}
} else {
FVector v = RefSkeletonTransform[index].GetLocation();
f.Transform.SetTranslation(v);
}
if (bIgnoreLocalRotation){
auto r_refg = RefSkeletonTransform_global[index].GetRotation();
auto r_ref = RefSkeletonTransform[index].GetRotation();
auto r_vmc = f.Transform.GetRotation();
auto r_dif = r_refg.Inverse() * r_vmc * r_refg;
f.Transform.SetRotation(r_ref * r_dif);
}
//f.Transform.SetTranslation(RefSkeletonTransform[index].GetLocation());
tmpOutTransform.Add(f);
boneIndexTable.Add(index);
}
// bone hierarchy
for (int i = 1; i < tmpOutTransform.Num(); ++i) {
int parentBoneIndex = RefSkeleton.GetParentIndex(boneIndexTable[i]);
int parentInTable = boneIndexTable.Find(parentBoneIndex);
for (int j = 0; j < 1000; ++j) {
if (parentInTable >= 0) {
break;
}
if (parentBoneIndex < 0) break;
// add outtransform with ref bone
FBoneTransform f(FCompactPoseBoneIndex(parentBoneIndex), RefSkeletonTransform[parentBoneIndex]);
tmpOutTransform.Add(f);
boneIndexTable.Add(parentBoneIndex);
parentBoneIndex = RefSkeleton.GetParentIndex(parentBoneIndex);
parentInTable = boneIndexTable.Find(parentBoneIndex);
}
}
// sort
tmpOutTransform.Sort(FCompareBoneTransformIndex());
boneIndexTable.Sort();
}
for (int i = 0; i < tmpOutTransform.Num(); ++i) {
auto& a = tmpOutTransform[i];
int parentBoneIndex = RefSkeleton.GetParentIndex(boneIndexTable[i]);
int parentInHandTable = boneIndexTable.Find(parentBoneIndex);
if (parentInHandTable >= 0) {
a.Transform *= tmpOutTransform[parentInHandTable].Transform;
} else {
// root
auto BoneSpace = EBoneControlSpace::BCS_ParentBoneSpace;
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, a.Transform, a.BoneIndex, BoneSpace);
}
OutBoneTransforms.Add(a);
}
}
bool FAnimNode_VrmVMC::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// if both bones are valid
//return (BoneToModify.IsValidToEvaluate(RequiredBones));
return true;
}
void FAnimNode_VrmVMC::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
//BoneToModify.Initialize(RequiredBones);
}
void FAnimNode_VrmVMC::ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground) const
{
#if WITH_EDITOR
if (VrmMetaObject_Internal == nullptr || PreviewSkelMeshComp == nullptr) {
return;
}
if (PreviewSkelMeshComp->GetWorld() == nullptr) {
return;
}
ESceneDepthPriorityGroup Priority = SDPG_World;
if (bPreviewForeground) Priority = SDPG_Foreground;
#endif
}
@@ -0,0 +1,34 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VRM4UCapture.h"
#include "CoreMinimal.h"
#include "VRM4UCaptureLog.h"
#include "Modules/ModuleManager.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE "VRM4UMisc"
DEFINE_LOG_CATEGORY(LogVRM4UCapture);
//////////////////////////////////////////////////////////////////////////
// FSpriterImporterModule
class FVRM4UCaptureModule : public FDefaultModuleImpl
{
public:
virtual void StartupModule() override
{
}
virtual void ShutdownModule() override
{
}
};
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_MODULE(FVRM4UCaptureModule, VRM4UCapture);
//////////////////////////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,8 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
//#include "VRMImporterModule.h"
@@ -0,0 +1,14 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
//#include "VRMImporterModule.h"
DECLARE_LOG_CATEGORY_EXTERN(LogVRM4UCapture, Verbose, All);
//#define SPRITER_IMPORT_ERROR(FormatString, ...) \
// if (!bSilent) { UE_LOG(LogVRM4UMIsc, Warning, FormatString, __VA_ARGS__); }
//#define SPRITER_IMPORT_WARNING(FormatString, ...) \
// if (!bSilent) { UE_LOG(LogVRM4UMIsc, Warning, FormatString, __VA_ARGS__); }
@@ -0,0 +1,113 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "VRM4U_VMCSubsystem.h"
#include "VrmVMCObject.h"
#include "Engine/Engine.h"
#include "UObject/StrongObjectPtr.h"
#include "Misc/ScopeLock.h"
#include "OSCManager.h"
#include "OSCServer.h"
bool UVRM4U_VMCSubsystem::CopyVMCData(FVMCData &data, FString ServerAddress, int port) {
for (int i = 0; i < VMCObjectList.Num(); ++i) {
auto a = VMCObjectList[i].Get();
if (a == nullptr) continue;
if (a->ServerName == ServerAddress && a->port == port) {
a->CopyVMCData(data);
return true;
}
}
return false;
}
bool UVRM4U_VMCSubsystem::GetVMCData(TMap<FString, FTransform>& BoneData, TMap<FString, float>& CurveData, FString ServerAddress, int port) {
FVMCData d;
if (CopyVMCData(d, ServerAddress, port) == false) {
return false;
}
BoneData = d.BoneData;
CurveData = d.CurveData;
return true;
}
UVrmVMCObject* UVRM4U_VMCSubsystem::FindOrAddServer(const FString ServerAddress, int port) {
bool bFound = false;
for (int i = 0; i < VMCObjectList.Num(); ++i) {
auto a = VMCObjectList[i].Get();
if (a == nullptr) continue;
if (a->ServerName == ServerAddress && a->port == port) {
bFound = true;
return a;
}
}
if (bFound == false) {
int ind = VMCObjectList.AddDefaulted();
VMCObjectList[ind].Reset(NewObject<UVrmVMCObject>());
VMCObjectList[ind]->CreateServer(ServerAddress, port);
return VMCObjectList[ind].Get();
}
return nullptr;
}
void UVRM4U_VMCSubsystem::DestroyVMCServer(const FString ServerAddress, int port) {
for (int i = 0; i < VMCObjectList.Num(); ++i) {
auto a = VMCObjectList[i].Get();
if (a == nullptr) continue;
if (a->ServerName == ServerAddress && a->port == port) {
a->DestroyServer();
VMCObjectList[i].Reset(nullptr);
VMCObjectList.RemoveAt(i);
return;
}
}
}
void UVRM4U_VMCSubsystem::DestroyVMCServerAll() {
while (VMCObjectList.Num()) {
auto a = VMCObjectList[0].Get();
if (a) {
a->DestroyServer();
}
VMCObjectList[0].Reset(nullptr);
VMCObjectList.RemoveAt(0);
}
}
bool UVRM4U_VMCSubsystem::CreateVMCServer(const FString ServerAddress, int port) {
return (FindOrAddServer(ServerAddress, port) != nullptr);
}
void UVRM4U_VMCSubsystem::ClearData(const FString ServerAddress, int port) {
for (int i = 0; i < VMCObjectList.Num(); ++i) {
auto a = VMCObjectList[i].Get();
if (a == nullptr) continue;
if (a->ServerName == ServerAddress && a->port == port) {
VMCObjectList[i]->ClearVMCData();
return;
}
}
}
void UVRM4U_VMCSubsystem::Initialize(FSubsystemCollectionBase& Collection) {
Super::Initialize(Collection);
#if WITH_EDITOR
FEditorDelegates::BeginStandaloneLocalPlay.AddLambda([&](const uint32 processID) {
this->DestroyVMCServerAll();
});
#endif
}
@@ -0,0 +1,64 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmCaptureManager.h"
#include "VrmMocopiReceiver.h"
#include "VRM4UCaptureLog.h"
UVrmMocopiReceiver* UVrmCaptureManager::CreateVrmMocopiReceiver(FString InReceiveIPAddress, int32 InPort, bool bInMulticastLoopback, bool bInStartListening, FString ServerName, UObject* Outer)
{
{
FString InAddress = InReceiveIPAddress;
if (!InAddress.IsEmpty() && InAddress != TEXT("0"))
{
}
bool bCanBind = false;
bool bAppendPort = false;
if (ISocketSubsystem* SocketSys = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM))
{
const TSharedPtr<FInternetAddr> Addr = SocketSys->GetLocalHostAddr(*GLog, bCanBind);
if (Addr.IsValid())
{
InAddress = Addr->ToString(bAppendPort);
}
}
UE_LOG(LogVRM4UCapture, Display, TEXT("MocopiReceiver ReceiveAddress not specified. Using LocalHost IP: '%s'"), *InAddress);
}
if (ServerName.IsEmpty())
{
ServerName = FString::Printf(TEXT("MocopiReceiver_%s"), *FGuid::NewGuid().ToString(EGuidFormats::Digits));
}
UVrmMocopiReceiver* NewMocopiServer = nullptr;
if (Outer)
{
NewMocopiServer = NewObject<UVrmMocopiReceiver>(Outer, *ServerName, RF_StrongRefOnFrame);
}
else
{
UE_LOG(LogVRM4UCapture, Warning, TEXT("Outer object not set. MocopiReceiver may be garbage collected if not referenced."));
NewMocopiServer = NewObject<UVrmMocopiReceiver>(GetTransientPackage(), *ServerName);
}
if (NewMocopiServer)
{
//NewMocopiServer->SetMulticastLoopback(bInMulticastLoopback);
if (NewMocopiServer->SetAddress(InReceiveIPAddress, InPort))
{
if (bInStartListening)
{
NewMocopiServer->Listen();
}
}
else
{
UE_LOG(LogVRM4UCapture, Warning, TEXT("Failed to parse ReceiveAddress '%s' for MocopiReceiver."), *InReceiveIPAddress);
}
return NewMocopiServer;
}
return nullptr;
}
@@ -0,0 +1,563 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmMocopiReceiver.h"
#include "VRM4UCaptureLog.h"
#include "CoreGlobals.h"
#include "Stats/Stats.h"
#include "Tickable.h"
#include "Common/UdpSocketReceiver.h"
//
//
FMocopiReceiverProxy::FMocopiReceiverProxy(UVrmMocopiReceiver * InReceiver):
Receiver(InReceiver){
FIPv4Address::Parse("0.0.0.0", ReceiveIPAddress);
}
FMocopiReceiverProxy::~FMocopiReceiverProxy() {
Stop();
}
void FMocopiReceiverProxy::Stop() {
if (SocketReceiver) {
delete SocketReceiver;
SocketReceiver = nullptr;
}
if (Socket) {
Socket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(Socket);
Socket = nullptr;
}
}
void FMocopiReceiverProxy::Listen() {
FString InServerName = "udp_serv";
//int32 Port = 12351;
bool bMulticastLoopback = true;
FUdpSocketBuilder Builder(*InServerName);
Builder.BoundToPort(Port);
if (ReceiveIPAddress.IsMulticastAddress())
{
Builder.JoinedToGroup(ReceiveIPAddress);
if (bMulticastLoopback)
{
Builder.WithMulticastLoopback();
}
}
else
{
if (bMulticastLoopback)
{
//UE_LOG(LogOSC, Warning, TEXT("OSCServer '%s' ReceiveIPAddress provided is not a multicast address. Not respecting MulticastLoopback boolean."),
// *InServerName);
}
Builder.BoundToAddress(ReceiveIPAddress);
}
Socket = Builder.Build();
if (Socket)
{
SocketReceiver = new FUdpSocketReceiver(Socket, FTimespan::FromMilliseconds(100), *(InServerName + TEXT("_ListenerThread")));
SocketReceiver->OnDataReceived().BindRaw(this, &FMocopiReceiverProxy::OnPacketReceived);
SocketReceiver->Start();
//UE_LOG(LogOSC, Display, TEXT("OSCServer '%s' Listening: %s:%d."), *InServerName, *ReceiveIPAddress.ToString(), Port);
}
else
{
// This is expected when the server isn't available, so it's not a Warning
//UE_LOG(LogOSC, Display, TEXT("OSCServer '%s' failed to bind to socket on %s:%d. Check that the server is available on the specified address."), *InServerName, *ReceiveIPAddress.ToString(), Port);
}
}
bool FMocopiReceiverProxy::SetAddress(const FString& InReceiveIPAddress, int32 InPort) {
if (!FIPv4Address::Parse(InReceiveIPAddress, ReceiveIPAddress))
{
//UE_LOG(LogOSC, Error, TEXT("Invalid ReceiveIPAddress '%s'. OSCServer ReceiveIP Address not updated."), *InReceiveIPAddress);
return false;
}
Port = InPort;
return true;
}
void FMocopiReceiverProxy::Tick(float InDeltaTime) {
}
TStatId FMocopiReceiverProxy::GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FMocopiReceiverProxy, STATGROUP_Tickables);
}
void FMocopiReceiverProxy::OnPacketReceived(const FArrayReaderPtr& InData, const FIPv4Endpoint& InEndpoint) {
RecvDataSet.Append(InData->GetData(), InData->Num());
// data size limit
if (RecvDataSet.Num() >= 1024 * 64) {
decltype(RecvDataSet) a;
a.Append(RecvDataSet.GetData() + 1024*48, RecvDataSet.Num() - 1024*48);
RecvDataSet = a;
}
//UE_LOG(LogVRM4UCapture, Verbose, TEXT("recv '%d' "), InData->Num());
struct LocalStructRawData {
TArray<float> f;
FQuat rot;
FVector pos;
LocalStructRawData() {
f.SetNum(7);
}
};
struct LocalStructTransData {
//TArray<LocalStructRawData> data;
TArray<FTransform> transformLocal;
TArray <FTransform> transformWorld;
TArray <FTransform> transformVrmLocal;
TArray <FTransform> transformBvhLocal;
LocalStructTransData() {
transformWorld.SetNum(MocopiData::BoneNum);
transformLocal.SetNum(MocopiData::BoneNum);
transformVrmLocal.SetNum(MocopiData::BoneNum);
transformBvhLocal.SetNum(MocopiData::BoneNum);
//data.SetNum(MocopiData::BoneNum);
}
};
LocalStructTransData d;
const char FIELD_HEAD[] = {
'h', 'e', 'a', 'd',
};
const char FIELD_SKDF[] = {
's', 'k', 'd', 'f',
};
const char FIELD_BTRS[] = {
'b', 't', 'r', 's',
};
const char FIELD_TRAN[] = {
't', 'r', 'a', 'n',
};
const char FIELD_BNID[] = {
'b', 'n', 'i', 'd',
};
const char FIELD_FRAM[] = {
'f', 'r', 'a', 'm',
};
const char FIELD_FNUM[] = {
'f', 'n', 'u', 'm',
};
const char FIELD_TIME[] = {
't', 'i', 'm', 'e',
};
const int BoneChain[] = {
0, // 0
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
7, // 11
11, 12, 13,
7, // 15
15, 16, 17,
0, //19
19, 20, 21,
0, //23
23, 24, 25,
};
auto GetValue = [&](uint8*& pData, uint32_t &length, int cur, const char field[4]) {
if (cur < 4) {
return false;
}
{
int t = 0;
for (t = 0; t < 4; ++t) {
if (field[t] != RecvDataSet.GetData()[cur + t]) {
break;
}
}
if (t == 4) {
pData = (RecvDataSet.GetData() + cur + 4);
length = *reinterpret_cast<uint32*>((RecvDataSet.GetData() + cur - 4));
return true;
}
}
pData = nullptr;
length = 0;
return false;
};
/*
for (int i = RecvDataSet.Num() - 4; i >= 8; --i) {
if (isalpha(RecvDataSet.GetData()[i]) == false) {
continue;
}
uint32 length = 0;
uint8* p = nullptr;
if (GetValue(p, length, i, FIELD_FRAM)){
// p == value
// p-4 == field
// p-8 == packetsize
//
// i == field
// i-4 == packetsize
uint16* packetSize = reinterpret_cast<uint16*>(p - 8);
//UE_LOG(LogVRM4UCapture, Verbose, TEXT("packetSize '%d'"), (*packetSize));
if ((*packetSize) + 8 <= RecvDataSet.Num()) {
//UE_LOG(LogVRM4UCapture, Verbose, TEXT("shrink '%d' -> %d "), RecvDataSet.Num(), (*packetSize) + 8);
decltype(RecvDataSet) a;
a.Append(RecvDataSet.GetData() + i - 4, (*packetSize) + 8);
RecvDataSet = a;
}
}
}*/
bool bUpdateData = false;
for (int packetNo = 0; packetNo < 10; ++packetNo) {
int32 frame = -1;
int32 time = -1;
{
bool bFindFieldSkdf = false;
bool bFindFieldBtrs = false;
bool bFindFieldFram = false;
float* TransformData = nullptr;
uint16* boneid = nullptr;
int i = 0;
for (i = 0; i < RecvDataSet.Num() - 4; ++i) {
if (isalpha(RecvDataSet.GetData()[i]) == false) {
continue;
}
uint32 length = 0;
uint8* p = nullptr;
if (GetValue(p, length, i, FIELD_SKDF)) {
//UE_LOG(LogVRM4UCapture, Verbose, TEXT("skdf %d"), bFindFieldFram);
bFindFieldSkdf = true;
// remove read data
FMemory::Memmove(RecvDataSet.GetData(), RecvDataSet.GetData() + (i+4), RecvDataSet.Num() - (i+4));
RecvDataSet.SetNum(RecvDataSet.Num() - (i+4));
break;
}
if (bFindFieldFram == false) {
if (GetValue(p, length, i, FIELD_FRAM)) {
bFindFieldFram = true;
}
continue;
}
/*
{
int t = 0;
for (t = 0; t < 4; ++t) {
if (isalpha((RecvDataSet.GetData()[i + t])) == false) {
break;
}
}
if (t == 4) {
UE_LOG(LogVRM4UCapture, Verbose, TEXT("recv '%c%c%c%c' "),
*((char*)(RecvDataSet.GetData()) + i),
*((char*)(RecvDataSet.GetData()) + i+1),
*((char*)(RecvDataSet.GetData()) + i+2),
*((char*)(RecvDataSet.GetData()) + i+3)
);
}
}
*/
if (GetValue(p, length, i, FIELD_FNUM)) {
frame = *reinterpret_cast<int32*>(p);
}
if (GetValue(p, length, i, FIELD_TIME)) {
time = *reinterpret_cast<int32*>(p);
}
if (frame < 0) continue;
if (bFindFieldBtrs == false) {
if (GetValue(p, length, i, FIELD_BTRS)) {
bFindFieldBtrs = true;
}
continue;
}
if (GetValue(p, length, i, FIELD_BNID)) {
boneid = reinterpret_cast<uint16*>(p);
}
if (GetValue(p, length, i, FIELD_TRAN)) {
TransformData = reinterpret_cast<float*>(p);
}
if (boneid && TransformData) {
// mocopi
{
LocalStructRawData st;
st.rot = FQuat(-TransformData[0], -TransformData[1], TransformData[2], TransformData[3]);
if (*boneid == 0) {
st.rot = FRotator(0, 0, -90).Quaternion() * st.rot;
}
st.pos.Set(TransformData[4], TransformData[5], -TransformData[6]);
st.pos *= 100.f;
d.transformLocal[*boneid] = FTransform(st.rot, st.pos);
}
// vrm
{
LocalStructRawData st;
d.transformVrmLocal[*boneid] = FTransform(st.rot, st.pos);
st.rot = FQuat(-TransformData[0], -TransformData[1], TransformData[2], TransformData[3]);
st.rot = FRotator(0, 0, -90).Quaternion() * st.rot * FRotator(0, 0, -90).Quaternion().Inverse();
st.pos.Set(TransformData[4], TransformData[6], TransformData[5]);
st.pos *= 100.f;
d.transformVrmLocal[*boneid] = FTransform(st.rot, st.pos);
}
if (*boneid == MocopiData::BoneNum-1) {
// remove read data
FMemory::Memmove(RecvDataSet.GetData(), RecvDataSet.GetData() + i, RecvDataSet.Num() - i);
RecvDataSet.SetNum(RecvDataSet.Num() - i);
break;
}
boneid = nullptr;
TransformData = nullptr;
}
}// data loop
if (bFindFieldSkdf) {
continue;
}
if (bFindFieldFram == false) {
break;
}
} // packet loop
// no packet
if (d.transformLocal.Num() != MocopiData::BoneNum) break;
d.transformWorld = d.transformLocal;
{
auto v = d.transformWorld[0].GetLocation();
d.transformWorld[0].SetLocation(FVector(v.X, v.Z, v.Y));
}
for (int i = 1; i < MocopiData::BoneNum; ++i) {
int parent = BoneChain[i];
auto r1 = d.transformWorld[parent].GetRotation();
auto p1 = d.transformWorld[parent].GetLocation();
FTransform::Multiply(&d.transformWorld[i], &d.transformLocal[i], &d.transformWorld[parent]);
}
FStructMocopiData md;
if (frame>=0 && time>=0) {
md.FrameNo = frame;
md.Time = time;
}
md.MocopiTransformWorld = d.transformWorld;
md.MocopiTransformLocal = d.transformLocal;
md.VrmTransformLocal = d.transformVrmLocal;
{
TMap<FString, int> BoneIdList = {
{"hips", 0},
{"leftUpperLeg", 19},
{"rightUpperLeg", 23},
{"leftLowerLeg", 20},
{"rightLowerLeg", 24},
{"leftFoot", 21},
{"rightFoot", 25},
{"spine", 3}, //
{"chest", 6}, //
{"upperChest", 7}, //
{"neck", 8}, //
{"head", 9},
{"leftShoulder", 11},
{"rightShoulder", 15},
{"leftUpperArm", 12},
{"rightUpperArm", 16},
{"leftLowerArm", 13},
{"rightLowerArm", 17},
{"leftHand", 14},
{"rightHand", 18},
{"leftToes", 22},
{"rightToes", 26},
};
for (auto& b : BoneIdList) {
md.VrmTransformBoneList.Add(b.Key, d.transformVrmLocal[b.Value]);
}
}
if (Receiver) {
Receiver->OnPacketReceived(md);
bUpdateData = true;
}
}// packet loop
if (bUpdateData && Receiver) {
Receiver->PacketBroadcast();
}
#ifdef PLATFORM_LITTLE_ENDIAN
#endif
}
//
UVrmMocopiReceiver::UVrmMocopiReceiver(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer), ReceiverProxy(MakeUnique<FMocopiReceiverProxy>(this))
{
MocopiReceiveBuffer.Reserve(BufferNum);
}
void UVrmMocopiReceiver::BeginDestroy() {
Stop();
Super::BeginDestroy();
}
bool UVrmMocopiReceiver::SetAddress(const FString& InReceiveIPAddress, int32 InPort) {
return ReceiverProxy->SetAddress(InReceiveIPAddress, InPort);
}
void UVrmMocopiReceiver::Stop() {
if (ReceiverProxy) {
ReceiverProxy->Stop();
}
}
void UVrmMocopiReceiver::Listen() {
ReceiverProxy->Listen();
}
void UVrmMocopiReceiver::SetBufferNum(int32 Num) {
FScopeLock ScopeLock(&BufferCS);
Num = FMath::Max(Num, 1);
BufferNum = Num;
MocopiReceiveBuffer.Reserve(BufferNum);
}
void UVrmMocopiReceiver::GetNextFrameData(FStructMocopiData &data, bool &bEnable, bool &bUpdate){
bEnable = false;
bUpdate = false;
FScopeLock ScopeLock(&BufferCS);
if (MocopiReceiveBuffer.Num() <= 0) {
return;
}
if (bEnable == false) {
for (int i = MocopiReceiveBuffer.Num() - 2; i >= 0; --i) {
if (MocopiReceiveBuffer[i].FrameNo == currentFrameNo) {
data = MocopiReceiveBuffer[i + 1];
bEnable = true;
break;
}
}
if (bEnable == false) {
data = MocopiReceiveBuffer.Last();
}
}
if (data.FrameNo != currentFrameNo) {
bUpdate = true;
}
currentFrameNo = data.FrameNo;
currentTime = data.Time;
bEnable = true;
}
void UVrmMocopiReceiver::GetLatestFrameData(FStructMocopiData &data, bool &bEnable, bool &bUpdate){
bEnable = false;
bUpdate = false;
FScopeLock ScopeLock(&BufferCS);
if (MocopiReceiveBuffer.Num() <= 0) {
return;
}
data = MocopiReceiveBuffer.Last();
if (data.FrameNo != currentFrameNo) {
bUpdate = true;
}
currentFrameNo = data.FrameNo;
currentTime = data.Time;
bEnable = true;
}
void UVrmMocopiReceiver::PacketBroadcast() {
FScopeLock ScopeLock(&BufferCS);
OnReceived.Broadcast(MocopiReceiveBuffer.Last());
}
void UVrmMocopiReceiver::OnPacketReceived(FStructMocopiData data) {
FScopeLock ScopeLock(&BufferCS);
while (MocopiReceiveBuffer.Num() >= BufferNum - 1) {
if (MocopiReceiveBuffer.Num() == 0) {
break;
}
#if UE_VERSION_OLDER_THAN(4,26,0)
MocopiReceiveBuffer.RemoveAt(0);
#else
MocopiReceiveBuffer.PopFront();
#endif
}
MocopiReceiveBuffer.Add(data);
}
@@ -0,0 +1,106 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "VrmVMCObject.h"
#include "VRM4U_VMCSubsystem.h"
#include "Engine/Engine.h"
#include "UObject/StrongObjectPtr.h"
#include "Misc/ScopeLock.h"
#include "OSCManager.h"
#include "OSCServer.h"
void UVrmVMCObject::DestroyServer() {
ServerName = "";
port = 0;
if (OSCServer.Get()) {
OSCServer->Stop();
}
OSCServer.Reset(nullptr);
}
void UVrmVMCObject::CreateServer(FString inName, uint16 inPort) {
ServerName = inName;
port = inPort;
#if UE_VERSION_OLDER_THAN(4,25,0)
#else
OSCServer.Reset(UOSCManager::CreateOSCServer(ServerName, port, true, true, FString(), this));
OSCServer->OnOscMessageReceivedNative.RemoveAll(nullptr);
OSCServer->OnOscMessageReceivedNative.AddUObject(this, &UVrmVMCObject::OSCReceivedMessageEvent);
#if WITH_EDITOR
OSCServer->SetTickInEditor(true);
#endif // WITH_EDITOR
#endif
}
void UVrmVMCObject::OSCReceivedMessageEvent(const FOSCMessage& Message, const FString& IPAddress, uint16 Port) {
FOSCAddress a = UOSCManager::GetOSCMessageAddress(Message);
FString addressPath = UOSCManager::GetOSCAddressFullPath(a);
TArray<FString> str;
UOSCManager::GetAllStrings(Message, str);
TArray<float> curve;
UOSCManager::GetAllFloats(Message, curve);
FTransform t;
float f = 0;
if (curve.Num() == 1) {
f = curve[0];
}
if (curve.Num() >= 7) {
t.SetLocation(FVector(-curve[0], curve[2], curve[1]) * 100.f);
t.SetRotation(FQuat(-curve[3], curve[5], curve[4], curve[6]));
}
if (curve.Num() >= 10) {
t.SetScale3D(FVector(curve[7], curve[9], curve[8]));
}
if (addressPath == TEXT("/VMC/Ext/Root/Pos")) {
VMCData.BoneData.FindOrAdd(str[0]) = t;
bDataUpdated = true;
}
if (addressPath == TEXT("/VMC/Ext/Bone/Pos")) {
VMCData.BoneData.FindOrAdd(str[0]) = t;
bDataUpdated = true;
}
if (addressPath == TEXT("/VMC/Ext/Blend/Val")) {
VMCData.CurveData.FindOrAdd(str[0]) = f;
bDataUpdated = true;
}
if (bDataUpdated == true){
bool b = bForceUpdate;
if (addressPath == TEXT("/VMC/Ext/OK")) {
b = true;
}
if (addressPath == TEXT("/VMC/Ext/T")) {
b = true;
}
if (addressPath == TEXT("/VMC/Ext/Blend/Apply")) {
b = true;
}
if (b) {
FScopeLock lock(&cs);
VMCData_Cache = VMCData;
bDataUpdated = false;
}
}
}
bool UVrmVMCObject::CopyVMCData(FVMCData& dst) {
FScopeLock lock(&cs);
dst = VMCData_Cache;
return true;
}
void UVrmVMCObject::ClearVMCData() {
FScopeLock lock(&cs);
VMCData.ClearData();
VMCData_Cache.ClearData();
}
@@ -0,0 +1,92 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "BoneControllers/AnimNode_ModifyBone.h"
#include "Misc/EngineVersionComparison.h"
#include "AnimNode_VrmVMC.generated.h"
class USkeletalMeshComponent;
class UVrmMetaObject;
class UVrmAssetListObject;
/**
* Simple controller that replaces or adds to the translation/rotation of a single bone.
*/
USTRUCT(BlueprintInternalUseOnly)
struct VRM4UCAPTURE_API FAnimNode_VrmVMC : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool EnableAutoSearchMetaData = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta=(PinHiddenByDefault))
const UVrmMetaObject *VrmMetaObject = nullptr;
#if UE_VERSION_OLDER_THAN(5,0,0)
TAssetPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TAssetPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
#else
TSoftObjectPtr<UVrmMetaObject> VrmMetaObject_Internal = nullptr;
TSoftObjectPtr<UVrmAssetListObject> VrmAssetListObject_Internal = nullptr;
#endif
//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
//TMap<FString, FTransform> BoneTrans;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
bool bUseRemoteCenterPos = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
float ModelRelativeScale = 1.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
bool bIgnoreLocalRotation = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
FString ServerAddress = "0.0.0.0";
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
int Port = 39539;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinShownByDefault))
bool bApplyPerfectSync = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Skeleton, meta = (PinHiddenByDefault))
bool bForceUpdate = false;
bool bCreateServer = false;
TArray<FTransform> RefSkeletonTransform_global;
FAnimNode_VrmVMC();
virtual ~FAnimNode_VrmVMC();
// FAnimNode_Base interface
virtual void GatherDebugData(FNodeDebugData& DebugData) override;
// End of FAnimNode_Base interface
// FAnimNode_SkeletalControlBase interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
// virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms) override;
virtual void EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output) override;
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
virtual void UpdateInternal(const FAnimationUpdateContext& Context)override;
// End of FAnimNode_SkeletalControlBase interface
virtual void ConditionalDebugDraw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp, bool bPreviewForeground = false) const;
private:
// FAnimNode_SkeletalControlBase interface
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface
};
@@ -0,0 +1,55 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/EngineSubsystem.h"
#include "Misc/EngineVersionComparison.h"
#include "UObject/StrongObjectPtr.h"
#include "OSCServer.h"
#include "VrmVMCObject.h"
#include "VRM4U_VMCSubsystem.generated.h"
#if UE_VERSION_OLDER_THAN(4,22,0)
//Couldn't find parent type for 'VRM4U_AnimSubsystem' named 'UEngineSubsystem'
#error "please remove VRM4U_AnimSubsystem.h/cpp for <=UE4.21"
#endif
UCLASS()
class VRM4UCAPTURE_API UVRM4U_VMCSubsystem : public UEngineSubsystem
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = VRM4U)
bool CreateVMCServer(const FString ServerAddress, int port);
void ClearData(const FString ServerAddress, int port);
UFUNCTION(BlueprintCallable, Category = VRM4U)
void DestroyVMCServer(const FString ServerAddress, int port);
UFUNCTION(BlueprintCallable, Category = VRM4U)
void DestroyVMCServerAll();
UVrmVMCObject* FindOrAddServer(const FString ServerAddress, int port);
TArray< TStrongObjectPtr<UVrmVMCObject> > VMCObjectList;
bool CopyVMCData(FVMCData& DstData, FString ServerAddress, int port);
UFUNCTION(BlueprintCallable, Category = VRM4U)
bool GetVMCData(TMap<FString, FTransform> &BoneData, TMap<FString, float> &CurveData, FString ServerAddress, int port);
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
private:
};
@@ -0,0 +1,20 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "Engine/LatentActionManager.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "VrmCaptureManager.generated.h"
class UVrmMocopiReceiver;
UCLASS()
class VRM4UCAPTURE_API UVrmCaptureManager : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "VRM4U")
static UVrmMocopiReceiver* CreateVrmMocopiReceiver(FString ReceiveIPAddress, int32 Port, bool bMulticastLoopback, bool bStartListening, FString ServerName, UObject* Outer = nullptr);
};
@@ -0,0 +1,157 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "Misc/CoreDelegates.h"
#include "UObject/NoExportTypes.h"
#include "Interfaces/IPv4/IPv4Address.h"
#include "Interfaces/IPv4/IPv4Endpoint.h"
#include "Common/UdpSocketReceiver.h"
#include "Sockets.h"
#include "Common/UdpSocketBuilder.h"
#include "Misc/EngineVersionComparison.h"
#include "Tickable.h"
#if UE_VERSION_OLDER_THAN(4,26,0)
#else
#include "Containers/RingBuffer.h"
#endif
#include "VrmMocopiReceiver.generated.h"
/**
*
*/
enum MocopiData{
BoneNum = 27,
};
USTRUCT(BlueprintType)
struct FStructMocopiData{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
int FrameNo = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
int Time = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, EditFixedSize, Category = "VRM4U")
TArray<FTransform> MocopiTransformWorld;
UPROPERTY(EditAnywhere, BlueprintReadWrite, EditFixedSize, Category = "VRM4U")
TArray<FTransform> MocopiTransformLocal;
UPROPERTY(EditAnywhere, BlueprintReadWrite, EditFixedSize, Category = "VRM4U")
TArray<FTransform> VrmTransformLocal;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRM4U")
TMap<FString, FTransform> VrmTransformBoneList;
FStructMocopiData() {
MocopiTransformWorld.SetNum(MocopiData::BoneNum);
MocopiTransformLocal.SetNum(MocopiData::BoneNum);
VrmTransformLocal.SetNum(MocopiData::BoneNum);
}
};
class VRM4UCAPTURE_API FMocopiReceiverProxy : public FTickableGameObject
{
UVrmMocopiReceiver* Receiver;
FSocket* Socket = nullptr;
FUdpSocketReceiver* SocketReceiver = nullptr;
FIPv4Address ReceiveIPAddress;
int32 Port = 8888;
TArray<uint8> RecvDataSet;
public:
FMocopiReceiverProxy(UVrmMocopiReceiver *InReceiver);
//FMocopiReceiverProxy(UVrmMocopiReceiver& InServer);
virtual ~FMocopiReceiverProxy();
#if WITH_EDITOR
virtual bool IsTickableInEditor() const override {
return true;
}
#endif // WITH_EDITOR
void Listen();
void Stop();
bool SetAddress(const FString& ReceiveIPAddress, int32 Port);
virtual void Tick(float InDeltaTime) override;
virtual TStatId GetStatId() const override;
void OnPacketReceived(const FArrayReaderPtr& InData, const FIPv4Endpoint& InEndpoint);
};
UCLASS(BlueprintType)
class VRM4UCAPTURE_API UVrmMocopiReceiver : public UObject
{
GENERATED_UCLASS_BODY()
int BufferNum = 10;
int currentFrameNo = 0;
int currentTime = 0;
mutable FCriticalSection BufferCS;
TUniquePtr<FMocopiReceiverProxy> ReceiverProxy;
#if UE_VERSION_OLDER_THAN(4,26,0)
TArray<FStructMocopiData> MocopiReceiveBuffer;
#else
TRingBuffer<FStructMocopiData> MocopiReceiveBuffer;
#endif
public:
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void Listen();
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void Stop();
void OnPacketReceived(const FArrayReaderPtr& InData, const FIPv4Endpoint& InEndpoint);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
bool SetAddress(const FString& ReceiveIPAddress, int32 Port);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void SetBufferNum(int32 Num = 10);
void OnPacketReceived(FStructMocopiData data);
void PacketBroadcast();
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVrmMocopiReceiverDelegate, FStructMocopiData, data);
UPROPERTY(BlueprintAssignable, Category = "VRM4U")
FVrmMocopiReceiverDelegate OnReceived;
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void GetNextFrameData(FStructMocopiData &data, bool &bEnable, bool &bUpdate);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void GetLatestFrameData(FStructMocopiData &data, bool &bEnable, bool &bUpdate);
UFUNCTION(BlueprintCallable, Category = "VRM4U")
void GetCurrentTime(int& FrameNo, int& Time) {
FrameNo = currentFrameNo;
Time = currentTime;
}
protected:
virtual void BeginDestroy() override;
};
@@ -0,0 +1,61 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Misc/EngineVersionComparison.h"
#include "UObject/StrongObjectPtr.h"
#include "OSCServer.h" // for game build link error
#include "VrmVMCObject.generated.h"
struct FOSCMessage;
struct FVMCData {
FString ServerAddress = "";
int Port = 0;
TMap<FString, FTransform> BoneData;
TMap<FString, float> CurveData;
void ClearData() {
BoneData.Empty();
CurveData.Empty();
}
bool operator==(const FVMCData& Other) const {
if (Port != Other.Port) return false;
if (ServerAddress != Other.ServerAddress) return false;
return true;
}
};
UCLASS()
class VRM4UCAPTURE_API UVrmVMCObject : public UObject
{
GENERATED_BODY()
FCriticalSection cs;
TStrongObjectPtr<UOSCServer> OSCServer;
FVMCData VMCData;
FVMCData VMCData_Cache;
bool bDataUpdated = false;
public:
FString ServerName;
uint16 port;
bool bForceUpdate = false;
void CreateServer(FString name, uint16 port);
void DestroyServer();
void OSCReceivedMessageEvent(const FOSCMessage& Message, const FString& IPAddress, uint16 Port);
bool CopyVMCData(FVMCData& dst);
void ClearVMCData();
};
@@ -0,0 +1,44 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
using UnrealBuildTool;
public class VRM4UCapture : ModuleRules
{
public VRM4UCapture(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PrivateDependencyModuleNames.AddRange(
new string[] {
"Core",
"CoreUObject",
"Engine",
"Networking",
"Sockets",
"OSC",
"AnimGraphRuntime",
"VRM4U",
});
if (Target.bBuildEditor)
{
PrivateDependencyModuleNames.Add("UnrealEd");
}
PrivateIncludePathModuleNames.AddRange(
new string[] {
});
DynamicallyLoadedModuleNames.AddRange(
new string[] {
});
PrivateIncludePaths.AddRange(
new string[] {
// Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source
//"../Runtime/Renderer/Private",
});
}
}
@@ -0,0 +1,159 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "AnimGraphNode_VrmVMC.h"
#include "Misc/EngineVersionComparison.h"
#include "UnrealWidget.h"
#include "AnimNodeEditModes.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstance.h"
#include "Kismet2/CompilerResultsLog.h"
#include "Components/SkeletalMeshComponent.h"
#include "VrmMetaObject.h"
#include "VrmUtil.h"
/////////////////////////////////////////////////////
// UAnimGraphNode_ModifyBone
#define LOCTEXT_NAMESPACE "A3Nodesaaaa"
////////////////////
UAnimGraphNode_VrmVMC::UAnimGraphNode_VrmVMC(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
#if UE_VERSION_OLDER_THAN(5,0,0)
CurWidgetMode = (int32)FWidget::WM_Rotate;
#else
CurWidgetMode = UE::Widget::EWidgetMode::WM_Rotate;
#endif
}
void UAnimGraphNode_VrmVMC::ValidateAnimNodePostCompile(FCompilerResultsLog& MessageLog, UAnimBlueprintGeneratedClass* CompiledClass, int32 CompiledNodeIndex) {
if (Node.VrmMetaObject == nullptr) {
//MessageLog.Warning(*LOCTEXT("VrmNoMetaObject", "@@ - You must set VrmMetaObject").ToString(), this);
} else {
if (Node.VrmMetaObject->SkeletalMesh) {
if (VRMGetSkeleton(Node.VrmMetaObject->SkeletalMesh) != CompiledClass->GetTargetSkeleton()) {
MessageLog.Warning(*LOCTEXT("VrmDifferentSkeleton", "@@ - You must set VrmMetaObject has same skeleton").ToString(), this);
}
}
if (CompiledClass->GetTargetSkeleton()->GetReferenceSkeleton().GetRawBoneNum() <= 0) {
MessageLog.Warning(*LOCTEXT("VrmNoBone", "@@ - Skeleton bad data").ToString(), this);
}
}
Super::ValidateAnimNodePostCompile(MessageLog, CompiledClass, CompiledNodeIndex);
}
void UAnimGraphNode_VrmVMC::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog)
{
// Temporary fix where skeleton is not fully loaded during AnimBP compilation and thus virtual bone name check is invalid UE-39499 (NEED FIX)
if (ForSkeleton && !ForSkeleton->HasAnyFlags(RF_NeedPostLoad))
{
if (Node.VrmMetaObject == nullptr) {
//MessageLog.Warning(*LOCTEXT("VrmNoMetaObject", "@@ - You must set VrmMetaObject").ToString(), this);
} else {
if (Node.VrmMetaObject->SkeletalMesh){
if (VRMGetSkeleton(Node.VrmMetaObject->SkeletalMesh) != ForSkeleton) {
// MessageLog.Warning(*LOCTEXT("VrmDifferentSkeleton", "@@ - You must set VrmMetaObject has same skeleton").ToString(), this);
}
}
if (ForSkeleton->GetReferenceSkeleton().GetRawBoneNum() <= 0) {
// MessageLog.Warning(*LOCTEXT("VrmNoBone", "@@ - Skeleton bad data").ToString(), this);
}
}
/*
//if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.BoneToModify.BoneName) == INDEX_NONE)
if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.BoneNameToModify) == INDEX_NONE)
{
//if (Node.BoneToModify.BoneName == NAME_None)
if (Node.BoneNameToModify == NAME_None)
{
MessageLog.Warning(*LOCTEXT("NoBoneSelectedToModify", "@@ - You must pick a bone to modify").ToString(), this);
}
else
{
FFormatNamedArguments Args;
//Args.Add(TEXT("BoneName"), FText::FromName(Node.BoneToModify.BoneName));
Args.Add(TEXT("BoneName"), FText::FromName(Node.BoneNameToModify));
FText Msg = FText::Format(LOCTEXT("NoBoneFoundToModify", "@@ - Bone {BoneName} not found in Skeleton"), Args);
MessageLog.Warning(*Msg.ToString(), this);
}
}
*/
}
//if ((Node.TranslationMode == BMM_Ignore) && (Node.RotationMode == BMM_Ignore) && (Node.ScaleMode == BMM_Ignore))
{
// MessageLog.Warning(*LOCTEXT("NothingToModify", "@@ - No components to modify selected. Either Rotation, Translation, or Scale should be set to something other than Ignore").ToString(), this);
}
Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog);
}
FText UAnimGraphNode_VrmVMC::GetControllerDescription() const
{
return LOCTEXT("VrmVMC", "VrmVMC");
}
FText UAnimGraphNode_VrmVMC::GetTooltipText() const
{
return LOCTEXT("AnimGraphNode_VrmVMC_Tooltip", "VrmVMC");
}
FText UAnimGraphNode_VrmVMC::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return GetControllerDescription();
//if ((TitleType == ENodeTitleType::ListView || TitleType == ENodeTitleType::MenuTitle) && (Node.SpringBone.BoneName == NAME_None))
//{
// return GetControllerDescription();
//}
/*
FFormatNamedArguments Args;
Args.Add(TEXT("ControllerDescription"), GetControllerDescription());
Args.Add(TEXT("Server"), FText::FromString(Node.ServerAddress));
Args.Add(TEXT("Port"), FText::FromString(FString::FromInt(Node.Port)));
if (TitleType == ENodeTitleType::ListView || TitleType == ENodeTitleType::MenuTitle)
{
CachedNodeTitles.SetCachedTitle(TitleType, FText::Format(LOCTEXT("AnimGraphNode_VrmVMC_ListTitle", "{ControllerDescription} - {Server}:{Port}"), Args), this);
}
else
{
CachedNodeTitles.SetCachedTitle(TitleType, FText::Format(LOCTEXT("AnimGraphNode_VrmVMC_ListTitle", "{ControllerDescription}\n{Server}:{Port}"), Args), this);
}
return CachedNodeTitles[TitleType];
*/
}
//void UAnimGraphNode_VrmVMC::CopyNodeDataToPreviewNode(FAnimNode_Base* InPreviewNode)
//{
//}
FEditorModeID UAnimGraphNode_VrmVMC::GetEditorMode() const
{
return Super::GetEditorMode();
}
void UAnimGraphNode_VrmVMC::Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent * PreviewSkelMeshComp) const
{
if (PreviewSkelMeshComp)
{
if (FAnimNode_VrmVMC* ActiveNode = GetActiveInstanceNode<FAnimNode_VrmVMC>(PreviewSkelMeshComp->GetAnimInstance()))
{
if (bPreviewLive) {
//ActiveNode->ConditionalDebugDraw(PDI, PreviewSkelMeshComp, bPreviewForeground);
}
}
}
}
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,65 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
//#include "BoneControllers/AnimNode_ModifyBone.h"
#include "AnimNode_VrmVMC.h"
#include "EdGraph/EdGraphNodeUtils.h"
#include "AnimGraphNode_SkeletalControlBase.h"
#include "UnrealWidget.h"
#include "AnimNodeEditMode.h"
#include "AnimGraphNode_VrmVMC.generated.h"
class FCompilerResultsLog;
class FPrimitiveDrawInterface;
class USkeletalMeshComponent;
UCLASS(meta=(Keywords = "VRM4U"))
class UAnimGraphNode_VrmVMC : public UAnimGraphNode_SkeletalControlBase
{
GENERATED_UCLASS_BODY()
UPROPERTY(EditAnywhere, Category = Settings)
FAnimNode_VrmVMC Node;
public:
UPROPERTY(EditAnywhere, Category = Preview)
bool bPreviewLive = true;
UPROPERTY(EditAnywhere, Category = Preview)
bool bPreviewForeground = false;
// UEdGraphNode interface
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
virtual FText GetTooltipText() const override;
// End of UEdGraphNode interface
protected:
// UAnimGraphNode_Base interface
virtual void ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog) override;
virtual void ValidateAnimNodePostCompile(FCompilerResultsLog& MessageLog, UAnimBlueprintGeneratedClass* CompiledClass, int32 CompiledNodeIndex) override;
// virtual FEditorModeID GetEditorMode() const override;
//virtual void CopyNodeDataToPreviewNode(FAnimNode_Base* InPreviewNode) override;
//virtual void CopyPinDefaultsToNodeData(UEdGraphPin* InPin) override;
virtual FEditorModeID GetEditorMode() const override;
virtual void Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent * PreviewSkelMeshComp) const override;
// End of UAnimGraphNode_Base interface
// UAnimGraphNode_SkeletalControlBase interface
virtual FText GetControllerDescription() const override;
virtual const FAnimNode_SkeletalControlBase* GetNode() const override { return &Node; }
// End of UAnimGraphNode_SkeletalControlBase interface
private:
/** Constructing FText strings can be costly, so we cache the node's title */
FNodeTitleTextTable CachedNodeTitles;
// storing current widget mode
int32 CurWidgetMode;
};
@@ -0,0 +1,34 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VRM4UCaptureEditor.h"
#include "CoreMinimal.h"
#include "VRM4UCaptureEditorLog.h"
#include "Modules/ModuleManager.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE "VRM4UMisc"
DEFINE_LOG_CATEGORY(LogVRM4UCaptureEditor);
//////////////////////////////////////////////////////////////////////////
// FSpriterImporterModule
class FVRM4UCaptureEditorModule : public FDefaultModuleImpl
{
public:
virtual void StartupModule() override
{
}
virtual void ShutdownModule() override
{
}
};
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_MODULE(FVRM4UCaptureEditorModule, VRM4UCaptureEditor);
//////////////////////////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,8 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
//#include "VRMImporterModule.h"
@@ -0,0 +1,14 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#pragma once
#include "CoreMinimal.h"
//#include "VRMImporterModule.h"
DECLARE_LOG_CATEGORY_EXTERN(LogVRM4UCaptureEditor, Verbose, All);
//#define SPRITER_IMPORT_ERROR(FormatString, ...) \
// if (!bSilent) { UE_LOG(LogVRM4UMIsc, Warning, FormatString, __VA_ARGS__); }
//#define SPRITER_IMPORT_WARNING(FormatString, ...) \
// if (!bSilent) { UE_LOG(LogVRM4UMIsc, Warning, FormatString, __VA_ARGS__); }
@@ -0,0 +1,42 @@
// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
using UnrealBuildTool;
public class VRM4UCaptureEditor : ModuleRules
{
public VRM4UCaptureEditor(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PrivateDependencyModuleNames.AddRange(
new string[] {
"Core",
"CoreUObject",
"Engine",
"AnimGraphRuntime",
"AnimGraph",
"BlueprintGraph",
"UnrealEd",
"AnimationEditMode",
"Persona",
"VRM4U",
"VRM4UCapture",
});
PrivateIncludePathModuleNames.AddRange(
new string[] {
});
DynamicallyLoadedModuleNames.AddRange(
new string[] {
});
PrivateIncludePaths.AddRange(
new string[] {
//"../Runtime/Renderer/Private",
});
}
}
@@ -0,0 +1,33 @@
#include "VRM4UEditor.h"
#include "CoreMinimal.h"
#include "VRM4UEditorLog.h"
#include "Modules/ModuleManager.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE "VRM4UEditor"
DEFINE_LOG_CATEGORY(LogVRM4UEditor);
//////////////////////////////////////////////////////////////////////////
// FSpriterImporterModule
class FVRM4UEditorModule : public FDefaultModuleImpl
{
public:
virtual void StartupModule() override
{
}
virtual void ShutdownModule() override
{
}
};
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_MODULE(FVRM4UEditorModule, VRM4UEditor);
//////////////////////////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE

Some files were not shown because too many files have changed in this diff Show More