Esfog_UnityShader教程_溶解效果Dissolve
溶解效果在游戏中是很常见的,比如在一些神话或者魔法世界中,一些NPC角色在剧情需要时候会身体会渐渐的消失掉.甚至有一些更炫的,比如用火焰喷射器把目标燃尽。这些都可以用到溶解效果。这篇文章主要是讲解一下比较基础的溶解效果如何实现,实现的方法并不唯一,本篇只是其中一种思路。
原理
既然想让角色的身体一块块渐渐消失,不妨就让角色身体上相应的部位不进行渲染(或者改成透明,我们这里选择前者)。那根据什么来判断身体的哪一部分需要被溶解呢,这时候就需要一张额外的贴图或者利用角色纹理贴图的Alpha通道(本篇选择前者)。这个贴图和纹理贴图一样,对应着玩家身体的每一个位置,这样我们就可以根据贴图上某个指定通道的颜色值来控制角色各个身体部位是否溶解了。
另外我们还会涉及到的一个命令叫discard,是由CG提供的,若出现在fragmentShader中表示立即放弃当前处理的片元。也就是说当我们判定当前片远需要溶解的时候我们就使用discard命令。

上面这张图就是用来控制溶解程度的纹理,我们这里比较简单,只使用了R通道,如果你想做的很复杂也可以利用上其它的通道。在本篇中我们将根据时间的推进不断溶解掉贴图上R通道颜色值较小的区域。美术可以利用这张贴图控制角色的任意溶解顺序和效果。由于我的素材都是随便找的,自己又不会画画,所以这个图和角色纹理可能并不搭配,请不要在意。
再看下面这个图,我先来提前说一下本篇Shader在Properties中提供的各个可调节的参数

1.Base(RGB)是角色纹理贴图,不用解释了.
2.NoiseTex(R)是很重重要的,我们用来控制角色溶解的样式贴图,我们只利用了R通道。
3.DissolveSpeed(Second),整个溶解过程需要的时间,单位是秒
4.EdgeWidth,这个就是额外加的一个边缘效果,比如你观察纸在化作灰烬时他的周围会先变成黑褐色。我们这里的EdgeWidth就是定义这个周围区域的大小,注意这个width并不是指的长度,而是定义一个透明度的间隔区间,也就是与基准值相差多少可以算作边缘处理。
5.EdgeColor,和4一样,边缘效果的颜色。
实现
Shader "Esfog/Dissolve"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
_NoiseTex ("NoiseTex (R)",2D) = "white"{}
_DissolveSpeed ("DissolveSpeed (Second)",Float) =
_EdgeWidth("EdgeWidth",Range(,0.5)) = 0.1
_EdgeColor("EdgeColor",Color) = (,,,)
}
SubShader
{
Tags { "RenderType"="Opaque" } Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc" uniform sampler2D _MainTex;
uniform sampler2D _NoiseTex;
uniform float _DissolveSpeed;
uniform float _EdgeWidth;
uniform float4 _EdgeColor; float4 frag(v2f_img i):COLOR
{
float DissolveFactor = saturate(_Time.y / _DissolveSpeed);
float noiseValue = tex2D(_NoiseTex,i.uv).r;
if(noiseValue <= DissolveFactor)
{
discard;
} float4 texColor = tex2D(_MainTex,i.uv);
float EdgeFactor = saturate((noiseValue - DissolveFactor)/(_EdgeWidth*DissolveFactor));
float4 BlendColor = texColor * _EdgeColor; return lerp(texColor,BlendColor, - EdgeFactor);
} ENDCG
}
} FallBack Off
}
5~9行,前面解释过了,这里就不再说明了。
18行,这里我使用了unity提供的vert_img顶点着色器,因为我们的需求很简单,只需要进行顶点坐标变换以及把uv传给后面就行了,既然有现成的就不自己写了,它会自动把结果返回到一个v2f_img结构体中.
30行,这里的_Time.y就是从物体一开始渲染到现在所过去的时间unity给我们提供了几个不同的时间参数都保存在_Time中,其中_Time.y是标准的时间,单位(s)。用它去除以_DissolveSpeed.就能得到当前时间已经占用了多少总溶解时间.由于我们要保证比值范围限定在(0,1)的范围内,所以最后调用一个saturate()函数,这个函数式CG提供的就是来完成这个目的的。
31行,从溶解贴图里面取出r通道的值.
32~35行,我们利用刚才算出比值来对溶解贴图里面的R通道颜色值进行判断,如果R通道颜色值小于等于这个比值那么我们就通过discard抛弃当前片远,当前片远的处理会立刻结束。
38行,又是计算一个比值,分子是noiseValue - DissolveFactor,这个值表示溶解贴图上的R通道值和目前的溶解基准值相差多少,而(_EdgeWidth*DissolveFactor)可以这样理解,_EdgeWidth表示可以多大的差值可以算作是边缘,而乘以一个DissolveFactor,就表示边缘最大宽度会随着时间变化时间越长,宽度越宽。最后这两个值相除就代表当前片元的边缘程度,值越大表示离他被溶解掉的时间越长,反之表示他很快就要被溶解掉了.
39行,我们计算一下当前纹理颜色与边缘颜色相乘的值,后面需要用。
41行,这里我们用lerp函数来利用上一步计算出来的(1-EdgeFactor)对原始纹理颜色和上一步中的混合颜色进行一个插值,在解释第38行时候我们已经说了,EdgeFactor越小表示离溶解时间越近,也就是说它边缘化的颜色成分越重,那么由于lerp(x,y,a) = x*(1-a) + y*a;为了让边缘化的颜色重一些我们就使用1-EdgeFactor作为因子了,反之亦然。
好了看一下效果,使用不同的溶解贴图会产生完全不同的效果,下面展示一下我从网上随便找到的两个贴图,由于和原模型纹理并不是一套的,所以看上去会有点怪,不要在意。
使用这个贴图1:

