1. 我们的目标是让物体从透明逐渐显现,那么先整理一下实现思路,如果开发过游戏或者对模型有一些基本的了解,一般都会想到,通过调节材质的Alpha通道,使其从0调节到1的过程,物体的透明度就会从纯透明变化到实体。如果是U3D,直接获取材质的Alpha通道进行调节即可,实现起来非常简单,下面我们来看一下UE4的实现方法。
2. UE4的材质分为5种类型,Opaque,Masked,Translucent,Additive,Modulate,其中Opaque是默认类型,为不透明材质。 Translucent为可透明材质。显而易见我们这里选用Translucent类型。 在Opaque模式下,材质的Opacity属性是灰的,不可调节。 换成Translucent模式,该属性点亮,但是很多其他属性例如金属性等都变灰,会损失很多的材质信息,这个我们后面进行分析和处理。
3. 我们把材质的Blend mode改为Translucent,并且为材质添加一个Scalar Parameter,(在材质编辑器的右边Palette中找到Scalar Parameter并拖拽到编辑器中),并把它与Opacity相连。相当于为材质的透明度关联了一个参数,我们只需要在游戏中调节该参数就可以控制该材质的透明度了。
4. 在UE4中,材质有点类似于类,在真正的应用中,我们一般会使用材质实例,材质实例相当于材质的实例化,所以为了实现该功能,可以先参考官方文档https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/MaterialInstances/index.html材质实例部分,来了解一下UE4材质的强大功能。 在UE4中,材质实例分为两种类型:静态(Constant) 和 动态(Dynamic Instance),其中静态的材质实例,只能在运行前进行一次计算,在游戏中不会发生变化。动态材质实例在运行过程中是可以进行计算的。所以我们要用的就是动态材质实例。 其实动态与静态实例是不需要 手动设置的,根据材质本身的不同,UE4会自动判断。
5. 我们在编辑好的材质上点右键,可以看到Create Material Instance的选项,点击就可以生成该材质的实例,点开材质实例可以看到左边Parameter Group中,我们添加的Scalar Parameter已经在里面了,改变他的值可以在预览窗口中看到材质实例的变化。
6. 到此为止我们要实现功能的材质实例已经搞定啦,下面我们来实现其逻辑,首先我们创建一个类,起名叫ATransparatableActor,继承Actor类, 为其创建两个UMaterialInstance属性,
以及一个UStaticMeshComponent的列表,用来保存Actor中所有的静态模型(因为预先不知道Actor中会有多少个模型,所以为了实现透明渐变,必须为所有的模型都换上可透明材质)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChangeTransparentalbe")
UMaterial* M_TransparentalbeMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChangeTransparentalbe")
UMaterial* M_OpaqueMaterial;
TArray<UStaticMeshComponent*> Components;
其中 M_TransparentalbeMaterial 为可透明材质,M_OpaqueMaterial 为不可透明材质,Components 为模型列表。
7. 之后添加一个 timeline 用来调节 Alpha 的值,来产生透明变换,Timeline是UE4的一个空间,具体可以参考UE4的文档,后续会介绍其功能
UPROPERTY()
UTimelineComponent* Timeline;
FOnTimelineFloat InterpFunction{};
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChangeTransparentalbe")
UCurveFloat* fCurve;
其中InterpFunction是Timeline绑定的函数,fCurve是Timeline的曲线参数。
8. 最后实现逻辑部分代码,逻辑就是在透明变换之前,为Actor所有的静态模型换上可透明材质,之后通过把timeline的值付给Scalar Parameter调节材质实例的Opacity参数,实现渐变过程,在Opacity参数达到1后,也就是变为纯不透明物体时,把材质换位不可透明材质。
//构造函数,初始化timeline
AATransparentableActor::AATransparentableActor(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
// Initiate the timeline
Timeline = ObjectInitializer.CreateDefaultSubobject<UTimelineComponent>(this, TEXT("Timeline"));
//Bind the Callbackfuntion for the float return value
InterpFunction.BindUFunction(this, FName{ TEXT("TimelineFloatReturn") });
}
void AATransparentableActor::BeginPlay()
{
Super::BeginPlay();
if (fCurve)
{
Timeline->AddInterpFloat(fCurve, InterpFunction, FName{ TEXT("Alpha") });
}
}
{
if (Timeline->IsPlaying())
{
return true;
}
else
{
return false;
}
}
// Called every frame
void AATransparentableActor::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
if (IsTransforming()) {
TransformByAlpha();
}
}
void AATransparentableActor::SetTransparentable()
{
//TArray<UStaticMeshComponent*> Components;
this->GetComponents<UStaticMeshComponent>(Components);
if (M_TransparentalbeMaterial) {
for (int32 Index = 0; Index != Components.Num(); ++Index)
{
UStaticMeshComponent* targetComp = Components[Index];
targetComp->SetMaterial(0, M_TransparentalbeMaterial);
}
}
}
void AATransparentableActor::SetOpaque()
{
//TArray<UStaticMeshComponent*> Components;
this->GetComponents<UStaticMeshComponent>(Components);
if (M_OpaqueMaterial) {
for (int32 Index = 0; Index != Components.Num(); ++Index)
{
UStaticMeshComponent* targetComp = Components[Index];
targetComp->SetMaterial(0, M_OpaqueMaterial);
}
}
}
{
Timeline->Play();
}
void AATransparentableActor::TransformByAlpha()
{
//TArray<UStaticMeshComponent*> Components;
this->GetComponents<UStaticMeshComponent>(Components);
float AlphaFloat = 0.0f;
if (fCurve)
{
AlphaFloat = fCurve->GetFloatValue(Timeline->GetPlaybackPosition());
}
for (int32 Index = 0; Index != Components.Num(); ++Index)
{
UStaticMeshComponent* targetComp = Components[Index];
targetComp->SetScalarParameterValueOnMaterials("alpha", AlphaFloat);
}
}