Unity中实现溶解(Dissolve)特效及其原理解析

4 篇文章 1 订阅

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的魅力, 坚定学习下去的信心.

我认为图形学的基础固然重要, 但是一上来就各种矩阵, 各种管线, 容易让人产生劝退效果, 所以我更喜欢从一些简单的特效来学习, 在学习和实现了效果之后, 再去探究其背后的原理, 这样比较容易产生成果, 也更能加深理解.

我觉得对于前端的同学, 做出各种绚丽的特效也是大家最初想做游戏的目的之一 , 不然做服务器不是更舒服? 虽然做游戏之后才知道, 这部分是美术的活儿, 哈哈.

好了, 今天就是这些啦, 希望对大家有所帮助.

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Unity Shader Graph是Unity引擎的一种可视化编程工具,它可以用于创建自定义的着色器效果溶解特效是一种常见的特效,在游戏和动画经常使用。 要使用Unity Shader Graph实现溶解特效,我们需要做以下几个步骤: 1. 创建Shader Graph:打开Unity编辑器,创建一个新的Shader Graph。可以通过右键点击Assets面板的空白区域,选择Create->Shader->PBR Graph来创建一个新的Shader Graph。 2. 添加输入节点:在Shader Graph编辑器,我们需要添加溶解特效所需的输入节点。这些节点可能包括Texture2D用于溶解图案、Float用于控制溶解的进度等。 3. 控制溶解过程:在Shader Graph,我们可以使用节点连接和编辑来控制溶解特效的过程。例如,我们可以使用Lerp节点将溶解图案与原始纹理进行混合,实现溶解效果。 4. 添加溶解动画:通过使用Time节点,我们可以在Shader Graph添加时间变量,以使溶解过程可以动态进行,从而实现溶解特效的动画效果。通过控制Time节点的输入值,我们可以控制溶解特效的速度、方向等。 5. 调整其他属性:除了溶解图案和动画外,还可以通过Shader Graph调整其他属性,如颜色、透明度、光照等,以使溶解特效具有更多的变化和个性化。 6. 导入及应用Shader:将编写好的Shader Graph保存,然后将其导入Unity项目。之后,我们可以将其应用到需要溶解特效的材质上,以实现溶解特效效果。 总之,通过使用Unity Shader Graph,我们可以通过可视化编辑界面来快速创建和调整溶解特效。这种方法非常直观和灵活,使得艺术家和开发人员可以快速实现他们想要的效果

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拂面清风三点水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值