利用第三方材质对物体进行描边【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 官方文档

时间: 2024-10-13 02:44:01

利用第三方材质对物体进行描边【UE4】【C++】的相关文章

【仿乐享微信源码】利用第三方微信营销托管平台快速增加粉丝,形成良好互动,打造精美微信APP

99%的人不知道的微信秘密!微信里的商机.仿乐享微信源码分享,把你的生意做到微信里. WeiKuCMS  (微酷CMS)功能特点:人工客服新功能正式上线!粉丝行为分析.渠道二维码生成.二维码折扣,微菜单,微统计,会员卡签到,微会员,刮刮卡,大转盘,优惠券,积分兑换,微官网,砸金蛋,微调研,微投票,微相册,微商城,微团购,微留言,微喜帖,商家入驻,微门店,微餐饮,微酒店,微教育,微物业,微医疗,微信墙,微花店,微美容,微生活. 微信公共账号轻松接入,无限自定义图文回复.欢迎您的加入! 微酷WeiK

JAVA利用第三方平台发送短信验证码。

前段时间自己做的一个小项目中,涉及到用短信验证码登录.注册的问题,之前没涉及过这一块,看了别人的博客其实也是似懂非懂的,现在就将自己做的利用第三方短信平台来发送验证码这个功能记下来. 本文以注册为例,在SpringMVC+Spring+Mybatis框架的基础上完成该短信验证码功能. 发送短信验证码的原理是:随机生成一个6位数字,将该6位数字保存到session当中,客户端通过sessionid判断对应的session,用户输入的验证码再与session记录的验证码进行比较. 为了防止有广告嫌疑

db数据库利用第三方框架进行提取和解析数据

db的数据包用从github上下载的三方框架进行解析和数据提取,格式一般为数组和字典.db的查看工具是firefox上的解析db插件SQLite 三方框架为FMDB #import "ViewController.h" //1. 引入头文件,需要引入libsqlite3的库 #import "FMDB.h" #import "Word.h" @interface ViewController () @end @implementation Vie

python利用第三方模块,发送短信验证码

对于初学者,如何利用第三方python开发包发送短信验证码,下面是具体的实现和记录过程! 环境:虚拟机上centos7平台,python3.7版本: 第三方短信平台:榛子云短信(smsow.zhenzikj.com) SDK下载地址: smsow.zhenzikj.com/sdkdownload- 注意要下载python3的 API文档: smsow.zhenzikj.com/doc/python_- 首先,申请账号的部分就省略了 1. 获得appid和appSecret 使用申请的账号,登录用

如何让你的scrapy爬虫不再被ban之二(利用第三方平台crawlera做scrapy爬虫防屏蔽)

我们在做scrapy爬虫的时候,爬虫经常被ban是常态.然而前面的文章如何让你的scrapy爬虫不再被ban,介绍了scrapy爬虫防屏蔽的各种策略组合.前面采用的是禁用cookies.动态设置user agent.代理IP和VPN等一系列的措施组合来防止爬虫被ban.除此以外官方文档还介绍了采用Google cache和crawlera的方法.这里就着重介绍一下如何利用crawlera来达到爬虫不被ban的效果.crawlera是一个利用代理IP地址池来做分布式下载的第三方平台,除了scrap

进阶光照与材质之物体和材质

第四章主要介绍分析真实世界中某些常见材质的特性与细节,作者提醒我们应该时刻关注大自然真实世界中材质的特点,加强自己的思考与敏锐的观察力和感知力对渲染实现很有帮助.作者主要对如下材质进行了分析:塑料木头:树,木材,被油漆过的木材叶子和植物金属混凝土和石头:混凝土,砖石,自然界的石头皮肤头发和毛发大气半透明材质:玻璃,水油漆旧的磨损的材质 塑料  塑料有很多种颜色形状甚至有的上了不同的漆,但是它的材质构成是一致的.大部分塑料由白色或半透明的基质构成,这些基质充满了染色粒子,像下图这样 当 光照射到塑

Java中解析HTML数据 (利用第三方库Jsoup)

需求分析: 在为网页服务提取API时需要解析页面中的信息 项目地址: https://github.com/hwding/LibXDUQuery 准备工作: 下载第三方库Jsoup(一款非常优秀的HTML Parser): https://jsoup.org/download 阅读Jsoup API Reference: https://jsoup.org/apidocs/ 查阅相关代码 了解JAVA解析XML的方式(具有异曲同工之妙): http://www.cnblogs.com/hwdin

ASP.NET 利用第三方插件DocX产生Word 之 打印批量打印

客户需求: 接上一篇需求说起~~~ 上一篇说客户需要固定格式打印(定义模板),实现了之后,客户又闲一张一张打印有些麻烦,要进行批量打印. 客户的需求就是这样,满足了一个又一个~~~没办法,做呗!毕竟客户给钱还是很痛快的! 解决办法: 还是利用DocX插件进行处理. DocX是一个以非常直观简单的方式操作Word 2007/2010文件的轻量级.NET组件.它的速度非常快,而且不需要安装微软的Office软件. 附上DocX插件官网:https://docx.codeplex.com/ 废话不说,

php 中引入邮箱服务 , 利用第三方的smtp邮件服务

项目中用短信通知有时间限制,对一些频率比较大的信息力不从心. 使用邮箱发送信息是个不错的选择\(^o^)/! 首先要注册一个邮箱,在邮箱设置里开通smtp功能. 简单介绍下smtp,大概就是第三方客户端登录邮箱的功能.打开smtp功能,我们的项目里的邮箱类就可以充当邮箱客户端使用,从而发送信息了.(但要注意,密码将不是邮箱的登录密码.而是邮箱生成授权码或者自己设置的授权码) 下面是干货 <? class SmtpAction extends Action { /* Public Variable