效果一览
基本原理
利用clip()函数将距离目标点一定距离内的像素进行剔除,通过采样杂讯贴图对该距离进行扰动,以便形成较为无序自然的燃烧边缘,同时燃烧边缘一定距离内对燃烧颜色贴图采样来形成燃烧边缘颜色
具体实现
在Unity中完成该效果,讲解见注释,场景搭建参考我专栏的另一篇文章unity热扰动
新建box,添加如下shader
DistanceMelt.shader
Shader "Custom/DistanceMelt" { Properties { [NoScaleOffset]_MainTex("主贴图", 2D) = "white" {} _MaxDistance("影响半径",float) = 0.5 _NoiseTex("杂讯贴图",2D) = "black"{} _XDensity("杂讯密度(水平)", float) = 1 _YDensity("杂讯密度(竖直)", float) = 1 _MeltPoint("消融点坐标",Vector)=(0,0,0,1) _NoiseEffect("杂讯影响占比",Range(0,1))=0.5 [NoScaleOffset]_EdgeColor("消融边缘贴图",2D) = "black"{} _ColScale("颜色比例",float) = 1 _EdgeWidth("消融边缘宽度",Range(0,1)) = 0 } SubShader { Tags { "RenderType" = "Opaque" } LOD 100
Pass { Cull Off
CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc"
struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float2 uvMain : TEXCOORD0; float2 uvNoise : TEXCOORD1; float4 objPos : TEXCOORD2; };
sampler2D _MainTex; sampler2D _NoiseTex; sampler2D _EdgeColor; float4 _NoiseTex_ST; float4 _MeltPoint; float _Threshold; float _XDensity; float _YDensity; float _EdgeWidth; float _MaxDistance; fixed _NoiseEffect; float _ColScale; float _DelayTime;
v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uvMain = v.uv; _NoiseTex_ST.xy *= float2(_XDensity, _YDensity);//改变杂讯贴图缩放来控制杂讯密度 o.uvNoise = TRANSFORM_TEX(v.uv, _NoiseTex); o.objPos = v.vertex;//保留物体的物体空间坐标,为后续计算距离准备 return o; }
fixed4 frag(v2f i) : SV_Target { float4 PointPos = mul(unity_WorldToObject , _MeltPoint);//将世界坐标的目标点转到物体空间坐标 float Distance = length(i.objPos - PointPos);//计算他们在物体空间坐标的距离 fixed noise = tex2D(_NoiseTex, i.uvNoise).r;//采样杂讯,后续将对消融距离进行扰动 //noise*_NoiseEffect表示杂讯扰动的影响程度 //Distance减去noise*_NoiseEffect完成对距离的扰动影响 //最后减去_MaxDistance判断影响后的距离是否大于最大距离,小于就剔除,大于就保留像素 fixed cutout = Distance - noise * _NoiseEffect - _MaxDistance; clip(cutout);//cutout小于0剔除像素,反之保留像素 fixed4 col = tex2D(_MainTex, i.uvMain); //cutout若大于0即可表示成与_MaxDistance的距离,除于_EdgeWidth并约束到0~1转化1成uv即可完成根据与_MaxDistance的距离查找uvEdgeCol对应的颜色 //_ColScale对uv.x进行缩放,完成水平方向对EdgeCol自定义分配,数值越大,采样约接近EdgeCol的深黑色部分 //EdgeCol帖图的导入设置中wrap mode要设为clamp fixed2 uvEdgeCol = fixed2(_ColScale*smoothstep(0, 1, cutout / _EdgeWidth), smoothstep(0, 1, cutout / _EdgeWidth)); fixed4 edgeCol = tex2D(_EdgeColor, uvEdgeCol); //根据与_MaxDistance的距离与_EdgeWidth的占比来过渡MainTex颜色与边缘颜色edgeCol fixed f= smoothstep(0, 1, cutout / _EdgeWidth); col = lerp(edgeCol, col, f); return col; } ENDCG } } }
参数一览
其中消融点坐标为场景中火把火焰的世界坐标
推荐阅读: