写在前面

前几天有人在群里问怎么制作一个纸张被火烧掉的效果,刚好那天没那么忙,就尝试实现了一个,效果如下:

这个shader并不复杂,主要是对噪音图的使用,趁这次机会和大家分享一下

基础材质

纸张本身不是这次效果的重点,所以简单的采样一张贴图即可,下面是随便找了张图贴上去

fixed4 col = tex2D(_MainTex, i.uv.xy);

我们还需要一张燃烧过后的图,把上面那张图扔PS里去个色,然后加点污渍:

fixed4 colAsh = tex2D(_AshTex, i.uv.xy);

余烬效果

燃烧过会还会留下一下余烬,我们可以利用噪音图来实现,通过采样两次噪音图进行叠加来让噪音更随机一些,让其中一次稍微放大一些防止完全重叠的情况。

这里用到一张网上随便找的噪音图(注意商用的话可能会有侵权风险)

vertex:

o.uv2 = TRANSFORM_TEX(v.uv, _NoiseMap).xyxy * half4(1,1,1.3,1.3) + _FlowVector * _Time.x;

fragment:

fixed noise =(tex2D(_NoiseMap2 , i.uv2.xy) + tex2D(_NoiseMap2, i.uv2.zw)) * 0.5;

效果如下

当然你也可以试试别的叠加算法,比如这样:

fixed noise =abs( (tex2D(_NoiseMap2 , i.uv2.xy) + tex2D(_NoiseMap2, i.uv2.zw)) - 1);

我们会得到一个这样的效果

提取其中一部分区域作为遮罩,叠加上火焰的颜色:

fixed3 spark =(smoothstep(0.8,1, noise)) * _SparkColor;

就能得到这样的效果了。

材质混合

这里图省事我们就直接使用uv的x方向来进行混合,因为这里的过渡范围限定为0到1,所以需要把混合因子映射到-1到2才能保证完全覆盖,效果如下:

_Blend = _Blend * 3 - 1;
half blendValue = smoothstep(_Blend-_Range, _Blend+_Range, i.uv.x) ;
col.rgb = lerp(colAsh + spark, col ,  blendValue) + burnRange;

现在的混合边缘太生硬,使用上面的噪音图对混合的边缘进行扰动,稍微调整下代码:

half blendValue = smoothstep(_Blend-_Range, _Blend+_Range, i.uv.x + noise * _Range) ;

火焰

从上面的的混合权重里把边缘提取出来,因为噪音的影响,我们就可以得到一个近似火焰的遮罩区域:

 float3 burnRange = blendValue * (1-blendValue) * _RangeColor;
col.rgb = lerp(colAsh + spark, col ,  blendValue) + burnRange;

现在火焰占满了整个过渡区域,我觉得有点太过了,所以调整了下,把火焰限定在更小的范围,并且加入了偏移值和火焰宽度值进行微调:

float3 burnRange = max(0 , 1 - abs(blendValue - (_FireOffset *(1-_FireRange*2)+ _FireRange)) /_FireRange) * _RangeColor;

写这类效果的时候我一般喜欢画图来辅助计算,比较推荐一个网站:

Graphing Calculator - GeoGebra​www.geogebra.org

上面的那个算法图像是这样子的:

https://www.zhihu.com/video/1225579900545224704

消散效果

消散效果应该很多人都写过,一个简单的clip即可,因为我们需要按照燃烧>灰烬>消散这个过程渐变,所以消散效果要在前面的混合权重基础上加一点偏移:

clip(col.a * (i.uv.x+ noise * _Range)  -  (_Blend  -  _Range -_EmberRange)) ;

顶点扰动

纸张燃烧时候还会因为热量产生一点轻微的变形,我们利用顶点动画来模拟这个效果,注意如果要做顶点动画的话,顶点数量不能太少,这里的模型使用的是一个30*30的网格

float4 noiseuv = float4(v.uv * _NoiseMap2_ST.xy + _NoiseMap2_ST.zw * _Time.x, 0,0) ;
fixed noise = tex2Dlod(_NoiseMap2 , noiseuv) ;
_Blend = _Blend * 4 - 1;
half vertOffset =  noise *  _VertOffset * saturate (1 - (o.uv.x*4  -_Blend));o.vertex = UnityObjectToClipPos(v.vertex + half4(0,0,vertOffset ,0));

这样我们的效果就全部完成了,看上去还不错, 再加一点粒子应该会很不错。

完整代码

