最近在学习Unreal, 学到了处理角色自适应地形部分的内容, 作者使用了 Control Rig, 我学习时遇到的一些问题, 在此记录, 如有大佬路过, 欢迎指点.
蓝图
先把蓝图内容贴上, 蓝图有点大, 可能需要copy 到本地才能看清楚.
源码
1
FRigUnit_GetBoneTransform_Execute() {
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT()
const URigHierarchy* Hierarchy = ExecuteContext.Hierarchy;
if (Hierarchy) {
//...
if (bFirstUpdate){//...}
if (!CachedBone.UpdateCache(FRigElementKey(Bone, ERigElementType::Bone), Hierarchy)){//...}
else {
switch (Space) {
//Global 即 Skeleten Space
case ERigVMTransformSpace::GlobalSpace: {
Transform = Hierarchy->GetGlobalTransform(CachedBone);
break;
}
// LocalSpace 即 Bone Space
case ERigVMTransformSpace::LocalSpace: {
Transform = Hierarchy->GetLocalTransform(CachedBone);
break;
}
default: {
break;
}
}
}
}
}
关键结论: 从骨骼获取的 Translation, 或者说 bone 的基点, 其实是在 Global 空间中的.
2
FRigUnit_SphereTraceByTraceChannel_Execute()
{
//...
if(WorkData.Hash == Hash){//...}
//...
FHitResult HitResult;
bHit = ExecuteContext.GetWorld()->SweepSingleByChannel(HitResult, ExecuteContext.ToWorldSpace(Start), ExecuteContext.ToWorldSpace(End), FQuat::Identity, CollisionChannel, CollisionShape, QueryParams);
if (bHit){
HitLocation = ExecuteContext.ToVMSpace(HitResult.ImpactPoint);
HitNormal = ExecuteContext.GetToWorldSpaceTransform().InverseTransformVector(HitResult.ImpactNormal);
}
//...
}
关键结论:
- Start 和 End 都被转换到了世界空间再进行计算
- trace 的过过程是在世界空间中完成的, 计算出的 bHit 也是在世界空间中的
- bHit 是相对偏移, 而不是HitPoint 的坐标
- bHit 转换到 VM 空间后负值给 HitLocation
FRigVMFunction_AlphaInterp_Execute(){
//...
Result = ScaleBiasClamp.ApplyTo(Value, ExecuteContext.GetDeltaTime());
}
float FInputScaleBiasClamp::ApplyTo(float Value, float InDeltaTime) const
{
float Result = Value;
//...
if (bInterpResult) {
if (bInitialized) {
const float InterpSpeed = (Result >= InterpolatedResult) ? InterpSpeedIncreasing : InterpSpeedDecreasing;
Result = FMath::FInterpTo(InterpolatedResult, Result, InDeltaTime, InterpSpeed);
}
InterpolatedResult = Result;
}
// 对象构造时 bInitialized 被初始化为 false, 这里我没有贴出构造函数代码
bInitialized = true;
return Result;
}
关键结论:
- 刚进入游戏第一帧
- Result = Value; // Result 即蓝图中的 Target 变量
- 由于 bInitialized == false, 因而不会进入if (bInitialized) {}, 即不会插值
- InterpolatedResult = Result;
- 从第二帧开始插值
- 如果角色在非水平地形上移动,这里我假设是倾斜向上, 此时 Result 将更新为新的 Target, 会变小(负z方向, 距离原点更远)
- 在 InterpolatedResult 和 Result 之间, 按一定的速度插值
- 插值完成后令 InterpolatedResult = Result
问题
- 什么是 VM 空间, 特点是什么? 这一点我没有搞清楚
- 我尝试 debug blueprint, 打印出的 GetTransform - Bone 的 z 值一直都是-7, 这说明 ik_foot 的基点在Skeleton 空间中在负z 方向?
- 我测试还是有一些问题, 虽然角色做出了弯腿的动作, 但是一只脚总是有些轻微的漂浮, 如果有能指点的大佬, 万分感谢!