概述

本篇是“练习项目”系列的第二篇,主要介绍一下利用消融实现的效果。在游戏开发的过程中,有很多看起来很神奇的效果,都是使用消融的原理实现的。

原理

主要的原理,就是使用噪声图和透明度测试,根据噪声图中采样的值,对某些像素进行剔除。

1、基本原理实现

这里会实现一个最基础的项目,来简单了解消融的基本原理。主要的代码如下:

float cutout = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, input.uv.zw).r;
AlphaDiscard(cutout, _Threshold);

注意,这里要使用AlphaDiscard方法的话,必须设置正确的KeyWord。

代码

2、边缘颜色

在上面的动图中可以看到,只是简单实现了消融,但看起来效果不太好,比较单调。下面将使用几种方式来丰富效果。

2.1 纯颜色

第一种实现方式比较简单,只是在未消融的边界留下一段缓冲,显示边界的颜色。这里需要开放两个属性接口:_EdgeLength、_EdgeColor。即边缘长度和边缘颜色。先根据噪声图进行透明度剔除,然后根据透明度确定一段范围内显示边界的颜色。代码如下:

float cutout = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, input.uv.zw).r;
AlphaDiscard(cutout, _Threshold);if (cutout - _Threshold < _EdgeLength)return _EdgeColor;

代码

2.2 两种颜色混合

一种颜色的效果看起来还是有点单调,使用两种颜色混合的效果可能会更好。根据_EdgeLength可以确定一个“边界”范围。“边界”与剔除区域的交界可以使用第一种颜色,“边界”与正常区域的交界可以使用第二种颜色,而在“边界”内部,则可以在第一种颜色和第二种颜色之间进行插值。代码如下:

float cutout = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, input.uv.zw).r;
AlphaDiscard(cutout, _Threshold);if (cutout - _Threshold < _EdgeLength)
{float degree = (cutout - _Threshold) / _EdgeLength;return lerp(_EdgeFirstColor, _EdgeSecondColor, degree);
}

代码

2.3 边界颜色混合物体颜色

从上面的动图可以看到,在“边界”区域只是边界的颜色,看起来有点不自然。下一步,就是对边界颜色和物体颜色进行混合,从而看起来更加地自然。主要代码如下:

float cutout = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, input.uv.zw).r;
AlphaDiscard(cutout, _Threshold);float degree = saturate((cutout - _Threshold) / _EdgeLength);
half4 edgeColor = lerp(_EdgeFirstColor, _EdgeSecondColor, degree);half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv.xy);half4 finalColor = lerp(edgeColor, col, degree);

在上面的代码中,degree的范围是[0,1],剔除区域是0,正常区域是1,而在“边界”区域,则在[0,1]之间。使用degree进行第一次插值,得到边界颜色,第二次插值,则混合了边界颜色和物体本身的颜色。

代码

2.4 使用渐变纹理

为了让“边界”颜色更加丰富,可以使用渐变纹理。

然后就可以使用degree对渐变纹理进行采样,来得到边界的颜色。得到边界颜色后,与物体本身的颜色混合的过程,就与上面相同了。主要代码如下:

float cutout = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, input.uv.zw).r;
AlphaDiscard(cutout, _Threshold);float degree = saturate((cutout - _Threshold) / _EdgeLength);
half4 edgeColor = SAMPLE_TEXTURE2D(_RampTex, sampler_RampTex, float2(degree, degree));half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv.xy);half4 finalColor = lerp(edgeColor, col, degree);

代码

3、从特定点开始消融

为了从特定点开始消融,必须将片元到特定点的距离考虑进来。

第一步,定义消融开始点的属性,该属性是在世界空间中定义的。在顶点着色器中将该点转换到物体的本地空间,然后将顶点的本地坐标和该点的本地空间坐标传递给片元着色器。在片元着色器中求出片元到该点的距离。代码如下:

//Properties
_StartPoint("Start Point",Vector) = (1,1,1,1)   //需要找到该点的世界坐标//Vert
output.objPos = input.positionOS.xyz;
output.objStartPos = TransformWorldToObject(_StartPoint.xyz);//Frag
float distance = length(input.objPos - input.objStartPos);

第二步,求出网格内任意两点之间的最大距离,用来对上面求出的距离进行归一化处理。这一步需要在C#中实现,思路是遍历任意两点,然后求出最大距离。这里求出的是网格内任意两点之间的最大距离,所以上面定义的消融开始点最好在网格上面,这样效果才是对的。代码如下:

public class Dissolve : MonoBehaviour {void Start () {Material mat = GetComponent<MeshRenderer> ().material;mat.SetFloat ("_MaxDistance", CalculateMaxDistance ());}float CalculateMaxDistance () {float maxDistance = 0;Vector3[] vertices = GetComponent<MeshFilter> ().mesh.vertices;for (int i = 0; i < vertices.Length; i++) {Vector3 v1 = vertices[i];for (int k = 0; k < vertices.Length; k++) {if (i == k) continue;Vector3 v2 = vertices[k];float mag = (v1 - v2).magnitude;if (maxDistance < mag) maxDistance = mag;}}return maxDistance;}
}

同时,也要定义_MaxDistance属性来存放最大距离值。

_MaxDistance("Max Distance",Float) = 0

第三步就是归一化距离值。

float normalizedDistance = saturate(distance / _MaxDistance);

第四步是定义_DistanceEffect属性,来控制距离对整个消融效果的影响程度。

//Properties
_DistanceEffect("Distance Effect",Range(0,1)) = 0.5//Frag
float cutout = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, input.uv.zw).r * (1.0 - _DistanceEffect) + normalizedDistance * _DistanceEffect;
AlphaDiscard(cutout, _Threshold);

代码

4、应用:场景切换

利用上面的从特定点开始消融的原理,我们可以用来实现场景切换的效果。

如下图所示,就是我们要实现的效果。

因为我们在上面实现的是从特点点开始消融,而上图是从从外部向特定点开始消融,所以这里要做一些修改。

float normalizedDistance = 1.0 - saturate(distance / _MaxDistance);

这样,就会从四周向中心点开始消融了。

然后,我们的距离是在局部空间计算的。但是这里有很多物体,再使用局部空间的话,就不太方便,所以,这里转到世界空间计算。

//Vert
output.worldPos = TransformObjectToWorld(input.positionOS.xyz);
//Frag
float distance = length(input.worldPos - _StartPoint.xyz);

接下来,需要获得场景所有物体的顶点到消融点的最大距离,用来对上面的距离做归一化处理,这一步,需要在C#中处理,代码在这里。

这样,场景中建一个空物体Environment,然后给Environment添加上面的C#脚本,再把其它物体都放到Environment下面即可。

代码

5、从特定方向开始消融

理解了上面的从特定点开始消融,那么这里的从特定方向开始消融就很好理解了。

这里实行的是从X方向消融。

第一步,求出X方向的边界,传递给Shader。

public class DissolveDirection : MonoBehaviour {void Start () {Material mat = GetComponent<Renderer>().material;float minX, maxX;CalculateMinMaxX(out minX, out maxX);mat.SetFloat("_MinBorderX", minX);mat.SetFloat("_MaxBorderX", maxX);}void CalculateMinMaxX(out float minX, out float maxX){Vector3[] vertices = GetComponent<MeshFilter>().mesh.vertices;minX = maxX = vertices[0].x;for(int i = 1; i < vertices.Length; i++){float x = vertices[i].x;if (x < minX)minX = x;if (x > maxX)maxX = x;}}
}

第二步,定义从X的正方向还是负方向开始消融,确定边界,然后求出各个片元在X方向上与边界的距离。再进行归一化处理。

float range = _MaxBorderX - _MinBorderX;
float border = _MinBorderX;
if (_Direction == 1) //1表示从X正方向开始,其他值则从负方向border = _MaxBorderX;float distance = abs(input.objPosX - border);
float normalizedDistance = saturate(distance / range);

