溶解效果在游戏中是很常见的,比如在一些神话或者魔法世界中,一些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. linux c网络编程之函数

    1. struct protoent *protocol=getprotobyname(char *p); 功能:通过协议名获取协议类型信息 解释:p为字符串指针,指向一个协议名,如icmp,stru ...

  2. 事件的委托处理 javascript

    javascript的事件模型,采用"冒泡"模式,即子元素的事件会逐级向上"冒泡",成为父元素的事件.这点可以简化事件的绑定... 例如,一个表格(table) ...

  3. 在linux中使用cmake编译运行cocos2d-x 3.4 projects

    原因: 由于不想在真机环境和 ide中调试环境, 只想在linux端进行 调试和运行, 需要使用cmake对现有的游戏进行编译(cocos2dx-lua 3.4) 修改步骤: 1.修改framewor ...

  4. java.nio.ByteBuffer中flip,rewind,clear方法的区别

    对缓冲区的读写操作首先要知道缓冲区的下限.上限和当前位置.下面这些变量的值对Buffer类中的某些操作有着至关重要的作用: limit:所有对Buffer读写操作都会以limit变量的值作为上限. p ...

  5. 深入理解javascript--笔记

    书写可维护的代码 1,最小全局变量   在js中不用声明变量就可以直接使用,因此注意不要没有声明就使用.(无意中创建的全局变量)比如使用任务链进行var声明.var a=b=12;正确写法为var   ...

  6. 计算ffff:0~ffff:b数据的和,结果存在dx中

    代码: assume cs:sad sad segment start: mov ax, 0ffffh mov ds, ax mov dx, ; add ds:0bh~ds:1h mov cx, 0b ...

  7. C++ 开篇

    C++ 程序员历练之路 1.C++ primer 2.C++程序设计语言 C++之父的作品 3.C++标准库 STL 4.TCP/IP协议详解  共3卷 5.Oracle数据库和MySQl数据库的学习 ...

  8. python 调用浏览器方法

    每天都要登陆某网站,刷积分.为了节省时间,用了下python中的webbrowser模块.新建.py 文件 #!/usr/bin/python import webbrowser webbrowser ...

  9. 终极解决maya渲染层丢材质,变线框等问题

    终极解决maya渲染层丢材质,变线框等问题 相信有很多同志在使用maya做灯光渲染的时候,经常能遇到渲染层的模型丢材质.变线框等问题,特别恶心.我也经常遇到,所以和大家分享一下我的解决或尽量避免的方法 ...

  10. c# foreach循环二维数组

    假设已有二维数组 array 行4, 列4for(int i=0;i<4;i++)//行的行数{ for(int j=0;j<4;j++)//行的列数 { console.wrie( ar ...