正文
Houdini 的 Curve 确实很方便,但在 UE 里的 Spline 会更方便。Houdini 的 Curve 要转成 UE 的 Spline ,很简单,一句代码搞定:
i@unreal_output_curve = 1;
在 Curve 输出前将 unreal_output_curve 置为 1 。上面的节点就是简单的将一个文本转成 Curve ,注意要计算法线。
制作的 HDA 我开了这几个参数,但没开字体(主要是我不会!)
- Text 是 Curve 的文本,
- FontSize 是字号大小,
- Length 是每个控制点的间隔。
点击 HDA 的 Bake 就可以将这个 Curve 转成 Spline 的 Actor 或者蓝图,但这里会一个问题,曲线会拆分到多个 BP 中,不是一个整体了,这不是我想要的。所以这里先建一个Actor,将 HoudiniAssetBlueprint 设为根组件,然后在 Actor 里进行 Bake,可以将所有的 Spline 放在一个 Actor 下。
但这样有一个问题我没有解决,在这里修改的参数是不会按着新参数进行 Bake 。暂时只想到两种临时解决办法:
- 一是试好参数后,直接设为 HDA 的默认参数。
- 二就是还是上面那种生成 Spline 的方式,让它拆分成多个 BP,然后一个一个将 Spline 粘贴到一个 Actor 中。
这时就得到了一个将文本转 Spline 的组件了,这里我做了一个拖尾的 Niagara 特效,用沿着 Spline 循环移动,在 Timeline 中移动特效,代码如下:
TextSplineFxActor.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TimelineComponent.h"
#include "TextSplineFxActor.generated.h"
class USplineComponent;
class UNiagaraComponent;
class USceneComponent;
class UNiagaraSystem;
class UCurveFloat;
UCLASS(BlueprintType)
class NB_NIAGARA_API ATextSplineFxActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ATextSplineFxActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
UFUNCTION(BlueprintCallable, Category = "Spline")
void StartSpline(USceneComponent* ParentComp);
UFUNCTION(BlueprintCallable, Category = "Spline")
void NiaSplineMovement(float Alpha, USplineComponent* SplineComponent, UNiagaraComponent* NiaComponent);
private:
UFUNCTION()
void UpdateTimeline(float Alpha);
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spline")
UNiagaraSystem* NiagaraAsset;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spline")
UCurveFloat* AniCurve = nullptr;
private:
UPROPERTY()
FTimeline AniTimeline;
};
TextSplineFxActor.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "TextSplineFxActor.h"
#include "Components/SplineComponent.h"
#include "NiagaraComponent.h"
#include "Components/TimelineComponent.h"
// Sets default values
ATextSplineFxActor::ATextSplineFxActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void ATextSplineFxActor::BeginPlay()
{
Super::BeginPlay();
if (AniCurve)
{
AniTimeline.SetLooping(true);
FOnTimelineFloat Delegate;
Delegate.BindUFunction(this, "UpdateTimeline");
AniTimeline.AddInterpFloat(AniCurve, Delegate);
}
}
// Called every frame
void ATextSplineFxActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
AniTimeline.TickTimeline(DeltaTime);
}
void ATextSplineFxActor::StartSpline(USceneComponent* ParentComp)
{
if (!NiagaraAsset || !ParentComp)
{
return;
}
TArray<USceneComponent*> ChildrenComponet = ParentComp->GetAttachChildren();
for (USceneComponent* ChildComp : ChildrenComponet)
{
if (USplineComponent* Spline = Cast<USplineComponent>(ChildComp))
{
UNiagaraComponent* NewNiaComponent = NewObject<UNiagaraComponent>(this);
NewNiaComponent->SetAsset(NiagaraAsset);
NewNiaComponent->SetupAttachment(Spline);
NewNiaComponent->RegisterComponent();
}
}
AniTimeline.PlayFromStart();
}
void ATextSplineFxActor::NiaSplineMovement(float Alpha, USplineComponent* SplineComponent, UNiagaraComponent* NiaComponent)
{
if (!SplineComponent || !NiaComponent)
{
return;
}
const float Distance = SplineComponent->GetSplineLength() * Alpha;
const FTransform& NewTransform = SplineComponent->GetTransformAtDistanceAlongSpline(Distance, ESplineCoordinateSpace::World, true);
NiaComponent->SetWorldTransform(NewTransform);
}
void ATextSplineFxActor::UpdateTimeline(float Alpha)
{
const TArray<UActorComponent*>& Components = GetComponentsByClass(USplineComponent::StaticClass());
for (UActorComponent* TmpComp : Components)
{
if (USplineComponent* Spline = Cast<USplineComponent>(TmpComp))
{
if (UNiagaraComponent* NiaComp = Cast<UNiagaraComponent>(Spline->GetChildComponent(0)))
{
NiaSplineMovement(Alpha, Spline, NiaComp);
}
}
}
}
然后在蓝图里开始: