当前位置:网站首页>Unity中实现溶解(Dissolve)特效及其原理解析
Unity中实现溶解(Dissolve)特效及其原理解析
2022-06-30 06:51:00 【拂面清风三点水】
Unity中实现溶解(Dissolve)特效及其原理解析
今天我们分享一个Unity中非常常见的特效: 溶解.
下面先来看看效果.

大家可能和我一样, 在不了解实现方式的时候, 会觉得这个效果很神奇, 实现起来十分复杂.
但是一旦你了解之后, 会觉得…更神奇, 简单到神奇.
溶解效果的原理和其实现
溶解特效的实现原理非常非常简单, 一句话概况就是: 给定一个变化量, 在值变化时, 抛弃对象的一部分像素不进行渲染.
所谓给定一个变化量, 我们可以将其抽象为一个进度条Slider, 代表溶解程度, 从0到1, 0代表一点都不溶解, 1代表全部溶解.
也就是说, Slider从0到1, 溶解效果从无到有.
那么怎么做到抛弃对象一部分像素不进行渲染呢.
依然很简单, 在片段着色器中使用clip函数, 抛弃掉不满足要求的片段.
clip(value)函数的效果是: 当传入的value小于0时, 则抛弃本片段, 内部的实现类似:
void clip(int value)
{
if (value < 0)
discard;
}
那么我们唯一的问题就是这个value该怎么传了.
我们通过Slider取值, 作为一个阈值(threshold value), 所有小于该阈值的片段颜色(任选颜色向量x, y, z, w的一个值作为比较)丢弃.
fixed4 color = tex2D(_MainTex, data.uv);
clip(color.r - threshold);
这样, 随着阈值的增大, 对象身上的颜色值大的片段会慢慢被丢弃, 在视觉上就形成了溶解效果. 代码如下:
Shader "Dissolve_Origin"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
// 通过Slider取阈值
_DissolveThreshold("DissolveThreshold", Range(0, 1)) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _DissolveThreshold;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed4 dissolveCol = col;
// 从噪声纹理采样颜色, 如果该值[小于阈值]则丢弃本片段
// 比如阈值为0.1, 则在噪声纹理上采样的所有像素r值小于0.1的片段都会被丢弃
// 即噪声纹理上偏黑的颜色(->0)首先开始溶解, 偏白的颜色(->1)最后溶解
clip(dissolveCol.r - _DissolveThreshold);
return col;
}
ENDCG
}
}
}
大家可以看到, 只是在最基本的着色器代码上加了区区4行代码就达到的一个酷炫的效果, 甚至真正起效的只有一行代码.

这个效果和第一张图有所差别, 是因为仅仅使用了对象自身的纹理信息, 效果比较受限.
业界常用的实现是还需要添加另一张噪声纹理, 用来指定溶解的区域和程度, 我们下面就开始介绍.
使用噪声纹理指定溶解信息
首先我们将纹理直接替换为另一张纹理, Shader不做任何变化, 可以看到下面的效果:

可以看到溶解是从黑色(0, 0, 0)的部分开始的, 渐渐溶解到白色的部分.
如果将对象的纹理信息和溶解信息分开, 也就是说使用另一张"溶解纹理(实际上被称为噪声纹理)", 我们就可以操作溶解的区域和速度.
噪声纹理的用途可谓是十分广, 很多特效都是使用噪声纹理, 比如水的流动, 旗帜的飘动, 裂缝等, 后面有机会我们会一一看到.
这里简单理解噪声纹理的意义就是: 将原来对象的纹理进行"扰动", 这些扰动信息使用单独的一张纹理来表示.
那么这是怎么实现呢?
其实也很简单, 在片段着色器中对对象本身的纹理正常采样, 然后使用同一个uv坐标在噪声纹理上采样, 使用该值来判断是否丢弃:
fixed4 frag (v2f i) : SV_Target
{
fixed4 dissolveCol = tex2D(_DissolveTex, i.uv);
// 从噪声纹理采样颜色, 如果该值[小于阈值]则丢弃本片段
// 比如阈值为0.1, 则在噪声纹理上采样的所有像素r值小于0.1的片段都会被丢弃
// 即噪声纹理上偏黑的颜色(->0)首先开始溶解, 偏白的颜色(->1)最后溶解
clip(dissolveCol.r - _DissolveThreshold);
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
相应的Shader属性面板如下:

这样就可以获得和第一张图一样的效果了, 从指定的位置开始溶解.
细心的同学可能看到, 最终效果会从怪物的嘴巴部分开始溶解, 但是噪声纹理最黑的部分明明是左下角:

这是因为本文使用的怪物纹理是基于PBR制作的, 和普通的纹理布局不太一样, 大家在实验的时候, 找一个正常的纹理就行了.
或者制作噪声纹理时也使用PBR的方式制作也可以达到相同的目的, 这里我是为了说明这种情况, 故意如此.
下面是完整的代码:
Shader "Dissolve"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_DissolveTex("DissolveTex", 2D) = "white" {}
_DissolveThreshold("DissolveThreshold", Range(0, 1)) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DissolveTex;
fixed _DissolveThreshold;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 dissolveCol = tex2D(_DissolveTex, i.uv);
// 从噪声纹理采样颜色, 如果该值[小于阈值]则丢弃本片段
// 比如阈值为0.1, 则在噪声纹理上采样的所有像素r值小于0.1的片段都会被丢弃
// 即噪声纹理上偏黑的颜色(->0)首先开始溶解, 偏白的颜色(->1)最后溶解
clip(dissolveCol.r - _DissolveThreshold);
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
总结
今天我们介绍了游戏中比较常见的溶解特效, 比如怪物在被击杀后, 可以溶解消失, 或者角色穿过传送门, 溶解消失等.
对于初次接触的同学来说, 溶解特效比较酷炫, 但是实现却超级简单, 不需要复杂的数学知识和图形学知识, 我认为这是一个非常好的学习Shader示例, 所以在此特意共享给大家.
后续我可能也会继续给大家分享一些简单却有意思的Shader, 让大家领略Shader的魅力, 坚定学习下去的信心.
我认为图形学的基础固然重要, 但是一上来就各种矩阵, 各种管线, 容易让人产生劝退效果, 所以我更喜欢从一些简单的特效来学习, 在学习和实现了效果之后, 再去探究其背后的原理, 这样比较容易产生成果, 也更能加深理解.
我觉得对于前端的同学, 做出各种绚丽的特效也是大家最初想做游戏的目的之一 , 不然做服务器不是更舒服? 虽然做游戏之后才知道, 这部分是美术的活儿, 哈哈.
好了, 今天就是这些啦, 希望对大家有所帮助.
边栏推荐
- 原理:WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南
- [Hot100]10. 正则表达式匹配
- 手机开户一般哪个证券公司好?还有,在线开户安全么?
- RT thread migration to s5p4418 (III): static memory pool management
- Introduction to neural networks
- Getting started with research
- 1.9 - Cache
- MySQL中的InnoDB引擎
- How to set the hot deployment of idea web project
- 成品升级程序
猜你喜欢

Why does ETL often become ELT or even let?

Connect to remote server

Principle: webmvcconfigurer and webmvcconfigurationsupport pit avoidance Guide

1.9 - Cache

Go installation and configuration (1)

Never forget the original intention, and be lazy if you can: C # operate word files

MySQL Optimization: from more than ten seconds to 300 milliseconds

Judge whether H5 is in wechat environment or enterprise wechat environment at both ends

记录一次腾讯测试开发工程师自动化接口测试实践经验

RT thread Kernel Implementation (V): timer
随机推荐
【模糊神经网络】基于模糊神经网络的移动机器人路径规划
不忘初心,能偷懒就偷懒:C#操作Word文件
Getting started with research
File transfer protocol, FTP file sharing server
Hao looking for a job
随机网络,无标度网络,小世界网络以及NS小世界的性能对比matlab仿真
Introduction to neural networks
Bat 使用细节2
Browser downloads files as attachments
Practice summary of Prometheus project in amu Laboratory
0 basic job transfer software test, how to achieve a monthly salary of 9.5k+
阿里云买的40G高效云盘挂载只有20G
神经网络入门
手机开户一般哪个证券公司好?还有,在线开户安全么?
Deep learning --- the weight of the three good students' scores (3)
Ffmplay is not generated during the compilation and installation of ffmpeg source code
memcpy内存重叠的解决
ROS service communication programming
Wuenda coursera deep learning course
Principle: webmvcconfigurer and webmvcconfigurationsupport pit avoidance Guide