UE4 C++ 攀爬功能

XTG111發表於2024-05-19

UE中的TEXT()

UE中使用TEXT()包含字串後,將字串轉換為寬字元,其將被處理為支援Unicode和跨平臺相容性,而普通型別的字串為一個窄字元型別,可能在跨平臺出現問題。
最主要的問題是在FString的建構函式中是接受TCHAR的


所以對於FString FName FTEXT的構造需要傳入TEXT("xxxx")。

TEXT()是一個宏定義

透過比較平臺的TCHAR型別,來決定將字串x轉換為u或者L型別

eg

主要是當我在使用UKismetSystemLibrary::K2_SetTimer(this, TEXT("AutoClimb"), 0.01f, true, 0.0f, 0.0f)時,該函式是藍圖中的該節點

最開始沒有使用TEXT來包含函式名,其會報錯
LogBlueprintUserMessages: Warning: SetTimer passed a bad function (AutoClimb) or object (None)
K2_SetTimer中函式名字是FName的型別引數,如果只傳入"AutoClimb",應該是"AutoClimb"由於編碼問題無法被正確處理為反射系統中儲存的函式名,所以導致在使用SetTimer被呼叫時,導致UE的反射系統沒有辦法找到函式而報錯
這裡只是猜測,待補充
當然K2_SetTimer可以利用GetWorldTimerManager().SetTimer代替

IK

使用UE中的FABRIK和Two Bone IK 匹配腳的位置
IK:逆向運動學
FK:正向運動學
是兩種用來確定骨骼位置的方式,如果將整個骨骼簡化為RootBone-->JointBone-->EndBone。
那麼FK就是透過調整RB,JB,EB的位置來最終實現EB在正確位置
而IK就是直接操作EB,透過EB的位置和其與RB,JB的幾何約束反向求解RB,JB的位置

Two Bone IK

在UE中TBIK發生在ComponentSpace所以當在動畫藍圖中使用TBIK時,UE會自動將骨骼從LocalSpace轉換為ComponentSpace。
而為了能夠透過EndBone求解出RB和JB,需要一個平面來放置JB,即JB的移動會在這個平面內。所以在TwoBoneIK的節點上要求我們傳入一個JointTarget,一般來說該Target可以是一個經驗定值即可

  1. 透過射線檢測求得腳部位置的偏移
    可以透過新增骨骼插槽來求解骨骼位置,然後從腳部位置EndBone發出射線來求解與地面的接觸點。
	FVector SocketLocation = CharacterRef->GetMesh()->GetSocketLocation(SocketName);
	FVector ActorLocation = CharacterRef->GetActorLocation();
	float FootTraceOffset;
	FVector Start = { SocketLocation.X,SocketLocation.Y,ActorLocation.Z };
	FVector End = { SocketLocation.X,SocketLocation.Y,SocketLocation.Z - CapsuleComponent->GetUnscaledCapsuleHalfHeight() };
	FHitResult Hit;
	ETraceTypeQuery Visible = UEngineTypes::ConvertToTraceType(ECC_Visibility);
	bool IsHit = UKismetSystemLibrary::LineTraceSingle(
		GetWorld(),
		Start,
		End,
		Visible,
		false,
		TArray<AActor*>{},
		EDrawDebugTrace::None,
		Hit,
		true
	);

當返回為true,說明檢測到了地面,現在就需要求解腳部位置的偏移量。這是為了對應在TwoBoneIK中選擇Effector的LocationSpace選擇Bone Space。
image
注意到Mesh的節點即計算其高度的節點實際上是在兩腳之間
image
所以當計算腳部偏移時,應當使用當前檢測到位置減去Mesh節點的位置才是正確的偏移量
image
而由於膠囊體的存在導致整體的骨骼由於碰撞無法下沉,所以還需要使用到
image
該節點將設定從pelvis骨骼下沉一段距離HipOffset,而由於下沉了HipOffset所以需要在腳部偏移量的位置進行補償

float Z = (HitLocation - CharacterRef->GetMesh()->GetComponentLocation()).Z;
//5.0f為測試引數,需根據實際情況進行調整
FootTraceOffset = Z - IKHipOffset + 5.0f;

到這裡,腳部的偏移已經求解完成,使用它至於在將其賦值給TwoBoneIK節點中的Effector引數的X值即可,因為在插槽的座標系X軸是豎直方向的。並且右腳的X還是反向的

//Animation Blueprint
LeftFootLocationIK.X = XClimbComp->GetIKLeftFootOffset();
RightFootLocationIK.X = XClimbComp->GetIKRightFootOffset() * (-1.0f);
  1. HipOffset
    前面說到為了使得骨骼下層,需要求解HipOffset,HipOffset其實就是左右腳的差值,這是由於如果補償HipOffset,由於膠囊體碰撞,骨骼將被限制在高處的臺階
    image
    其次為了避免出現左右腳Hit位置高度差過大,而導致的骨骼拉扯問題,還需要對HipOffset的大小進行限制
    當過大就不再進行HipOffset,說明再走一步可能就掉下去了
float target = abs((RightFootLocation - LeftFootLocation).Z);
if (target != 0.0f)target = UKismetMathLibrary::SelectFloat((-1.0f * target), 0.0f, (target < CapsuleComponent->GetUnscaledCapsuleHalfHeight() / 2.0f));
IKHipOffset = UKismetMathLibrary::FInterpTo(
	IKHipOffset,
	target,
	UGameplayStatics::GetWorldDeltaSeconds(this),
	20.0f
);

那麼整個在動畫藍圖中的節點使用情況就如下所示
image
image
image

FABRIK

相關文章