UE4_后期处理_后期处理材质及后期处理体积三—遮挡物体描边显示

news/2024/9/16 17:10:28/ 标签: ue4, 材质

一、效果:

在很多游戏中为了玩家能看到墙面背后是否有敌人,会给被遮挡的敌人增加描边显示,效果如下:

参考:

https://zhuanlan.zhihu.com/p/81310476

https://zhuanlan.zhihu.com/p/358140547

二、所需知识

知识点梳理

1、PixelDepth 像素深度

当前被渲染的这个像素点与摄像机的距离。该节点没有输入接口,说明这个节点不能够获取特定位置的深度,只能获取像素着色器目前处理的这个像素点。

最基础的深度概念,我们说起深度时默认指的就是PixelDepth。

2、SceneDepth 场景深度

场景深度,当前场景的深度信息映射到屏幕上的一张图,从输入值有UV这一点来看就知道它是基于屏幕UV且可以获取非当前像素深度的。比较经常用在屏幕后处理里面。

3、CustomDepth 自定义深度

通过SceneTexture节点获取,用在屏幕后处理中,只需要在指定的物体上开启“渲染自定义深度通道”即“Render Custom Depth”,该物体的PixelDepth就会被渲染到一张单独的Buffer中。

这张Buffer是一张与SceneDepth很相似的Buffer,不同的地方在于它将没有开启CustomDepth的区域扣掉了,用一个极大的值去填充(10^8),得到了一张只有CustomDepth区域有效的Buffer。

假设场景中只有一个物体开启了自定义深度,整个场景的自定义深度应该是这样的:

4、CustomStencil/CustomDepthStencil 自定义模具/自定义深度模具

不要被它称呼中带有的Depth迷惑了(血泪教训),它根本不是深度值,而是一个模板值,这个模板值就是在细节面板设置的一个1-255的整数值,从个人的使用体验来讲它就像是一个图层的标识,可以将物体分类处理。

各蓝图节点之间的区别:

PixelDepth VS SceneDepth

SceneDepth很好理解,就是一张写入了屏幕上每一个像素距离摄像机的距离的图片,可以找到很多示例,注意深度值一般要除以3000左右的数值来使深度值在0-1范围内才能直接输出到材质的BaseColor节点上测试。

而PixelDepth不是一张图,只是一个点而已,它对其他像素的深度一无所知。

SceneDepth VS CustomDepth、

就是把不需要的地方涂掉,看图就比较好理解了。

CustomDepth VS CustomStencil

假设图中三个物体都被开启了在CustomDepth通道中渲染,并且设置了不同的模板值,那么在材质里就可以获取它们的模板值并且分别处理。

说明

在视口左上角的视图模式可以在缓冲显示的子菜单里找到CustomDepth和CustomStencil的可视化,可以通过这个菜单检查自定义深度和模具开启情况和具体数值。注意在ES3.1情况下是看不到缓冲可视化的,记得关闭ES3.1再进行检查。

启用CustomDepth需要在项目设置-Rendering-Postprocessing中启用自定义深度-模具通道

这里深度和模具是分开开启的,“已启用”选项意味着只启用深度而禁用模具,需要注意有一下,如果设置了模板、能够看到自定义深度,却看不到模板可视化图像,可以检查一下项目设置。(以模具开启)。

三、分析

要找到物体的边缘边界,假设这是场景的自定义深度图,每一格是一个像素,里面存放着各个像素点的自定义深度值 

我们看到的物体内部是蓝色数值,红色的就是我们需要的边,正无穷就是没有开启自定义深度的物体外部

判定物体的边有很多种方法,我们要先搞清楚以下几点:

 a.物体的内部:可以获取到自定义深度的数值,上下左右4个像素点都可以获取自定义深度

       b.物体的边缘:可以获取到自定义深度的数值,上下左右4个像素点不全都能获取到自定义深度

       c.物体的外部:自定义深度的数值为正无穷,上下左右4个像素点不全都能获取到自定义深度

       通过上述规律,我们可以用这种方法确定物体的边界:当一个像素点自身的自定义深度值不为正无穷,但上下左右四个像素点的和却为正无穷时,这个像素点就是物体的边(UE4中没有正无穷,所以用一个很大的数来近似判定是否为正无穷)

       而在UE4中SceneTextureCustomDepth(自定义深度)就是用来输出这张图的 。效果验证图如下:

但是直接连接的话由于数值都大于1,所以都显示为白色,需要除以一个很大的数来把数值控制在0-1之间才能正确显示我们需要的结果

       

四、步骤:

了解了原理后,我们开始制作描边效果。

1、创建后期材质

创建一个新的材质球,在参数中修改为后期处理与色调映射前 

2、添加屏幕位置ScreenPosition节点

屏幕uv是这样的,先创建一个ScreenPosition(屏幕位置)节点,ScreenPosition的原点在屏幕左上角。

ScreenPosition蓝图节点的ViewportUV引脚输出的是每个像素点在屏幕上的UV值(2维数组),取值范围是0~1,等于是每个像素点的UV都获取一次,然后进行处理,连接到自发光可以看到,横坐标为R值纵坐标为G值,右上角为(1,0)显示红色,左下角为(0,1)显示绿色,右下角为(1,1)显示黄色(红+绿为黄色) 

ScreenPosition蓝图节点的PixelPosition引脚输出的是每个像素点在屏幕上的位置坐标,取值范围是0~屏幕尺寸,直接连接到自发光可以看到画面偏亮,但不是纯白色 

而当我们把这个值除以1000后,画面的颜色与ViewportUV接近 

3、理解SceneTexelSize场景纹素大小并使用

我们再创建一个SceneTexelSize(场景纹素大小),这也是一个2维数组的值,对应着UV(u,v),uv均为正数,这里u就代表着要在横向偏移一个像素单位需要增加或者减少多少,v也同理

       比如你的屏幕是1920*1080的,那么你屏幕的横向上就有1920个像素,U的取值区间是0~1,那么横向上每个像素就占1/1920≈0.000521,同理纵向上每个像素就占1/1080≈0.000926,那么SceneTexelSize的值就为(0.000521,0.000926)。

  举个例子,比如现在有个像素点的uv为(0.2,0.6),那么这个像素上方的像素点则为

(0.2,0.6-0.000926),下方则为(0.2,0.6+0.000926),左右同理(因为UE4中uv坐标系原点在左上角,所以这里向上为减,向下为加)

       上述的结论可以由PixelPosition与SceneTexelSize相乘得到的结果验证 

SceneTexture:PostProcessInput0(后期处理输入0)节点:这个节点其实就是SceneColor(场景本来的颜色),而SceneColor只能用于材质域为Surface(表面)的材质,所以这里用的是SceneTexture:后期处理输入0 

观察场景没有变化。

理解了这些节点之后,我们就可以通过这些节点来计算出各个自定义深度像素点的上下左右4个像素点之和了。如下图所示:

 4、判断上下左右四个深度之和是否是无穷大

然后我们再把算出来的和跟一个近似无穷大的数作比较,如果大于近似无穷大的数则为自定义模具物体的边与外部,给它一个颜色值(这里我用了黄色),如果小于近似无穷大的数则为自定义模具物体内部,给它场景原本的颜色 。蓝图节点如下图:

5、使用后期材质观察效果

(一定要注意蓝图节点输出数据的维数):

6、使用自定义模具作为选区使用

从上面结果上看,我们现在已把开启自定义深度的物体外部和物体边缘显示了黄色,物体内部显示了本来颜色,现在我们需要把物体外部排除掉,让它也显示原本的颜色(自定义模具正好能够得到这么个选区)。

实现的蓝图节点如下图:

注意:项目设置中不要忘了以模具开启:

得到的效果如下:

7、添加遮挡判断

现在的结果是比较接近目的了,但是我们需要的是被挡住的才能显示,所以还得加上判断:

通过上面的区别我们知道了customDepth与scenedepth的区别,通过下图,我们能更加直观的区分开:

SceneDepth(场景深度):当前画面上的像素点和摄像机之间的距离,这是从你看得到的地方开始算的,比如摄像机镜头正对着一面墙,墙后有个自定义深度的立方体,那么获取到的场景深度就是黑色虚线的长度(墙到摄像机之间的距离),跟立方体无关。

       CustomDepth(自定义深度):想获得被遮挡的物体离相机的距离,要开启物体上的自定义深度通道,如果在UV对应的像素点方向上有物体开启了自定义深度,即使被遮挡也可以获取到它的场景深度。如果该位置没有物体开启自定义深度,那么得到的值则是无穷大。

       所以我们就可以根据自定义深度(绿色虚线)和场景深度(黑色虚线)的差值来判断是否有东西被遮挡住(如果有两个开启了自定义深度通道的物体在一条线上的话,那么获取到的CustomDepth是离摄像机更近的那个)。

CustomDepth-SceneDepth的差

       (1)如果开启CustomDepth被挡住,那么CustomDepth>SceneDepth,CustomDepth-SceneDepth=有限值

       (2)如果开启CustomDepth没被挡住,那么CustomDepth=SceneDepth=0

       (3)如果没有开启CustomDepth,那么CustomDepth-SceneDepth=无穷大

       结论:

当<=0时,也就是物体没有被遮挡,那么用原本的颜色即SceneTexture后期处理输入0的Color值;

当0<差值<9999999时,说明物体开启了自定义深度并且被挡住了,输出之前得到的描边;

当>9999999时,也就是为正无穷,说明没有物体开启自定义深度通道,也是用原本的颜色。

但是由于上一步中我们已经用SceneTexture自定义模具判断是否开启自定义深度通道了,所以我们下一步只需要判断是否遮挡就可以了:

8、效果如图:

  五、拓展

1、亮度分层

现在完全达到了我们需要的效果,只有遮挡的部分会显示描边,但是在上一章中我们知道了,当我们调整自定义深度模具值后,亮度会变化,因为自定义模具只是返回一个数值就是模具值,开具自定义深度并有模具值的才显示这个颜色灰阶,其它显示黑色,这会使效果更佳有趣,可是如果我们不需要亮度增加的话,我们设置自定义深度模具值为1就可以。

2、描边宽度

可以添加一个Width参数,这个参数与SceneTexelSize相乘,就可以调节描边的粗细了,就是通过改变偏移的像素数量来控制描边粗细。蓝图节点如下:


http://www.ppmy.cn/news/1522900.html

相关文章

3.C_数据结构_栈

概述 什么是栈&#xff1a; 栈又称堆栈&#xff0c;是限定在一段进行插入和删除操作的线性表。具有后进先出(LIFO)的特点。 相关名词&#xff1a; 栈顶&#xff1a;允许操作的一端栈底&#xff1a;不允许操作的一端空栈&#xff1a;没有元素的栈 栈的作用&#xff1a; 可…

如何在 Linux 系统中禁用用户登录 ?

管理 Linux 系统上的帐户是系统管理员的一项重要任务。一个常见的任务是禁用帐户&#xff0c;由于各种原因可能需要禁用帐户&#xff0c;例如当员工离开公司或出于安全目的需要临时禁用访问时。 本指南将以简单易懂的步骤引导您完成在 Linux 系统上禁用帐户的过程。 Step 1: …

2024.9.8

打了一上午又一下午的比赛 DABOI Round 1 【MX-X3】梦熊周赛 未来组 3 & RiOI Round 4 第一场还好&#xff0c;共得180pts 难度比较合理&#xff0c;偏向正常noip 然后就发现自己计数问题很难做到推广思路&#xff0c;只会部分分 梦熊的模拟赛就抽象了 题目难度夸大…

IDEA安装教程配置java环境(超详细)

引言 IntelliJ IDEA 是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;广泛用于 Java 开发&#xff0c;但也支持多种编程语言&#xff0c;如 Kotlin、Groovy 和 Scala。本文将为你提供一步一步的指南&#xff0c;帮助你在 Windows 系统上顺利安装 Intelli…

Qt:解决player->duration()第一次获取媒体时长为0的问题

前言 最近想做一个白噪声播放器&#xff0c;中间就用到了QMediaplayer这个类&#xff0c;其中遇到两个问题&#xff0c;一个是未初始化好就调用player->state()导致程序异常崩溃的问题(这个问题留到下一个文章去说)&#xff1b;还有一个就是调用player->duration()第一次…

Mendix 创客访谈录|Mendix赋能汽车零部件行业:重塑架构,加速实践与数字化转型

在当前快速发展的技术时代&#xff0c;汽车行业正经历着前所未有的数字化转型。全球领先的汽车零配件制造商面临着如何利用最新的数字技术优化其制造车间管理的挑战。从设备主数据管理到生产执行工单管理&#xff0c;再到实时监控产量及能耗&#xff0c;需要一个灵活、快速且高…

基于单片机智能电源插座设计

本设计基于单片机智能电源插座设计&#xff0c;该系统主要包括&#xff1a;单片机、WIFI模块、显示模块、继电器模块、按键输入模块、功率检测模块及手机APP&#xff0c;实现对用电量的实时监测的功能。功率检测模块实时测量用电器的供电电压、电流、功率&#xff1b;按键输入模…

微信小程序:navigateTo跳转无效

关于 navigateTo 跳转无效问题&#xff0c;在IOS、模拟器上面都能正常跳转&#xff0c;但是在安卓上面不能跳转&#xff0c;过了一段时间IOS也不能跳转了。仔细找了下问题结果是要跳转的页面是tab&#xff0c;不能使用navigateTo 取跳转修改为&#xff1a; wx.switchTab({url:…

经验笔记:跨站脚本攻击(Cross-Site Scripting,简称XSS)

