利用第三方后期处理材质(PostProcess Material)对物体进行描边【UE4】【C++】

 

效果图:

 

第一步,创建C++ Basic Code

 

第二步,定义键盘和鼠标输入的映射

 

第三步,修改 Rendering 中的 Custom Depth - Stencil Pass

 

第四步,找到GlobalPostProcessVolume [如果没有的话自行拖放一个PostProcessVolume组件] 

 

将 unbound 勾选上

 

再修改 Blendables 为 PPI_OutlineColored

 

 

完整代码如下:

MyPlayer.h

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Character.h"
#include "MyPlayer.generated.h"

UCLASS()
class OUTLINECPLUSPLUS_API AMyPlayer : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMyPlayer();

	void MoveForward(float val);
	void MoveRight(float val);
	void LookYaw(float val);
	void LookPitch(float val);
	void Use();

	class AInteractableActor* FindFocusedActor();
	void HandleHighlight();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

private:
	UPROPERTY(EditDefaultsOnly)
	float InteractionDistance = 300.f;	// 交互的范围
	class AInteractableActor* FocusedActor;
	// 用于 LineTraceSingleByChannel
	FCollisionQueryParams TraceParams;
};

 

MyPlayer.cpp

 

 

 

// Fill out your copyright notice in the Description page of Project Settings.
#include "InteractableActor.h"
#include "MyPlayer.h"

// Sets default values
AMyPlayer::AMyPlayer()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	TraceParams = FCollisionQueryParams(FName(TEXT("TraceParams")), false, this);
	TraceParams.bTraceComplex = false;
	TraceParams.bTraceAsyncScene = false;
	TraceParams.bReturnPhysicalMaterial = false;
}

// Called when the game starts or when spawned
void AMyPlayer::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AMyPlayer::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

	if (Controller && Controller->IsLocalController())
	{
		HandleHighlight();
	}

}

// Called to bind functionality to input
void AMyPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	InputComponent->BindAxis("MoveForward", this, &AMyPlayer::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &AMyPlayer::MoveRight);
	InputComponent->BindAxis("LookYaw", this, &AMyPlayer::LookYaw);
	InputComponent->BindAxis("LookPitch", this, &AMyPlayer::LookPitch);
	InputComponent->BindAction("Use", IE_Pressed, this, &AMyPlayer::Use);

}
// 前后移动
void AMyPlayer::MoveForward(float val)
{
	FRotator Rotation(0, GetActorRotation().Yaw, 0);	// Roll, Yaw, Pitch
	FVector forward = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X);
	AddMovementInput(forward, val);
}

// 左右移动
void AMyPlayer::MoveRight(float val)
{
	FRotator Rotation(0, GetActorRotation().Yaw, 0);	// Roll, Yaw, Pitch
	FVector right = FRotationMatrix(Rotation).GetScaledAxis(EAxis::Y);
	AddMovementInput(right, val);
}

// 左右转向
void AMyPlayer::LookYaw(float val)
{
	AddControllerYawInput(val);
}

// 上下转向
void AMyPlayer::LookPitch(float val)
{
	// 注意方向相反
	AddControllerPitchInput(val);
}

// 按 E 键与激活对象进行交互
void AMyPlayer::Use()
{
	AInteractableActor* Interactable = FindFocusedActor();
	if (Interactable)
	{
		// OnInteract_Implementation
		Interactable->OnInteract(this);
	}
}

AInteractableActor* AMyPlayer::FindFocusedActor()
{
	if (!Controller)
	{
		return nullptr;
	}

	FVector Location;
	FRotator Rotation;
	FHitResult Hit(ForceInit);
	Controller->GetPlayerViewPoint(Location, Rotation);

	FVector Start = Location;
	FVector End = Start + (Rotation.Vector() * InteractionDistance);

	// 通过 “射线拾取” 选定对象
	GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Camera, TraceParams);
	if (Hit.bBlockingHit)	// 击中
	{
		// 获取当前被击中的对象的引用
		AInteractableActor* MyCastActor = Cast<AInteractableActor>(Hit.GetActor());
		if (MyCastActor)
		{
			return MyCastActor;
		}
	}
	return nullptr;
}

void AMyPlayer::HandleHighlight()
{
	AInteractableActor* NewHighlight = FindFocusedActor();
	if (NewHighlight)
	{
		// 如果当前描边和新激活的对象不是同一个
		if (FocusedActor != NewHighlight)
		{
			if (FocusedActor)
			{
				// 当前描边对象取消描边
				FocusedActor->OnEndFocus();
			}
			// 描边新激活对象
			NewHighlight->OnBeginFocus();
			FocusedActor = NewHighlight;
		}
	}
	else
	{
		if (FocusedActor)
		{
			// 取消描边
			FocusedActor->OnEndFocus();
			FocusedActor = nullptr;
		}
	}
}

 

 

 

InteractableActor.h

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Actor.h"
#include "OutlineCPlusPlus.h"
#include "InteractableActor.generated.h"

UCLASS()
class OUTLINECPLUSPLUS_API AInteractableActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AInteractableActor();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Interaction)
	void OnInteract(AActor* Caller) ;
	virtual void OnInteract_Implementation(AActor* Caller);

	void OnBeginFocus();
	void OnEndFocus();

private:
	UPROPERTY(EditDefaultsOnly)
	uint32 bCanInteract : 1;
	TArray<UMeshComponent*> Meshes;
	UPROPERTY(EditDefaultsOnly)
	EStencilColor Color = EStencilColor::SC_Green;

};

 

InteractableActor.cpp

 

 

 

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyPlayer.h"
#include "InteractableActor.h"


// Sets default values
AInteractableActor::AInteractableActor()
{
 	// 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 AInteractableActor::BeginPlay()
{
	Super::BeginPlay();
	
	for (UActorComponent* Mesh : GetComponentsByClass(UMeshComponent::StaticClass()))
	{
		UMeshComponent* thisMesh = Cast<UMeshComponent>(Mesh);
		if (thisMesh)
		{
			Meshes.Push(thisMesh);
		}
	}

}

// Called every frame
void AInteractableActor::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

}

void AInteractableActor::OnInteract_Implementation(AActor* Caller)
{
	AMyPlayer* Player = Cast<AMyPlayer>(Caller);

	if (Player)
	{
		GEngine->AddOnScreenDebugMessage(-1,   
        5.f,   
        FColor::Red,   
        FString::Printf(TEXT("Now deleting the interactable actor!  "))
		); 

		// 销毁自己
		Destroy();
	}

}

void AInteractableActor::OnBeginFocus()
{
		if (bCanInteract)
		{
				for (UMeshComponent* Mesh : Meshes)
				{
					Mesh->SetRenderCustomDepth(true);
					Mesh->SetCustomDepthStencilValue((uint8)Color);
				}
		}
}

void AInteractableActor::OnEndFocus()
{
		if (bCanInteract)
		{
				for (UMeshComponent* Mesh : Meshes)
				{
					Mesh->SetRenderCustomDepth(false);
				}
		}
}

 

 

 

颜色 的 Enum 

 

UENUM(BlueprintType)
enum class EStencilColor : uint8
{
	SC_Green = 250  UMETA(DisplayName = "Green"),
	SC_Blue = 251  UMETA(DisplayName = "Blue"),
	SC_Red = 252  UMETA(DisplayName = "Red"),
	SC_White = 253  UMETA(DisplayName = "White")
};

 

 

 

 

 

第三方材质下载链接

PostProcess 官方文档

 

 

 

 

 

 

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShaderJoy

您的打赏是我继续写博客的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值