溶解效果在游戏中是很常见的,比如在一些神话或者魔法世界中,一些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的更多相关文章

  1. Esfog_UnityShader教程_镜面反射SpecularReflection

    系列教程第四篇,本来打算昨天写的,有些小偷懒就今天写了,这一期我们来讨论一下关于镜面反射的基本原理和具体代码.这一篇是承接着上一篇<Esfog_UnityShader教程_漫反射DiffuseR ...

  2. Esfog_UnityShader教程_前言

    很多人在学习Unity的时候对Shader都是一知半解,作为刚入职半年的新人接触Shader的时间也并不长,正因为是新人才能体会到学习Shader时候所遇到的困难和迷茫,无奈于资料不好找,网上难得的几 ...

  3. Esfog_UnityShader教程_漫反射DiffuseReflection

    这篇是系列教程的第三篇,最近工作比较紧,所以这个周六周日就自觉去加了刚回来就打开电脑补上这篇,这个系列的教程我会尽量至少保证一周写一篇的.如果大家看过我的上一篇教程<Esfog_UnitySha ...

  4. Shader实例:溶解效果(Dissolve)

    效果: 图左:一道金光闪过,瞬间灰飞烟灭 图右:燃烧效果,先过渡到黄色,然后渐渐过渡到黑色,最后消失殆尽. 这是游戏中常见的效果,各位可以想想自己玩过的游戏. 手头正在玩的,梦三国手游,死亡的时候就是 ...

  5. Esfog_UnityShader教程_遮挡描边(原理篇)

    咳咳,有段时间没有更新了,最近有点懒!把不少精力都放在C++身上了.闲言少叙,今天要讲的可和之前的几篇有所不同了,这次是一个次综合应用.这篇内容中与之前不同主要体现在下面几点上. 1.之前我们写的都是 ...

  6. Esfog_UnityShader教程_逐帧动画

    有段日子没出这个系列的新文章了,今天就拿一个比较常见也比较基础的利用改变Shader来改变不断调整UV实现播放逐帧动画的小功能.很久没写了就当练练手了.在新版本的Unity中早就已经集成了Sprite ...

  7. Esfog_UnityShader教程_遮挡描边(实现篇)

     在上一篇中,我们基本上说明了遮挡描边实现的一种基本原理.这一篇中我们将了解一下基于这种原理的具体实现代码.本篇中的内容和前几篇教程相比,相对比较难一些,建议先有一些基本的Unity的C#脚本编程经验 ...

  8. pixijs shader 贴图溶解效果教程

    pixijs shader 贴图溶解效果教程 我直接贴代码了 没什么好讲解了 稍微有点基础的人应该能看懂 const app = new PIXI.Application({ transparent: ...

  9. Spring_MVC_教程_快速入门_深入分析

    Spring MVC 教程,快速入门,深入分析 博客分类: SPRING Spring MVC 教程快速入门  资源下载: Spring_MVC_教程_快速入门_深入分析V1.1.pdf Spring ...

随机推荐

  1. MyBatis笔记

    Mybatis:将java对象映射成SQL语句,再将结果转化为java对象,解决了java对象和sql拼接.结果集的问题,又可以自己写sql语句 总体结构: 根据JDBC规范建立与数据库的连接 通过反 ...

  2. jQuery基本语法

    jQuery 是 JavaScript 的一个函数库.方便.主流   jQuery的开发步骤: (1) 导入jQuery 库   (2)  在 <script src="../js/j ...

  3. ionic slidebox 嵌套问题

    ionic slidebox 嵌套 会有一个 冒泡 事件 , 即使是 阻止了 父级冒泡也不管用 , 最终 用  滑动 事件on-drag="drag()"   去阻止 了父级的 滑 ...

  4. iOS 动画

    图层树.寄宿图以及图层几何学(一)图层的树状结构 技术交流新QQ群:414971585 巨妖有图层,洋葱也有图层,你有吗?我们都有图层 -- 史莱克 Core Animation其实是一个令人误解的命 ...

  5. Spark2.0自定义累加器

    Spark2.0 自定义累加器 在2.0中使用自定义累加器需要继承AccumulatorV2这个抽象类,同时必须对以下6个方法进行实现: 1.reset 方法: 将累加器进行重置; abstract  ...

  6. pthread_cond_wait()函数的理解(摘录)

    /************pthread_cond_wait()的使用方法**********/pthread_mutex_lock(&qlock);    /*lock*/pthread_c ...

  7. TP中关于自定义类库的添加和使用

    ThinkPHP的类库主要包括公共类库和应用类库,都是基于命名空间进行定义和扩展的.只要按照规范定义,都可以实现自动加载. 类库存放位置:Think目录:系统核心类库Org目录:第三方公共类库demo ...

  8. 从返回值未报错得到的对于java finally理解

    不多说了,直接看图 这个代码来自<深入理解java虚拟机(第二版)>,我在eclipse中编辑的,但是没有报错,一般来说,没有返回值,eclipse都会有个提示或者报错啥的,但是这个没有, ...

  9. JTree使用

    package JTree; import java.awt.Component; import javax.swing.Icon; import javax.swing.JTree; import ...

  10. C++编写DLL的方法

    http://files.cnblogs.com/files/profession/DllTest.zip 在写C++程序时,时常需要将一个class写成DLL,供客户端程序调用.这样的DLL可以导出 ...