效果如下

使用贴图2:

效果如下:

好了基本效果就是如此,总体来说这个Shader的效果看起来好与不好,主要还是取决于美术提供的溶解贴图是否合适,本节素材并不是一套的,看起来会有点怪。
另外一点就是大家在学习Shader的过程中你总会发现别人打源代码中会出现很多pow,lerp,或者对各个参数的加减乘除,希望大家不要太纠结这些地方的意义,有时候确实是有一定的数学原理,但很多时候都是开发者自己写的一个经验公式,为了调效果而写的。随着你的经验慢慢增多,渐渐的你也会开始使用一些经验公式。效果对了就好,只要不影响性能。毕竟给玩家看的又不是源代码。
尊重他人智慧成果,欢迎转载,请注明作者esfog,原文地址http://www.cnblogs.com/Esfog/p/4469025.html
Esfog_UnityShader教程_溶解效果Dissolve的更多相关文章
- Esfog_UnityShader教程_镜面反射SpecularReflection
系列教程第四篇,本来打算昨天写的,有些小偷懒就今天写了,这一期我们来讨论一下关于镜面反射的基本原理和具体代码.这一篇是承接着上一篇<Esfog_UnityShader教程_漫反射DiffuseR ...
- Esfog_UnityShader教程_前言
很多人在学习Unity的时候对Shader都是一知半解,作为刚入职半年的新人接触Shader的时间也并不长,正因为是新人才能体会到学习Shader时候所遇到的困难和迷茫,无奈于资料不好找,网上难得的几 ...
- Esfog_UnityShader教程_漫反射DiffuseReflection
这篇是系列教程的第三篇,最近工作比较紧,所以这个周六周日就自觉去加了刚回来就打开电脑补上这篇,这个系列的教程我会尽量至少保证一周写一篇的.如果大家看过我的上一篇教程<Esfog_UnitySha ...
- Shader实例:溶解效果(Dissolve)
效果: 图左:一道金光闪过,瞬间灰飞烟灭 图右:燃烧效果,先过渡到黄色,然后渐渐过渡到黑色,最后消失殆尽. 这是游戏中常见的效果,各位可以想想自己玩过的游戏. 手头正在玩的,梦三国手游,死亡的时候就是 ...
- Esfog_UnityShader教程_遮挡描边(原理篇)
咳咳,有段时间没有更新了,最近有点懒!把不少精力都放在C++身上了.闲言少叙,今天要讲的可和之前的几篇有所不同了,这次是一个次综合应用.这篇内容中与之前不同主要体现在下面几点上. 1.之前我们写的都是 ...
- Esfog_UnityShader教程_逐帧动画
有段日子没出这个系列的新文章了,今天就拿一个比较常见也比较基础的利用改变Shader来改变不断调整UV实现播放逐帧动画的小功能.很久没写了就当练练手了.在新版本的Unity中早就已经集成了Sprite ...
- Esfog_UnityShader教程_遮挡描边(实现篇)
在上一篇中,我们基本上说明了遮挡描边实现的一种基本原理.这一篇中我们将了解一下基于这种原理的具体实现代码.本篇中的内容和前几篇教程相比,相对比较难一些,建议先有一些基本的Unity的C#脚本编程经验 ...
- pixijs shader 贴图溶解效果教程
pixijs shader 贴图溶解效果教程 我直接贴代码了 没什么好讲解了 稍微有点基础的人应该能看懂 const app = new PIXI.Application({ transparent: ...
- Spring_MVC_教程_快速入门_深入分析
Spring MVC 教程,快速入门,深入分析 博客分类: SPRING Spring MVC 教程快速入门 资源下载: Spring_MVC_教程_快速入门_深入分析V1.1.pdf Spring ...
随机推荐
- sublime text 2 ubuntu安装及插件管理
参考 dudumao 1.下载Sublime Text2官网下载地址:http://www.sublimetext.com 2.安装Sublime Text2解压即可使用 $ sudo tar -jx ...
- ion-header-bar
ion-header-bar 指令声明一个标题栏元素,标题栏总是位于屏幕顶部 它有两个同级的可选属性 align-title:设置标题文字的对齐方式.允许值:left|right|center no- ...
- echarts图表标签(axisLabel)折行
在项目中遇到了一个echarts图表标签过长需折行的需求,so引出这篇总结,啦啦啦有帮助就多多支持啦,撒花撒花撒花~~~~ 在此不对echarts其他用法做解释,详细见echarts文档(点击前往) ...
- Android常用库
原文链接:http://www.jianshu.com/p/19368c2cdcaf 系统框架 1. 网络请求 Android Async HTTP Android异步HTTP库 AndroidAsy ...
- AJAX跨域
AJAX跨域AJAX不允许跨域访问. 跨域是指浏览器B显示的是服务器S1的数据,全是从S1取得的数据则是同域:但如果B显示的S1上的数据的某个比如img是从S2上取得的数据,则是跨域.端口不一样也是跨 ...
- c# 函数
1.输入三个数,求最大的数. 2.输入一个数,求1~n的和. 3.求n的阶乘. 4.输入一个小于等于100的数,判断是否是100,还是小于10,还是两位数.
- jsp基础知识
- [转]iOS代码块Block
代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量.作为参数.作为返回值,特殊地,Block还可以保存一段代码,在需要 ...
- KMPlayer 捆绑商业软件问题以及解决办法
Kmplayer 本来是很好的播放软件,支持的格式很多,特别我要在本地播放flash swf 就用它.昨天下载安装了他们推荐已久的更新之后,莫名帮我安装了几个软件,都是我不能选择的,例如Winzip. ...
- Saying that Java is nice because it works on every OS is like saying that anal sex is nice because it works on every gender.
Saying that Java is nice because it works on every OS is like saying that anal sex is nice because i ...