跨站脚本攻击&#xff08;Cross-Site Scripting&#xff0c;简称XSS&#xff09;经验笔记 跨站脚本攻击&#xff08;XSS&#xff1a;Cross-Site Scripting&#xff09;是一种常见的Web应用程序安全漏洞&#xff0c;它允许攻击者将恶意脚本注入到看起来来自可信网站的网页上。当…

Spring Boot集成PDFBox实现电子签章

概述 随着无纸化办公的普及&#xff0c;电子文档的使用越来越广泛。电子签章作为一种有效的身份验证方式&#xff0c;在很多场景下替代了传统的纸质文件签名。Apache PDFBox 是一个开源的Java库&#xff0c;可以用来渲染、生成、填写PDF文档等操作。本文将介绍如何使用Spring …

Socket编程 (连接,发送消息) (Tcp、Udp) - Part1

Socket编程 (连接,发送消息) (Tcp、Udp) 本篇文章主要实现Socket在Tcp\Udp协议下相互通讯的方式。(服务器端与客户端的通讯) 1.基于Tcp协议的Socket通讯类似于B/S架构&#xff0c;面向连接&#xff0c;但不同的是服务器端可以向客户端主动推送消息。 使用Tcp协议通讯需要具备…

HiveServer2 启动时 datanucleus.schema.autoCreateTables 不生效的问题

HiveServer2 启动时出 "Either your MetaData is incorrect, or you need to enable "datanucleus.schema.autoCreateTables"问题 Required table missing : "FUNCS" in Catalog "" Schema "". DataNucleus requires this table…

深入探索Go语言中的指针:内存操作的艺术

首先&#xff0c;尽管指针&#xff08;pointer&#xff09;和switch语句在概念上并无直接联系&#xff0c;但本文将它们并置讨论的原因在于&#xff1a;这两个编程概念在实际学习和应用过程中常被编程人员所忽视。 对于指针的使用&#xff0c;初学者往往因其概念的抽象性和操作…

探索Oracle数据库的多租户特性:架构、优势与实践

在云计算和大数据时代&#xff0c;多租户架构成为数据库设计中的一个重要趋势。Oracle数据库的多租户选项&#xff08;Multitenant&#xff09;允许单个数据库实例支持多个独立数据库&#xff08;称为容器数据库和可插拔数据库&#xff09;&#xff0c;每个数据库都有自己的数据…

Vue3:<Teleport>传送门组件的使用和注意事项

你好&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 Vue3 引入了一个新的内置组件 <Teleport>&#xff0c;它允许你将子组件树渲染到 DOM 中的另一个位置&#xff0c;而不是在父组件的模板中直接渲染。这对于需要跳出当前组件的 DOM 层级结构进行渲染的…

算法:判断一个整数是不是2的阶次方

一、思路 核心&#xff1a;不断除以2&#xff0c;缩小判断的范围 判断整数除以2的余数是否为0&#xff0c;如果不为0&#xff0c;则直接返回false&#xff1b;如果为0&#xff0c;则将将整数除以2后重复本步骤。 注意&#xff1a; 1为2的0次幂。 二、代码 public class Numb…

第十章 【后端】环境准备(10.2)——Maven

10.2 Maven Maven 官网:https://maven.apache.org/ Maven 仓库:https://mvnrepository.com/ 下载 解压 在非系统盘上创建仓库目录 如:E:\maven-repository 修改配置 配置文件为 Maven 目录的 conf\settings.xml,修改为: <?xml version="1.0" encoding=&qu…

25版王道数据结构课后习题详细分析 第八章 8.5 归并排序、基数排序和计数排序

一、单项选择题 ———————————————————— ———————————————————— 解析&#xff1a;我们知道插入排序不能保证在一趟排序结束后一定有元素放在最终位置上。事实上&#xff0c;归并排序也不能保证。例如&#xff0c;序列{6,5,7,8,2,1,4,3}…

【Linux 从基础到进阶】Redis缓存服务安装与调优

Redis缓存服务安装与调优 引言 Redis 是一个开源的内存数据结构存储系统,广泛应用于缓存、会话管理和实时分析等场景。它支持多种数据结构,如字符串、哈希、列表、集合和有序集合,因其高性能和灵活性,成为开发者的首选缓存解决方案。本文将介绍如何在 CentOS 和 Ubuntu 系…

Python | Leetcode Python题解之第387题字符串中的第一个唯一字符

题目&#xff1a; 题解&#xff1a; class Solution:def firstUniqChar(self, s: str) -> int:position dict()q collections.deque()n len(s)for i, ch in enumerate(s):if ch not in position:position[ch] iq.append((s[i], i))else:position[ch] -1while q and po…