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

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

效果图:

image.png

第一步,创建C++ Basic Code

image.png

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

image.png

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

image.png

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

image.png

将 unbound 勾选上

image.png

再修改 Blendables 为 PPI_OutlineColored

image.png

image.png

完整代码如下:

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 官方文档

目录
相关文章
【着色器实现Glow可控局部发光效果_Shader效果第十三篇】
【着色器实现Glow可控局部发光效果_Shader效果第十三篇】
|
9月前
|
JavaScript 定位技术
WebGis——Pixi开发vue项目之使用遮罩实现图形缓慢填充颜色(三)
WebGis——Pixi开发vue项目之使用遮罩实现图形缓慢填充颜色(三)
|
10月前
【Three.js入门】纹理及其常用属性、透明纹理、环境遮挡贴图与强度
【Three.js入门】纹理及其常用属性、透明纹理、环境遮挡贴图与强度
294 0
|
10月前
|
图形学
【Three.js入门】纹理加载进度、环境贴图、经纬线映射贴图与高动态范围成像HDR
【Three.js入门】纹理加载进度、环境贴图、经纬线映射贴图与高动态范围成像HDR
300 0
|
10月前
【Three.js入门】标准网格材质、置换贴图、粗糙度贴图、金属贴图、法线贴图
【Three.js入门】标准网格材质、置换贴图、粗糙度贴图、金属贴图、法线贴图
286 0
Revit & Navisworks 二次开发—获取材质贴图
Revit & Navisworks 二次开发—获取材质贴图
Revit & Navisworks 二次开发—获取材质贴图
|
并行计算 iOS开发 MacOS
Metal每日分享,调整图片角度滤镜效果
Metal每日分享,调整图片角度滤镜效果
Metal每日分享,调整图片角度滤镜效果
|
并行计算 iOS开发 MacOS
Metal每日分享,调整曝光滤镜效果
Metal每日分享,调整曝光滤镜效果
Metal每日分享,调整曝光滤镜效果
|
缓存 BI API
从0开发游戏引擎之纹理管理器实现 纹理数据绑定OpenGL滤波方式选择线性滤波
从0开发游戏引擎之纹理管理器实现 纹理数据绑定OpenGL滤波方式选择线性滤波