UE4中SuggestProjectileVelocity_CustomArc节点可以通过传入两个位置A,B,然后计算出从A到B的斜抛运动的初始速度。
结点的截图如下:
看看结点的中文解释:
由于对其中的原理感到很感兴趣因此就去找了C++的结点源码,然后了解了一下原理,本文是对该节点的一个源码解读,仅代表个人观点,若大佬有别的想法望指正。
首先看看C++代码:
bool UGameplayStatics::SuggestProjectileVelocity_CustomArc(const UObject* WorldContextObject, FVector& OutLaunchVelocity, FVector StartPos, FVector EndPos, float OverrideGravityZ , float ArcParam ) { FVector const StartToEnd = EndPos - StartPos; float const StartToEndDist = StartToEnd.Size(); UWorld const* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); if (World && StartToEndDist > KINDA_SMALL_NUMBER) { const float GravityZ = FMath::IsNearlyEqual(OverrideGravityZ, 0.0f) ? World->GetGravityZ() : OverrideGravityZ; // choose arc according to the arc param FVector const StartToEndDir = StartToEnd / StartToEndDist; FVector LaunchDir = FMath::Lerp(FVector::UpVector, StartToEndDir, ArcParam).GetSafeNormal(); // v = sqrt ( g * dx^2 / ( (dx tan(angle) + dz) * 2 * cos(angle))^2 ) ) FRotator const LaunchRot = LaunchDir.Rotation(); float const Angle = FMath::DegreesToRadians(LaunchRot.Pitch); float const Dx = StartToEnd.Size2D(); float const Dz = StartToEnd.Z; float const NumeratorInsideSqrt = (GravityZ * FMath::Square(Dx) * 0.5f); float const DenominatorInsideSqrt = (Dz - (Dx * FMath::Tan(Angle))) * FMath::Square(FMath::Cos(Angle)); float const InsideSqrt = NumeratorInsideSqrt / DenominatorInsideSqrt; if (InsideSqrt >= 0.f) { // there exists a solution float const Speed = FMath::Sqrt(InsideSqrt); // this is the mag of the vertical component OutLaunchVelocity = LaunchDir * Speed; return true; } } OutLaunchVelocity = FVector::ZeroVector; return false; }
要了解这部分的代码,首先要了解斜抛运动,因为该运动其实主要运用的是中学的物理,因此不过多赘述可以参考文章:https://www.zhihu.com/topic/20683808/intro
大家可以自己简单推导一下,而UE的C++主要应用的是最下面的公式
接下来就来具体看看代码部分:
代码的第一部分,主要是通过传入的参数两个位置相减得到一个方向向量,然后那向量的长度就可以得到两个点的距离,然后方向向量除距离得到方向向量的单位向量StartToEndDir,然后将其与Actor的向上向量做一个插值,插值由Arc决定,注意,因为因为这个Arc默认值是0.5,所以如果你传入的两个点的位置为同一平面的,得出的速度值也是会让Actor向上抛一定高度的。插值后得到的向量就定为最终发射速度的方向向量LaunchDir。然后用这个向量的rotation的pitch值得到这个方向向量相对于水平面的夹角。因为pitch代表的是绕x轴的旋转,所以可以表示一个角度。
得到了方向,还要计算出这个速度的大小,这个就是利用斜抛运动的上文提到的y的公式:
可能这么看比较不直观,简单来讲,C++代码里面求的就是公式里面的V0,首先我们试着通过这个公式转换出关于V的公式。:
然后1+tanθ的平方其实就是1/cosθ平方,所以也可以化简为:
此时就可以与代码中间部分一一对应了(注,图中的V0应该带有平方,截图的时候发现有遗漏):
Dz代表的是斜抛运动的高度,Dx代表的是这个方向向量的水平投影,因为这个公式的推到其实是在二维的,就利用向量的水平投影代表斜抛运动的水平位移。
NumeratorInsideSqrt代表的就是公式中分子的部分,(Squara(Dx)表示求Dx的平方)
DenominatorInsideSqrt表示的是公式中的分母部分,然后相除便可以得到V0的平方。
也就是速度的大小。
最后一部分就是通过判断最终的速度大小如果大于0,则将其乘方向向量,就可以得到最终的初始速度。
以上便是本人对该节点的解读,如果有错误的地方还望大佬指正。