確認UE5: 5.4.4
グラフベースでタイムライン等の制御に利用できる便利なCurveVector、CurveLinearColor。
運用していると、下記のようになる事が偶にあります。ありました。
- CurveVectorではカーブが3つ。今回5つのパラメーターがあるので CurveVector を2つ使います
- 1つのカーブアセットで編集したい……アセット切り替えたくない……
- X は "Intensity"、Y は "Attenuation" として内部的には扱います
- "X, Y, Z" ではなくて、実際のパラメーターの名前にしたい……どれがどれだっけ、になる……
このような場合に、Curveアセットの種類を自作していい感じにします
このような形で、上図はカーブを6つ用意、それぞれに名前を設定して分かりやすくしています。
実装コード
C++で UCurveBase を継承するだけで利用可能です。
PostProcessCurve.h
UCLASS()
class UPostProcessCurve : public UCurveBase
{
GENERATED_UCLASS_BODY()
UPROPERTY()
FRichCurve FloatCurves[6]; // todo 要素番号を定数化
UFUNCTION(BlueprintCallable, Category="Math|Curves")
float GetValue(int32 CurveIndex, float InTime) const;
// Begin FCurveOwnerInterface
virtual TArray<FRichCurveEditInfoConst> GetCurves() const override;
virtual TArray<FRichCurveEditInfo> GetCurves() override;
virtual FLinearColor GetCurveColor(FRichCurveEditInfo CurveInfo) const override;
virtual bool IsValidCurve( FRichCurveEditInfo CurveInfo ) override;
bool operator == (const UPostProcessCurve& Curve) const;
};
PostProcessCurve.cpp
UPostProcessCurve::UPostProcessCurve(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
#if WITH_EDITOR
// カーブの初期値を設定したい場合に
bool bIsEmpty = true;
for (int32 Index = 0 ; Index < UE_ARRAY_COUNT(FloatCurves) ; ++Index)
{
if (FloatCurves[Index].GetNumKeys() > 0)
{
bIsEmpty = false;
break;
}
}
if (bIsEmpty)
{
FloatCurves[0].AddKey(0.0f, 6500.0f);
FloatCurves[1].AddKey(0.0f, 0.5f);
FloatCurves[2].AddKey(0.0f, 1.0f);
FloatCurves[3].AddKey(0.0f, 0.0f);
FloatCurves[4].AddKey(0.0f, 0.0f);
FloatCurves[5].AddKey(0.0f, 0.0f);
}
#endif
}
float UPostProcessCurve::GetValue(int32 CurveIndex, float InTime) const
{
if ((CurveIndex < 0) || (CurveIndex >= UE_ARRAY_COUNT(FloatCurves)))
{
ensure(false);
return 0;
}
return FloatCurves[CurveIndex].Eval(InTime);
}
// カーブエディターで表示される名前
static const FName PostProcessCurveWhiteTempName(TEXT("WhiteTemp"));
static const FName PostProcessCurveBloomName(TEXT("Bloom"));
static const FName PostProcessCurveLensFlareName(TEXT("LensFlare"));
static const FName PostProcessCurveVignetteName(TEXT("Vignette"));
static const FName PostProcessCurveFringeName(TEXT("Fringe"));
static const FName PostProcessCurveMotionBlurName(TEXT("MotionBlur"));
TArray<FRichCurveEditInfoConst> UPostProcessCurve::GetCurves() const
{
TArray<FRichCurveEditInfoConst> Curves;
Curves.Add(FRichCurveEditInfoConst(&FloatCurves[0], PostProcessCurveWhiteTempName));
Curves.Add(FRichCurveEditInfoConst(&FloatCurves[1], PostProcessCurveBloomName));
Curves.Add(FRichCurveEditInfoConst(&FloatCurves[2], PostProcessCurveLensFlareName));
Curves.Add(FRichCurveEditInfoConst(&FloatCurves[3], PostProcessCurveVignetteName));
Curves.Add(FRichCurveEditInfoConst(&FloatCurves[4], PostProcessCurveFringeName));
Curves.Add(FRichCurveEditInfoConst(&FloatCurves[5], PostProcessCurveMotionBlurName));
return Curves;
}
TArray<FRichCurveEditInfo> UPostProcessCurve::GetCurves()
{
TArray<FRichCurveEditInfo> Curves;
Curves.Add(FRichCurveEditInfo(&FloatCurves[0], PostProcessCurveWhiteTempName));
Curves.Add(FRichCurveEditInfo(&FloatCurves[1], PostProcessCurveBloomName));
Curves.Add(FRichCurveEditInfo(&FloatCurves[2], PostProcessCurveLensFlareName));
Curves.Add(FRichCurveEditInfo(&FloatCurves[3], PostProcessCurveVignetteName));
Curves.Add(FRichCurveEditInfo(&FloatCurves[4], PostProcessCurveFringeName));
Curves.Add(FRichCurveEditInfo(&FloatCurves[5], PostProcessCurveMotionBlurName));
return Curves;
}
FLinearColor UPostProcessCurve::GetCurveColor(FRichCurveEditInfo CurveInfo) const
{
// カーブエディターで表示される色
if (CurveInfo.CurveName == PostProcessCurveWhiteTempName) return FLinearColor(0.8f, 0.2f, 0.2f);
else if (CurveInfo.CurveName == PostProcessCurveBloomName) return FLinearColor(0.8f, 0.8f, 0.2f);
else if (CurveInfo.CurveName == PostProcessCurveLensFlareName) return FLinearColor(0.2f, 0.8f, 0.2f);
else if (CurveInfo.CurveName == PostProcessCurveVignetteName) return FLinearColor(0.2f, 0.8f, 0.8f);
else if (CurveInfo.CurveName == PostProcessCurveFringeName) return FLinearColor(0.2f, 0.2f, 0.8f);
else if (CurveInfo.CurveName == PostProcessCurveMotionBlurName) return FLinearColor(0.8f, 0.2f, 0.8f);
return Super::GetCurveColor(CurveInfo);
}
bool UPostProcessCurve::IsValidCurve( FRichCurveEditInfo CurveInfo )
{
for (const auto& Curve : FloatCurves)
{
if (CurveInfo.CurveToEdit == &Curve)
{
return true;
}
}
return false;
}
bool UPostProcessCurve::operator == (const UPostProcessCurve& Curve) const
{
for (int32 Index = 0 ; Index < UE_ARRAY_COUNT(FloatCurves) ; ++Index)
{
if (Curve.FloatCurves[Index] != FloatCurves[Index])
{
return false;
}
}
return true;
}
上記のように UCurveBaseを継承したクラスを用意すると、Editorでのカーブアセット作成時にクラスが表示されて使用可能になります。