You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb:none ============================ MAJOR FEATURES & CHANGES ============================ Change 4300079 by Thomas.Sarkanen Fixed incorrect sub instance error reporting when multiple sub-instances of the same class are used #jira UE-62613 - Using a Sub Anim Instance causes a "Sub Instance Loop" Compile Error Change 4301787 by Lina.Halper Fix crash when multi select with bone driven controller - make sure you can't continue with mismatching types of classes, code becomes very vulnerable #jira: UE-58531 Change 4302310 by Lina.Halper Fix for anim slot window of small icons #jira: UE-54822 Change 4302385 by Lina.Halper remove constructor female data from control rig example Change 4303861 by Lina.Halper PR #4298: Avoid division by 0 in AnimLinkableElement (Contributed by DSDambuster) #jira: UE-53260 Change 4304915 by Lina.Halper PR #4842: UE-52767: UAnimComposite doesn't inherit from UAnimSequence (Contributed by projectgheist) Fixes issue with stepping not working with AnimComposite - it also loops around #jira: UE-61367 Change 4307241 by Lina.Halper Control rig : invalid FOV issue #jira: UE-62799 Change 4310924 by Lina.Halper Only display native control rig class for parent class picker #jira: UE-62798 Change 4314164 by Jurre.deBaare Fix issue with propagating vertex colors to static meshes in some cases not working correctly #fix Using .OverrideVertexColors instead of .OverrideMapBuildData to do pointer comparison #jira none Change 4321197 by Lina.Halper fix aim offset assets - removed aimtest2 as it doens't really do anything Change 4321673 by Martin.Wilson Autoload Animation Blueprint compiler module in editor so that we can set up logging category (following how normal blueprint compiler works) #jira UE-59319 Change 4321898 by Martin.Wilson Change Live Link tab to nomad #jira UE-54412 Change 4322333 by Thomas.Sarkanen Fix additional params being displayed on blutility asset/actor actions dialog #jira UE-62063 - Blutility context menu popup shows all pins inside function Change 4322338 by Thomas.Sarkanen Fixed mis-reported HLOD build indicator #jira UE-62648 - HLOD cluster needs to be rebuilt even though they have been build Change 4322368 by Lina.Halper fixed build error Change 4322378 by Lina.Halper Fix issue where preview asset is not saved and not loaded unless it's loaded manually #jira: UE-63254 Change 4322490 by Lina.Halper - added an option to refresh transform as that can solve quick issues where ref pose goes wrong - fixed search #jira: UE-63136, UE-63181 Change 4322824 by Martin.Wilson Fix possible crash due to retarget asset being cleaned up on ULiveLinkInstance #jira UE-62265 Change 4325357 by Thomas.Sarkanen Perform anim update even when we have zero bones, but still skip evaluation This ensures that notifies still get triggered in all update-relevant tick modes, even on dedicated servers. #jira UE-63204 - Dedicated servers do not trigger anim notifies in anim sequences Change 4325358 by Thomas.Sarkanen Fix incorrect interpolations when using URO and CopyPoseFromMesh This ensures that CopyPoseFromMesh uses the correct target pose to inteprolate to, rather than the already-interpolated output pose. #jira UE-62588 - URO is incompatible with CopyPoseFromMesh in certain circumstances Change 4325552 by Martin.Wilson Fix doubling of playrate in marker sync code #jira UE-59008 Change 4331507 by Thomas.Sarkanen Fixed crash when creating a new notify in certain circumstances When creating a notify causes a timing order change, then the timing panel wasnt getting refreshed and was accessing the wrong notify to do its drawing. #jira UE-63476 - Editor crashes if you add a notify to montage #ROBOMERGE-OWNER: jason.bestimt #ROBOMERGE-SOURCE: CL 4335668 in //UE4/Main/... #ROBOMERGE-BOT: DEVVR (Main -> Dev-VR) [CL 4335669 by lina halper in Dev-VR branch]
558 lines
21 KiB
C++
558 lines
21 KiB
C++
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "AnimGraphNode_BoneDrivenController.h"
|
|
#include "SceneManagement.h"
|
|
#include "Components/SkeletalMeshComponent.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
#include "Kismet2/CompilerResultsLog.h"
|
|
#include "PropertyHandle.h"
|
|
#include "DetailLayoutBuilder.h"
|
|
#include "DetailWidgetRow.h"
|
|
#include "IDetailPropertyRow.h"
|
|
#include "DetailCategoryBuilder.h"
|
|
#include "AnimationCustomVersion.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "A3Nodes"
|
|
|
|
UAnimGraphNode_BoneDrivenController::UAnimGraphNode_BoneDrivenController(const FObjectInitializer& ObjectInitializer)
|
|
:Super(ObjectInitializer)
|
|
{
|
|
|
|
}
|
|
|
|
void UAnimGraphNode_BoneDrivenController::Serialize(FArchive& Ar)
|
|
{
|
|
Super::Serialize(Ar);
|
|
|
|
Ar.UsingCustomVersion(FAnimationCustomVersion::GUID);
|
|
|
|
const int32 AnimVersion = Ar.CustomVer(FAnimationCustomVersion::GUID);
|
|
|
|
if (AnimVersion < FAnimationCustomVersion::BoneDrivenControllerRemapping)
|
|
{
|
|
if (AnimVersion < FAnimationCustomVersion::BoneDrivenControllerMatchingMaya)
|
|
{
|
|
// The node used to be able to only drive a single component rather than a selection of components
|
|
Node.ConvertTargetComponentToBits();
|
|
|
|
// The old definition of range was clamping the output, rather than the input
|
|
if (Node.bUseRange && !FMath::IsNearlyZero(Node.Multiplier))
|
|
{
|
|
// Before: Output = clamp(Input * Multipler)
|
|
// After: Output = clamp(Input) * Multiplier
|
|
Node.RangeMin /= Node.Multiplier;
|
|
Node.RangeMax /= Node.Multiplier;
|
|
}
|
|
}
|
|
|
|
Node.RemappedMin = Node.RangeMin;
|
|
Node.RemappedMax = Node.RangeMax;
|
|
}
|
|
}
|
|
|
|
FText UAnimGraphNode_BoneDrivenController::GetTooltipText() const
|
|
{
|
|
return LOCTEXT("UAnimGraphNode_BoneDrivenController_ToolTip", "Drives the transform of a bone or morph target using the transform of another bone");
|
|
}
|
|
|
|
FText UAnimGraphNode_BoneDrivenController::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
|
{
|
|
if ((Node.SourceBone.BoneName == NAME_None) && (Node.TargetBone.BoneName == NAME_None) && ((TitleType == ENodeTitleType::ListView) || (TitleType == ENodeTitleType::MenuTitle)))
|
|
{
|
|
return GetControllerDescription();
|
|
}
|
|
else
|
|
{
|
|
// Determine the mapping
|
|
FText FinalSourceExpression;
|
|
{
|
|
FFormatNamedArguments SourceArgs;
|
|
SourceArgs.Add(TEXT("SourceBone"), FText::FromName(Node.SourceBone.BoneName));
|
|
SourceArgs.Add(TEXT("SourceComponent"), ComponentTypeToText(Node.SourceComponent));
|
|
|
|
if (Node.DrivingCurve != nullptr)
|
|
{
|
|
FinalSourceExpression = LOCTEXT("BoneDrivenByCurve", "curve({SourceBone}.{SourceComponent})");
|
|
}
|
|
else
|
|
{
|
|
if (Node.bUseRange)
|
|
{
|
|
if (Node.Multiplier == 1.0f)
|
|
{
|
|
FinalSourceExpression = LOCTEXT("WithRangeBoneMultiplierIs1", "remap({SourceBone}.{SourceComponent})");
|
|
}
|
|
else
|
|
{
|
|
SourceArgs.Add(TEXT("Multiplier"), FText::AsNumber(Node.Multiplier));
|
|
FinalSourceExpression = LOCTEXT("WithRangeNonUnityMultiplier", "remap({SourceBone}.{SourceComponent}) * {Multiplier}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Node.Multiplier == 1.0f)
|
|
{
|
|
FinalSourceExpression = LOCTEXT("BoneMultiplierIs1", "{SourceBone}.{SourceComponent}");
|
|
}
|
|
else
|
|
{
|
|
SourceArgs.Add(TEXT("Multiplier"), FText::AsNumber(Node.Multiplier));
|
|
FinalSourceExpression = LOCTEXT("NonUnityMultiplier", "{SourceBone}.{SourceComponent} * {Multiplier}");
|
|
}
|
|
}
|
|
}
|
|
|
|
FinalSourceExpression = FText::Format(FinalSourceExpression, SourceArgs);
|
|
}
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("ControllerDesc"), GetControllerDescription());
|
|
|
|
Args.Add(TEXT("ParameterName"), FText::FromName(Node.ParameterName));
|
|
|
|
Args.Add(TEXT("TargetBone"), FText::FromName(Node.TargetBone.BoneName));
|
|
|
|
// Determine the target component
|
|
int32 NumComponents = 0;
|
|
EComponentType::Type TargetComponent = EComponentType::None;
|
|
|
|
#define UE_CHECK_TARGET_COMPONENT(ComponentProperty, ComponentChoice) if (ComponentProperty) { ++NumComponents; TargetComponent = ComponentChoice; }
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetTranslationX, EComponentType::TranslationX);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetTranslationY, EComponentType::TranslationY);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetTranslationZ, EComponentType::TranslationZ);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetRotationX, EComponentType::RotationX);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetRotationY, EComponentType::RotationY);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetRotationZ, EComponentType::RotationZ);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetScaleX, EComponentType::ScaleX);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetScaleY, EComponentType::ScaleY);
|
|
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetScaleZ, EComponentType::ScaleZ);
|
|
Args.Add(TEXT("TargetComponents"), (NumComponents <= 1) ? ComponentTypeToText(TargetComponent) : LOCTEXT("MultipleTargetComponents", "multiple"));
|
|
|
|
if ((TitleType == ENodeTitleType::ListView) || (TitleType == ENodeTitleType::MenuTitle))
|
|
{
|
|
Args.Add(TEXT("Delim"), FText::FromString(TEXT(" - ")));
|
|
}
|
|
else
|
|
{
|
|
Args.Add(TEXT("Delim"), FText::FromString(TEXT("\n")));
|
|
}
|
|
|
|
Args.Add(TEXT("SourceExpression"), FinalSourceExpression);
|
|
|
|
FText FormattedText;
|
|
if (Node.DestinationMode == EDrivenDestinationMode::Bone)
|
|
{
|
|
FormattedText = FText::Format(LOCTEXT("AnimGraphNode_BoneDrivenController_Title_Bone", "{TargetBone}.{TargetComponents} = {SourceExpression}{Delim}{ControllerDesc}"), Args);
|
|
}
|
|
else if ( Node.DestinationMode == EDrivenDestinationMode::MorphTarget || Node.DestinationMode == EDrivenDestinationMode::MaterialParameter)
|
|
{
|
|
FormattedText = FText::Format(LOCTEXT("AnimGraphNode_BoneDrivenController_Title_Curve", "{ParameterName} = {SourceExpression}{Delim}{ControllerDesc}"), Args);
|
|
}
|
|
|
|
return FormattedText;
|
|
}
|
|
}
|
|
|
|
FText UAnimGraphNode_BoneDrivenController::GetControllerDescription() const
|
|
{
|
|
return LOCTEXT("BoneDrivenController", "Bone Driven Controller");
|
|
}
|
|
|
|
void UAnimGraphNode_BoneDrivenController::Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* SkelMeshComp) const
|
|
{
|
|
static const float ArrowHeadWidth = 5.0f;
|
|
static const float ArrowHeadHeight = 8.0f;
|
|
|
|
const int32 SourceIdx = SkelMeshComp->GetBoneIndex(Node.SourceBone.BoneName);
|
|
const int32 TargetIdx = SkelMeshComp->GetBoneIndex(Node.TargetBone.BoneName);
|
|
|
|
if ((SourceIdx != INDEX_NONE) && (TargetIdx != INDEX_NONE))
|
|
{
|
|
const FTransform SourceTM = SkelMeshComp->GetComponentSpaceTransforms()[SourceIdx] * SkelMeshComp->GetComponentTransform();
|
|
const FTransform TargetTM = SkelMeshComp->GetComponentSpaceTransforms()[TargetIdx] * SkelMeshComp->GetComponentTransform();
|
|
|
|
PDI->DrawLine(TargetTM.GetLocation(), SourceTM.GetLocation(), FLinearColor(0.0f, 0.0f, 1.0f), SDPG_Foreground, 0.5f);
|
|
|
|
const FVector ToTarget = TargetTM.GetTranslation() - SourceTM.GetTranslation();
|
|
const FVector UnitToTarget = ToTarget.GetSafeNormal();
|
|
FVector Midpoint = SourceTM.GetTranslation() + 0.5f * ToTarget + 0.5f * UnitToTarget * ArrowHeadHeight;
|
|
|
|
FVector YAxis;
|
|
FVector ZAxis;
|
|
UnitToTarget.FindBestAxisVectors(YAxis, ZAxis);
|
|
const FMatrix ArrowMatrix(UnitToTarget, YAxis, ZAxis, Midpoint);
|
|
|
|
DrawConnectedArrow(PDI, ArrowMatrix, FLinearColor(0.0f, 1.0f, 0.0), ArrowHeadHeight, ArrowHeadWidth, SDPG_Foreground);
|
|
|
|
PDI->DrawPoint(SourceTM.GetTranslation(), FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground);
|
|
PDI->DrawPoint(SourceTM.GetTranslation() + ToTarget, FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground);
|
|
}
|
|
}
|
|
|
|
void UAnimGraphNode_BoneDrivenController::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog)
|
|
{
|
|
if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.SourceBone.BoneName) == INDEX_NONE)
|
|
{
|
|
MessageLog.Warning(*LOCTEXT("DriverJoint_NoSourceBone", "@@ - You must pick a source bone as the Driver joint").ToString(), this);
|
|
}
|
|
|
|
if (Node.SourceComponent == EComponentType::None)
|
|
{
|
|
MessageLog.Warning(*LOCTEXT("DriverJoint_NoSourceComponent", "@@ - You must pick a source component on the Driver joint").ToString(), this);
|
|
}
|
|
|
|
if (Node.DestinationMode == EDrivenDestinationMode::Bone)
|
|
{
|
|
if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.TargetBone.BoneName) == INDEX_NONE)
|
|
{
|
|
MessageLog.Warning(*LOCTEXT("DriverJoint_NoTargetBone", "@@ - You must pick a target bone as the Driven joint").ToString(), this);
|
|
}
|
|
|
|
const bool bAffectsTranslation = Node.bAffectTargetTranslationX || Node.bAffectTargetTranslationY || Node.bAffectTargetTranslationZ;
|
|
const bool bAffectsRotation = Node.bAffectTargetRotationX || Node.bAffectTargetRotationY || Node.bAffectTargetRotationZ;
|
|
const bool bAffectsScale = Node.bAffectTargetScaleX || Node.bAffectTargetScaleY || Node.bAffectTargetScaleZ;
|
|
|
|
if (!bAffectsTranslation && !bAffectsRotation && !bAffectsScale)
|
|
{
|
|
MessageLog.Warning(*LOCTEXT("DriverJoint_NoTargetComponent", "@@ - You must pick one or more target components on the Driven joint").ToString(), this);
|
|
}
|
|
}
|
|
|
|
Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog);
|
|
}
|
|
|
|
|
|
void UAnimGraphNode_BoneDrivenController::AddTripletPropertyRow(const FText& Name, const FText& Tooltip, IDetailCategoryBuilder& Category, TSharedRef<IPropertyHandle> PropertyHandle, const FName XPropertyName, const FName YPropertyName, const FName ZPropertyName, TAttribute<EVisibility> VisibilityAttribute)
|
|
{
|
|
const float XYZPadding = 5.0f;
|
|
|
|
TSharedPtr<IPropertyHandle> XProperty = PropertyHandle->GetChildHandle(XPropertyName);
|
|
Category.GetParentLayout().HideProperty(XProperty);
|
|
|
|
TSharedPtr<IPropertyHandle> YProperty = PropertyHandle->GetChildHandle(YPropertyName);
|
|
Category.GetParentLayout().HideProperty(YProperty);
|
|
|
|
TSharedPtr<IPropertyHandle> ZProperty = PropertyHandle->GetChildHandle(ZPropertyName);
|
|
Category.GetParentLayout().HideProperty(ZProperty);
|
|
|
|
Category.AddCustomRow(Name)
|
|
.Visibility(VisibilityAttribute)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(Name)
|
|
.ToolTipText(Tooltip)
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
.ValueContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.f, 0.f, XYZPadding, 0.f)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
XProperty->CreatePropertyNameWidget()
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
XProperty->CreatePropertyValueWidget()
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.f, 0.f, XYZPadding, 0.f)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
YProperty->CreatePropertyNameWidget()
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
YProperty->CreatePropertyValueWidget()
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.f, 0.f, XYZPadding, 0.f)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
ZProperty->CreatePropertyNameWidget()
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
ZProperty->CreatePropertyValueWidget()
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
void UAnimGraphNode_BoneDrivenController::AddRangePropertyRow(const FText& Name, const FText& Tooltip, IDetailCategoryBuilder& Category, TSharedRef<IPropertyHandle> PropertyHandle, const FName MinPropertyName, const FName MaxPropertyName, TAttribute<EVisibility> VisibilityAttribute)
|
|
{
|
|
const float MiddlePadding = 4.0f;
|
|
|
|
TSharedPtr<IPropertyHandle> MinProperty = PropertyHandle->GetChildHandle(MinPropertyName);
|
|
Category.GetParentLayout().HideProperty(MinProperty);
|
|
|
|
TSharedPtr<IPropertyHandle> MaxProperty = PropertyHandle->GetChildHandle(MaxPropertyName);
|
|
Category.GetParentLayout().HideProperty(MaxProperty);
|
|
|
|
Category.AddCustomRow(Name)
|
|
.Visibility(VisibilityAttribute)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(Name)
|
|
.ToolTipText(Tooltip)
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
.ValueContent()
|
|
.MinDesiredWidth(100.0f * 2.0f)
|
|
.MaxDesiredWidth(100.0f * 2.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1)
|
|
.Padding(0.0f, 0.0f, MiddlePadding, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
MinProperty->CreatePropertyValueWidget()
|
|
]
|
|
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("MinMaxSpacer", ".."))
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1)
|
|
.Padding(MiddlePadding, 0.0f, 0.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
MaxProperty->CreatePropertyValueWidget()
|
|
]
|
|
];
|
|
}
|
|
|
|
void UAnimGraphNode_BoneDrivenController::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
|
|
{
|
|
Super::CustomizeDetails(DetailBuilder);
|
|
|
|
TSharedRef<IPropertyHandle> NodeHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimGraphNode_BoneDrivenController, Node), GetClass());
|
|
|
|
// if it doesn't have this node, that means this isn't really bone driven controller
|
|
if (!NodeHandle->IsValidHandle())
|
|
{
|
|
return;
|
|
}
|
|
|
|
TAttribute<EVisibility> NotUsingCurveVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreNonCurveMappingValuesVisible, &DetailBuilder));
|
|
TAttribute<EVisibility> MapRangeVisiblity = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreRemappingValuesVisible, &DetailBuilder));
|
|
|
|
// Source (Driver) category
|
|
IDetailCategoryBuilder& SourceCategory = DetailBuilder.EditCategory(TEXT("Source (Driver)"));
|
|
|
|
// Mapping category
|
|
IDetailCategoryBuilder& MappingCategory = DetailBuilder.EditCategory(TEXT("Mapping"));
|
|
MappingCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, DrivingCurve)));
|
|
|
|
MappingCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bUseRange))).Visibility(NotUsingCurveVisibility);
|
|
|
|
AddRangePropertyRow(
|
|
/*Name=*/ LOCTEXT("InputRangeLabel", "Source Range"),
|
|
/*Tooltip=*/ LOCTEXT("InputRangeTooltip", "The range (relative to the reference pose) over which to limit the effect of the input component on the output component"),
|
|
/*Category=*/ MappingCategory,
|
|
/*PropertyHandle=*/ NodeHandle,
|
|
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RangeMin),
|
|
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RangeMax),
|
|
MapRangeVisiblity);
|
|
AddRangePropertyRow(
|
|
/*Name=*/ LOCTEXT("MappedRangeLabel", "Mapped Range"),
|
|
/*Tooltip=*/ LOCTEXT("MappedRangeTooltip", "The range of mapped values that correspond to the input range"),
|
|
/*Category=*/ MappingCategory,
|
|
/*PropertyHandle=*/ NodeHandle,
|
|
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RemappedMin),
|
|
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RemappedMax),
|
|
MapRangeVisiblity);
|
|
|
|
MappingCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, Multiplier))).Visibility(NotUsingCurveVisibility);
|
|
|
|
// Destination visiblity
|
|
TAttribute<EVisibility> BoneTargetVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreTargetBonePropertiesVisible, &DetailBuilder));
|
|
TAttribute<EVisibility> CurveTargetVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreTargetCurvePropertiesVisible, &DetailBuilder));
|
|
|
|
// Destination (Driven) category
|
|
IDetailCategoryBuilder& TargetCategory = DetailBuilder.EditCategory(TEXT("Destination (Driven)"));
|
|
|
|
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, DestinationMode)));
|
|
|
|
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, ParameterName))).Visibility(CurveTargetVisibility);
|
|
|
|
|
|
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, TargetBone))).Visibility(BoneTargetVisibility);
|
|
// Add a note about the space (it is not configurable, and this helps set expectations)
|
|
const FText TargetBoneSpaceName = LOCTEXT("TargetComponentSpace", "Target Component Space");
|
|
TargetCategory.AddCustomRow(TargetBoneSpaceName)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(TargetBoneSpaceName)
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
.ValueContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("TargetComponentSpaceIsAlwaysParentBoneSpace", "Parent Bone Space"))
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
.Visibility(BoneTargetVisibility);
|
|
|
|
AddTripletPropertyRow(
|
|
/*Name=*/ LOCTEXT("DrivenTranslationLabel", "Translation"),
|
|
/*Tooltip=*/ LOCTEXT("DrivenTranslationTooltip", "Should the source bone drive one or more translation components of the target bone?"),
|
|
/*Category=*/ TargetCategory,
|
|
/*PropertyHandle=*/ NodeHandle,
|
|
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetTranslationX),
|
|
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetTranslationY),
|
|
/*Z=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetTranslationZ),
|
|
BoneTargetVisibility);
|
|
|
|
AddTripletPropertyRow(
|
|
/*Name=*/ LOCTEXT("DrivenRotationLabel", "Rotation"),
|
|
/*Tooltip=*/ LOCTEXT("DrivenRotationTooltip", "Should the source bone drive one or more rotation components of the target bone?"),
|
|
/*Category=*/ TargetCategory,
|
|
/*PropertyHandle=*/ NodeHandle,
|
|
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetRotationX),
|
|
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetRotationY),
|
|
/*Z=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetRotationZ),
|
|
BoneTargetVisibility);
|
|
|
|
AddTripletPropertyRow(
|
|
/*Name=*/ LOCTEXT("DrivenScaleLabel", "Scale"),
|
|
/*Tooltip=*/ LOCTEXT("DrivenScaleTooltip", "Should the source bone drive one or more scale components of the target bone?"),
|
|
/*Category=*/ TargetCategory,
|
|
/*PropertyHandle=*/ NodeHandle,
|
|
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetScaleX),
|
|
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetScaleY),
|
|
/*Z=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetScaleZ),
|
|
BoneTargetVisibility);
|
|
|
|
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, ModificationMode))).Visibility(BoneTargetVisibility);
|
|
}
|
|
|
|
FText UAnimGraphNode_BoneDrivenController::ComponentTypeToText(EComponentType::Type Component)
|
|
{
|
|
switch (Component)
|
|
{
|
|
case EComponentType::TranslationX:
|
|
return LOCTEXT("ComponentType_TranslationX", "translateX");
|
|
case EComponentType::TranslationY:
|
|
return LOCTEXT("ComponentType_TranslationY", "translateY");
|
|
case EComponentType::TranslationZ:
|
|
return LOCTEXT("ComponentType_TranslationZ", "translateZ");
|
|
case EComponentType::RotationX:
|
|
return LOCTEXT("ComponentType_RotationX", "rotateX");
|
|
case EComponentType::RotationY:
|
|
return LOCTEXT("ComponentType_RotationY", "rotateY");
|
|
case EComponentType::RotationZ:
|
|
return LOCTEXT("ComponentType_RotationZ", "rotateZ");
|
|
case EComponentType::Scale:
|
|
return LOCTEXT("ComponentType_ScaleMax", "scaleMax");
|
|
case EComponentType::ScaleX:
|
|
return LOCTEXT("ComponentType_ScaleX", "scaleX");
|
|
case EComponentType::ScaleY:
|
|
return LOCTEXT("ComponentType_ScaleY", "scaleY");
|
|
case EComponentType::ScaleZ:
|
|
return LOCTEXT("ComponentType_ScaleZ", "scaleZ");
|
|
default:
|
|
return LOCTEXT("ComponentType_None", "(none)");
|
|
}
|
|
}
|
|
|
|
EVisibility UAnimGraphNode_BoneDrivenController::AreNonCurveMappingValuesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
|
|
{
|
|
const TArray<TWeakObjectPtr<UObject>>& SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
|
|
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
|
|
{
|
|
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
|
|
{
|
|
if (BoneDrivenController->Node.DrivingCurve == nullptr)
|
|
{
|
|
return EVisibility::Visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility UAnimGraphNode_BoneDrivenController::AreRemappingValuesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
|
|
{
|
|
const TArray<TWeakObjectPtr<UObject>>& SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
|
|
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
|
|
{
|
|
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
|
|
{
|
|
if((BoneDrivenController->Node.DrivingCurve == nullptr) && BoneDrivenController->Node.bUseRange)
|
|
{
|
|
return EVisibility::Visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility UAnimGraphNode_BoneDrivenController::AreTargetBonePropertiesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
|
|
{
|
|
const TArray<TWeakObjectPtr<UObject>>& SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
|
|
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
|
|
{
|
|
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
|
|
{
|
|
if(BoneDrivenController->Node.DestinationMode == EDrivenDestinationMode::Bone)
|
|
{
|
|
return EVisibility::Visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility UAnimGraphNode_BoneDrivenController::AreTargetCurvePropertiesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
|
|
{
|
|
TArray<TWeakObjectPtr<UObject>> SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
|
|
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
|
|
{
|
|
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
|
|
{
|
|
if(BoneDrivenController->Node.DestinationMode == EDrivenDestinationMode::MorphTarget || BoneDrivenController->Node.DestinationMode == EDrivenDestinationMode::MaterialParameter)
|
|
{
|
|
return EVisibility::Visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|