1. 程式人生 > >UE4學習筆記(4)——材質學習

UE4學習筆記(4)——材質學習

UE4材質相關的東西很多,要學起來比較複雜,今天通過一個讓物體從透明逐漸顯現出實體的例項,來初步瞭解一下UE4的材質、材質例項的一些基本知識。

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") });
}
// Called when the game starts or when spawned
void AATransparentableActor::BeginPlay()
{
Super::BeginPlay();

if (fCurve)
{
Timeline->AddInterpFloat(fCurve, InterpFunction, FName{ TEXT("Alpha") });
}

}
bool AATransparentableActor::IsTransforming()
{
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);
}
}
}
void AATransparentableActor::StartTransform()
{
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);
}

}

9. 我們 要注意的是,如果材質為可透明材質,那麼即便Opacity引數為1,該物體也是透明的,如果多個透明物體疊加會出現嚴重的效率瓶問題,要儘量避免該情況發生。