UE4学习笔记(2)——材质学习

发表于2018-01-08
评论0 2.4k浏览

上一篇给大家介绍了streamingLevel,这篇就要和大家说说材质了,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,该物体也是透明的,如果多个透明物体叠加会出现严重的效率瓶问题,要尽量避免该情况发生。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论