/*******************************************************
*   2020-03-18 16:38:42
*   @Mya
*   模拟纸张燃烧的shader
********************************************************/
Shader "Mya/Effect/BurningPaper"
{Properties{_MainTex ("Texture", 2D) = "white" {}_AshTex ("Ash Texture", 2D) = "white" {}_NoiseMap("Noise" , 2D) = "black"{}_Blend("Blend" , Range(0,1)) = 0[hdr]_RangeColor("Range Color" , Color) = (1,0,0,1)_Range("Range" , Range(0.01,0.5)) = 0.1_FireRange("Fire Range" , Range(0,0.5)) = 0.2_FireOffset("Fire Offset" , Range(0,1)) = 0[hdr]_SparkColor("spark Color" , Color) = (1,0,0,1)_AshRange("EmberRange" , Range(0,1)) = 0.1_FlowVector("Flow Vector" , vector) = (0,0,0,0)_NoiseMap2("Noise2" , 2D) = "black"{}_VertOffset("Vert Offset" , Range(0,1))    = 0.1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Blend SrcAlpha OneMinusSrcAlphaCull OffPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex   : POSITION;float2 uv       : TEXCOORD0;};struct v2f{float2 uv       : TEXCOORD0;float4 uv2      : TEXCOORD1;float4 vertex   : SV_POSITION;};sampler2D   _MainTex;float4      _MainTex_ST;sampler2D   _AshTex;sampler2D   _NoiseMap; float4      _NoiseMap_ST ;sampler2D   _NoiseMap2;float4      _NoiseMap2_ST ;half        _Blend;half        _Range;fixed4      _RangeColor;fixed4      _SparkColor;half        _AshRange;half        _FireRange;half        _FireOffset;half4       _FlowVector;half        _VertOffset;v2f vert (appdata v){v2f o;o.uv = TRANSFORM_TEX(v.uv, _MainTex);//通过采样两次噪音图进行叠加来让噪音更随机一些,让其中一次稍微放大一些防止完全重叠的情况o.uv2 = TRANSFORM_TEX(v.uv, _NoiseMap).xyxy * half4(1,1,1.3,1.3) + _FlowVector * _Time.x;//顶点里采样贴图需要使用tex2Dlodfloat4 noiseuv = float4(v.uv * _NoiseMap2_ST.xy + _NoiseMap2_ST.zw * _Time.x, 0,0) ;fixed noise = tex2Dlod(_NoiseMap2 , noiseuv) ;_Blend = _Blend * 4 - 1;//对燃烧区域的顶点做一点偏移,模拟飘动的效果half vertOffset =  noise *  _VertOffset * saturate (1 - (o.uv.x*4  -_Blend));o.vertex = UnityObjectToClipPos(v.vertex + half4(0,0,vertOffset ,0));return o;}fixed4 frag (v2f i) : SV_Target{fixed noise = (tex2D(_NoiseMap , i.uv2.xy) + tex2D(_NoiseMap2, i.uv2.zw))*0.5;//基于uv的x方向计算混合的权重,边缘使用噪音进行扰动//要保证四个状态(原始,燃烧,灰烬,消散)都能完整显示,需要把混合因子映射到-1~3_Blend = _Blend * 4 - 1;half blendValue = smoothstep(_Blend-_Range, _Blend+_Range, i.uv.x + noise * _Range) ;//原始的颜色fixed4 col = tex2D(_MainTex, i.uv.xy);//燃烧后的颜色fixed4 colAsh = tex2D(_AshTex, i.uv.xy);//余烬fixed3 spark =(smoothstep(0.8,1, noise)) * _SparkColor;//火焰float3 burnRange = max(0 , 1 - abs(blendValue - (_FireOffset *(1-_FireRange*2)+ _FireRange)) /_FireRange) * _RangeColor;//消散clip(col.a * (i.uv.x+ noise * _Range)  -  (_Blend  -  _Range -_AshRange)) ;//混合col.rgb = lerp(colAsh + spark, col ,  blendValue) + burnRange;return col;}ENDCG}}
}

GitHub:

https://github.com/myacat/PaperBurn​github.com

写在最后

简单修改下还可以做出类似这样的效果,有兴趣的小伙伴可以自己尝试继续优化下:

=====4.18更新====================

今天稍微调整了一下这个曲线的算法,让曲线更平滑一些

https://www.zhihu.com/video/1234725242905935872

左边是新的算法

拆成了独立的函数

            half Pow2(half x){return x*x;}half ReMap(half range, half offset , half val){#if SMOOTHRANGE//Range(10-0)range = 10*(1 -range);return Pow2(max(0, 1 - Pow2(range*val + 2*val - range*offset - 1)));#else//Range(0.5-0.1)range = 0.1 + range * 0.4;return max(0 , 1 - abs(val - (offset *(1-range*2)+ range)) /range) ;#endif}

因为两个算法range参数的值域是不一样的,所以重映射了一次。

左边是新的算法

然而改完后发现效果也并没有变好多少.....emmm算是提供另一个思路吧...

火焰效果材质实现_利用噪音图制作一个纸张燃烧的效果相关推荐

  1. 免装版_无缝贴图制作软件 PixPlant2中文免装版

    点击上方蓝字关注我们 如您喜欢我们的公众号,不妨推荐给身边的朋友 资源介绍: 资源来源于网络,很多时候我们从网上找的贴图并不是无缝的,而且一般都没有高光/法线 贴图这些,在材质的模拟上就要差了很多,在 ...

  2. 函数模板案例_利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序 排序规则从大到小,排序算法为选择排序 分别利用char数组和int数组进行测试

    案例描述: 利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序 排序规则从大到小,排序算法为选择排序 分别利用char数组和int数组进行测试 #include <iostream& ...

  3. github项目怎么运行_利用 GitHub 从零开始搭建一个博客

    "NightTeam",一个值得加星标的公众号. 趁着周末,搭建了一下 NightTeam 的官方博客和官方主页,耗时数个小时,两个站点终于完工了. 由于 NightTeam 的域 ...

  4. 在java里四舍五入怎么做_利用java怎么实现一个四舍五入功能

    利用java怎么实现一个四舍五入功能 发布时间:2020-12-02 16:46:08 来源:亿速云 阅读:68 作者:Leah 这期内容当中小编将会给大家带来有关利用java怎么实现一个四舍五入功能 ...

  5. python如何创建一个文件夹_利用Python怎么创建一个文件夹

    利用Python怎么创建一个文件夹 发布时间:2020-12-08 14:48:04 来源:亿速云 阅读:91 作者:Leah 这期内容当中小编将会给大家带来有关利用Python怎么创建一个文件夹,文 ...

  6. python输入一个字符串、计算其中小写字符的个数_利用键盘录入,输入一个字符串,统计该字符串中各个字符的数量,并输出(c/c++实现)...

    title: 输入一串字符串统计字符个数 localimage: image1 urlname: staticstringnum categories: summarytags: [writen, e ...

  7. java运用到的单词_利用Java怎么实现一个单词提取功能

    利用Java怎么实现一个单词提取功能 发布时间:2020-12-08 17:07:00 来源:亿速云 阅读:65 作者:Leah 这篇文章给大家介绍利用Java怎么实现一个单词提取功能,内容非常详细, ...

  8. java 方法数统计_利用Java简单实现一个代码行数统计器方法实例

    前言 哈喽,我是小黑, 最近学了java的输入输出流后一直心痒痒,总想找一点事情来做,所以用java代码来实现了一下统计代码的所有行数,看一下我上大学以来到底打了多少行. 先附上实现代码吧! pack ...

  9. python center函数_利用Python函数实现一个万历表完整示例

    前言 大家可以根据格式化打印字符去调一下最后的输出,不过有中文好像不好调整,可以换成星期的单词,这样应该会好一点,format()函数可以用来格式化打印字符,format()可以使用字符串去调用,也可 ...

最新文章

  1. 九项重要的职业规划提示
  2. 12.文件系统——磁盘管理之RAID概述
  3. ubuntu14.04下mysql数据库的默认存放路径并修改
  4. IDEA以UML图表方式查看maven项目pom文件中全局及部分jar之间依赖关系
  5. [博客园公告]编辑器改进(二)
  6. 【线段树】Optimal Insertion(CF751E)
  7. 斗地主AI算法——第六章の牌型判断
  8. Linux服务器性能分析
  9. 无限极业绩_2019中国保健品行业典型企业分析——无限极、康宝莱、汤臣倍健...
  10. 快速排序 与 归并排序
  11. java 符号引用与直接引用
  12. python美多商城项目百度网盘_美多商城项目(十)
  13. java小球反弹_java实现小球碰撞反弹(示例代码)
  14. Echarts使用教程
  15. 最小二乘支持向量机--LSSVM分类及MATLAB代码实现
  16. 2020校招Java笔试题
  17. web微信授权登陆-配置篇
  18. App启动页倒计时圆形并且跳过功能实现
  19. 【记录】一个自动投票的小程序(python实现)
  20. 关于商业智能BI,你需要知道的相关知识都在这里了

热门文章

  1. java报错怎么看_IGV 哐当就不能用了,除了换台电脑还能怎么办?
  2. PHP二维数组根据字段排序
  3. java安卓获取mac_android开发分享以编程方式获取Android设备的MAC
  4. 闲置硬盘自制nas私有云_闲置U盘不用扔,教你一招变云盘,随时随地备份数据、访问私有云...
  5. java 模块 分工_Java秒杀系统实战系列~构建SpringBoot多模块项目
  6. emcy协议_CANopen协议 -
  7. dblink传输clob字段
  8. c语言 元组顺序随机化,为什么关系中的元组没有先后顺序且不允许有重复元组?...
  9. python如何定义一个空变量_如何在python中定义自由变量? - python
  10. ipython使用_IPython的介绍与使用