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可以是一个经验定值即可
- 通过射线检测求得脚部位置的偏移
可以通过添加骨骼插槽来求解骨骼位置,然后从脚部位置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。
注意到Mesh的节点即计算其高度的节点实际上是在两脚之间
所以当计算脚部偏移时,应当使用当前检测到位置减去Mesh节点的位置才是正确的偏移量
而由于胶囊体的存在导致整体的骨骼由于碰撞无法下沉,所以还需要使用到
该节点将设置从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);
- HipOffset
前面说到为了使得骨骼下层,需要求解HipOffset,HipOffset其实就是左右脚的差值,这是由于如果补偿HipOffset,由于胶囊体碰撞,骨骼将被限制在高处的台阶
其次为了避免出现左右脚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
);
那么整个在动画蓝图中的节点使用情况就如下所示