UE自带的IK RIG和ControlRig技术
【UE5】角色脚部IK——如何让脚贴在不同斜度的地面(设置脚的旋转)_哔哩哔哩_bilibili
实验后这个还是有一部分问题,首先只能保证高度不能穿过,但是脚步旋转还是会导致穿模
IK前,整个模型在斜坡上会浮空
参考制作:https://www.youtube.com/watch?v=YDTxXM-ss5w
没有动画的时候是正常的,有动画后就又回到原来的样子
PowerIK
虚幻引擎插件:使用Power IK轻松愉快地实现脚底板位置矫正-CSDN博客
Foot Placement
https://www.youtube.com/watch?v=ENmX4YupJY8
这个方法成功了
参考视频 https://www.youtube.com/watch?v=BuHhKj71DU0
首先给骨骼建立虚拟骨骼vb_foot_root,vb_foot_l和vb_foot_r
在FootPlacement这里,把VB_foot_root作为IKFoot的Root骨骼,把自己的Foot_r和Foot_L作为FK骨
LegIK这里把VB的IK骨骼加上,FK骨骼和前面一样
使用了节点之后脚部不会穿过地面了
左边是没有使用Foot,右边是使用Foot
这个方案有一定局限性,需要是根骨骼运动动画,动画本身Root位置不能低于地面,不能控制除了Foot骨骼以外的旋转(例如Ball骨骼穿过地面)
脚底部浮空的问题需要使用IKRIG解决
制作脚底IK检测地面
在Ball朝下检测与地面的距离,当和地面的距离在一定范围就判断为浮空,把脚IK向下移动
思路是制作IKRig,利用IK带动骨骼向下移动,同时有逆向运动学,带动身体其他位置防止腿部拉长
参考IK: https://www.youtube.com/watch?v=-1zBeREIQYc&ab_channel=MullerDigital
这个是中文机翻
【UE5】角色脚部IK——如何让脚贴在不同斜度的地面(设置脚的旋转)_哔哩哔哩_bilibili
锁定Pelvis,让角色不会飘飞
设置大腿被Foot带动的的弯曲方向
FootIK需要暴露出变量,在动画蓝图里面使用
//计算脚浮空与踩住地板
void UBlendAnimInstance::HeelFootTrace(FName SocketName,FVector& OutLocation,float& OutHeelDistance)
{
ACharacter* Character = Cast<ACharacter>(TryGetPawnOwner());
if (!Character)
{
return;
}
USkeletalMeshComponent* Mesh = Character->GetMesh();
if (!Mesh)
{
return;
}
// 获取脚部位置(从脚尖往下发射)
FVector SocketLocation = Mesh->GetSocketLocation(SocketName);
// 设置射线检测的起始和结束位置
FVector Start = SocketLocation; // 脚底位置
FVector End = Start - FVector(0, 0, FootOffset); // 向下发射射线(通过偏移量设置长度)
UE_LOG(LogTemp, Log, TEXT("%s 足底的射线位置: Start: %s, End: %s"),*SocketName.ToString(), *Start.ToString(), *End.ToString());
// 射线检测
FHitResult HitResult;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(Character); // 忽略自己
if (GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility, QueryParams))
{
// 射线命中地面
FVector ImpactPoint = HitResult.ImpactPoint;
// 计算脚部调整距离
FVector Correction = SocketLocation - ImpactPoint;
UE_LOG(LogTemp, Log, TEXT("%s 足底距离地面的长度 %s"),*SocketName.ToString(), *Correction.ToString());
if (Correction.Z >= 0 && Correction.Z <= 8)
{
// 在插值前记录当前 OutLocation 和 Correction
UE_LOG(LogTemp, Log, TEXT("[%s] Correction.Z 在 [0, 8] 范围内: %f"), *SocketName.ToString(), Correction.Z);
UE_LOG(LogTemp, Log, TEXT("[%s] 插值前 OutLocation: %s, Correction: %s"),
*SocketName.ToString(),
*OutLocation.ToString(),
*Correction.ToString());
// 执行插值
OutLocation = FMath::VInterpTo(OutLocation, Correction, GetWorld()->DeltaTimeSeconds, 10.0f);
// 记录插值后的 OutLocation
UE_LOG(LogTemp, Log, TEXT("[%s] 插值后 OutLocation: %s"), *SocketName.ToString(), *OutLocation.ToString());
// 限制 Z 分量
OutLocation.Z = FMath::Clamp(OutLocation.Z, -0.8f, -0.5f);
// 记录限制后的 OutLocation.Z
UE_LOG(LogTemp, Log, TEXT("[%s] 限制后 OutLocation.Z: %f"), *SocketName.ToString(), OutLocation.Z);
// 也可在此打印最终的脚底高度
UE_LOG(LogTemp, Log, TEXT("[%s] 现在的高度 %f"), *SocketName.ToString(), OutLocation.Z);
}
else
{
// 如果 Correction.Z 不在 [0, 8] 范围内,可以在此打印日志帮助定位问题
UE_LOG(LogTemp, Warning, TEXT("[%s] Correction.Z = %f 不在 [0, 8] 范围内,未进行脚部调整"),
*SocketName.ToString(),
Correction.Z);
}
}
}
在动画蓝图内使用这个节点,输入脚的位置(foot或者ball)作为脚底检测,然后发射一个向下检测的射线
把输出的值再设置到IK上