代码

6、灰烬飞散效果

第一步,灰烬向特定方向飞散。这一步可以在顶点着色器中通过顶点动画实现。

float cutout = GetNormalizeDistance(output.positionWS.y);
float3 localFlyDirection = TransformWorldToObjectDir(_FlyDirection.xyz);
float flyDegree = (_Threshold- cutout) / _EdgeLength;
float val = saturate(flyDegree * _FlyIntensity);
input.positionOS.xyz += localFlyDirection * val;

第二步,从特定方向开始消融。上面已经介绍了。这里注意,因为要生成灰烬的效果,所以要延迟透明度剔除的时机。

float edgeCutout = cutout - _Threshold;
clip(edgeCutout + _AshWidth);

这样,可以在消融边缘留下大片的颜色。而我们需要的是细碎的灰烬,所以需要再次使用噪声图对这片颜色区域进行消融处理。

if(degree < 0.001)
{clip(whiteNoise * _AshDensity + normalizedDistance * _DistanceEffect - _Threshold);finalColor = _AshColor;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZSKmByXl-1614487076825)(https://cdn.jsdelivr.net/gh/bzyzhang/ImgHosting//img/2020-11-28/20201128210450.gif)]

代码

7、镜头遮挡消融

这里要实现的,是当角色和镜头之间有障碍物时,对障碍物进行消融处理。

第一步,将角色的坐标传递给Shader,这一步是在C#中实现的。

public class SendPlayerPos : MonoBehaviour {public Transform player;public Material blockMat;void Update () {blockMat.SetVector ("_PlayerPos", player.position);}
}

第二步,使用屏幕空间的遮罩纹理,对消融区域进行控制。对角色和镜头之间的片元,进行剔除处理。

float toCamera = distance(input.positionWS, _WorldSpaceCameraPos);
float playerToCamera = distance(_PlayerPos.xyz, _WorldSpaceCameraPos);float2 wcoord = input.positionNDC.xy / input.positionNDC.w;
float mask = SAMPLE_TEXTURE2D(_ScreenSpaceMaskTex, sampler_ScreenSpaceMaskTex, wcoord).r;
half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
float gradient = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, input.uv).r;if (toCamera < playerToCamera)clip(gradient - mask + (toCamera - _WorkDistance) / _WorkDistance);

代码

参考

  • [1] Unity Shader - 消融效果原理与变体
  • [2] 《Unity Shader入门精要​》
  • [3] Unity技术分享 |《Trifox》中的遮挡处理和溶解着色器(上)
  • [4] A Burning Paper Shader
  • [5] Tutorial - Burning Edges Dissolve Shader in Unity

练习项目(二):消融效果相关推荐

  1. 表决器c语言课程设计,项目二:玩转RGB点阵屏——表情表决器

    项目二:玩转RGB点阵屏--表情表决器项目二:玩转RGB点阵屏--表情表决器(建议2课时) [情境导入] 图2.1 医护人员"逆行"湖北 是她们不畏生死驰援湖北,为中国抗疫带来胜利 ...

  2. Vue购物商城项目(二) 数据请求使用

    Vue购物商城项目(二) 文章目录 Vue购物商城项目(二) 前言 一.请求数据 request.js home.js Home.vue 二.使用数据 总结 前言 1.这里面包含了大量的.我的个人理解 ...

  3. 常见的预设分栏包括_计算机应用基础_实训项目二Word综合应用

    . 专业学习资料 . 实训项目二 Word 综合应用示例 实训项目二 Word 综合应用 实训满分 20 分 . 以日常应用为基础 , 设计一个综合运用 Word 基本操作技能解决实际问题的文档 . ...

  4. 计算机基础实训项目二 Word 综合应用,计算机应用基础-实训项目二 Word 综合应用[优质文档]...

    实训项目二Word 综合应用 实训满分20分. 以日常应用为基础,设计一个综合运用Word 基本操作技能解决实际问题的文档.文档内容要求包括以下基本操作和元素: 标题.正文.页眉/页脚/页码.首行缩进 ...

  5. 计算机应用基础模块三项目二,计算机应用基础 高职计算机大类专业 刁爱军模块三 项目二 海报的制作.pptx...

    计算机应用基础 高职计算机大类专业 刁爱军模块三 项目二 海报的制作.pptx (31页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.90 积分 模块 ...

  6. 【项目二、蜂巢检测项目】一、串讲各类经典的卷积网络:InceptionV1-V4、ResNetV1-V2、MobileNetV1-V3、ShuffleNetV1-V2、ResNeXt、Xception

    目录 前言 一.InceptionV1-V4 1.1.InceptionV1(GoogLeNet) - 2014 1.2.InceptionV2.InceptionV3 - 2015 1.3.Ince ...

  7. 信创操作系统--麒麟Kylin桌面版 (项目二 桌面环境)

    信创操作系统–麒麟Kylin桌面版 (项目二 桌面环境) 目录 桌面布局 新建文件夹/文档 设置排序方式 调整图标 设置显示器 壁纸与屏保 剪贴板 任务栏 回收站 开始菜单 开始菜单模式 应用管理 窗 ...

  8. 项目二 PLC与RobotStudio联合仿真激光切割工作站——仿真模型搭建

    项目二 PLC与RobotStudio联合仿真激光切割工作站--仿真模型搭建 一.任务描述 上图给出了整个任务的描述和基础分析.本任务牵涉到两台机器人联合仿真,整体思路有很多种.这里为了配合PLC练习 ...

  9. CocosCreator消融效果

    效果预览 前期准备 首先我们准备一张噪声图用于后续的噪声消融 核心思路 片段着色器中有一个discard可以将片元的颜色丢弃,那我们的可以读取当前片元的某一个颜色基色(r.g.b),与我们的消融阈值b ...

最新文章

  1. 获取用户电脑的上网IP地址
  2. 系统启动时,spring配置文件解析失败,报”cvc-elt.1: 找不到元素 'beans' 的声明“异常...
  3. 在VMware Workstation中安装Ubuntu设置网络连接
  4. boost::make_tuple用法的测试程序
  5. VMware 扩展磁盘容量
  6. MVC之排球比赛计分程序 ——(二)架构概要设计
  7. MySQL查询更新所有满足条件的数据
  8. 一个页面同时发起多个ajax请求,会出现阻塞情况
  9. 工作总结8:关于Vue中的slot-scope=“scope“
  10. Oracle对表空间操作的sql
  11. java 中反射的使用_java中反射的基本使用
  12. 【白皮书分享】2022新职业教育洞察白皮书:“职”成机遇,“育”见未来.pdf...
  13. java 通过类名创建类,通过类名动态生成对象
  14. 在AIX 5.3+HACMP 5.4以上环境安装10gR2 10.2.0.1 RAC CRS Clusterware必须先运行Patch 6718715中的rootpre.sh...
  15. 刮刮乐html5效果擦除,HTML5实现刮刮卡的效果
  16. 怎么不能锁门_镜子能不能对着床
  17. 【谷粒商城】k8s、devops集群篇(4/4)
  18. ArcGIS 各版本产品补丁荟萃
  19. 异数OS-星星之火(二)--远程实验室注册开放
  20. 一文让你彻底弄清failfast、failsafe、failover、failback、failsilent

热门文章

  1. 栈溢出漏洞CVE-2020-8423复现
  2. 错误:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server vers
  3. mysql查询逗号隔开的字段
  4. 隐藏CNZZ统计代码
  5. 五年磨一剑,QUI框架V3.2完美推出
  6. MACBook 空间整理
  7. STC15单片机6路专用PWM
  8. 数据分析1 -- 数据集的获取
  9. Android学习笔记之 仿QQ登录界面的实现
  10. WebRTC信令服务器