一种火焰shader的实现

火焰在我们的日常生活中十分常见,我们都知道火焰有内外焰之分,在现实世界中内外焰的颜色区别并不是十分明显,而在大多数游戏尤其是卡通渲染风格的游戏中火焰的内外焰颜色有明显的区别(我十分喜爱的一款国产游戏:蜡烛人)

接下来我们来实现一个简易的火焰shader

先上最终效果图

整体思路:分别渲染火焰的内焰和外焰,叠加后得到最终效果

首先我们来实现火焰的主体也就是内焰的效果,为了表现出火焰扭曲且流动的特性,我们需要使用一张噪音纹理和一张控制扭曲的纹理,关键步骤是使用扭曲纹理来采样这张流动的噪音纹理,我们这里选择使用扭曲纹理的rgb通道中的两个通道来对噪音纹理进行采样:

 

v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _NoiseTex);
o.uv2 = TRANSFORM_TEX(v.uv, _DistortTex);
return o;

}

fixed4 distort = tex2D(_DistortTex, i.uv2) * _Distort;

fixed4 noise = tex2D(_NoiseTex,fixed2((i.uv.x + _Time.x * _SpeedX) + distort.g  ,(i.uv.y + _Time.x * _SpeedY) + distort.r));

这里为防止偏移速度过快使用_Time.x控制流动速度,_Distort控制扭曲的强度

我们同样可以用两张噪音纹理完成这种效果,先采样一张噪音纹理,对其加上偏移和强度控制后在用于采样第二张噪音纹理,可以达成类似效果此处不再演示

得到的效果如下:

好的,已经初步有扰乱和流动的感觉了,但是火焰不可能是全屏的,应当还有渐变效果,这里我们自然可以想到使用一张从上到下由黑变白的渐变纹理与其叠加从而产生一种渐变的效果

 

float4 gradientBlend = lerp(float4(1,1,1,1), float4(0, 0, 0, 0), (i.uv2.y + _Height));

noise += gradientBlend;

float4 flame = float4(noise.rgb, saturate(noise.a * _MainAlphaControl));

 

注意,这里的叠加次数越多,得到的效果就更加平滑,这里我选择叠加两次,由于多次叠加,叠加后用saturate将alpha钳制,使用_Height来控制渐变的范围,_AlphaControl用于控制边缘

得到效果如下:

恩不错,现在乘上我们的颜色就能得到内焰的效果了,现在考虑外焰效果,我们可以将外焰考虑为只是在内焰的边缘向外延伸一段距离的火焰,所以可以将flame的alpha值加上一个阈值后再减去原本的而得到

float4 flameedge = saturate((flame + _Edge) * _EdgeAlphaControl) - flame;
flameedge.a = 1 - flameedge.a;

 

这样我们就得到了外焰的效果,乘上外焰颜色再和内焰相加即可得到最终的效果了,由于叠加的渐变纹理alpha自身就是渐变的,所以我们最终得到的颜色也带有渐变的效果

完整的shader如下:

Shader "Myshader/FireTest"
{
	Properties
	{
		//噪音纹理流动速度
		_SpeedX("SpeedX", Range(-10,10)) = 1
		_SpeedY("SpeedY", Range(-10,10)) = 1

		_NoiseTex("Noise Texture", 2D) = "white" {}
		_DistortTex("Distort Texture", 2D) = "white" {}

		//控制整体的alpha值
		_MainAlphaControl("MainAlphaControl", Range(1,20)) = 1
		_EdgeAlphaControl("EdgeAlphaControl", Range(1,50)) = 1

		//控制渐变纹理
		_Height("Height", Range(-4,10)) = 1

		//火焰边缘大小
		_Edge("Edge", Range(0.02,0.3)) = 0.1

		//控制扭曲强度
		_Distort("Distort", Range(0,1)) = 0.2

		_MainColor("MainColor",Color) = (1,1,1,1)
		_EdgeColor("EdgeColor",Color) = (1,1,1,1)
	}
		SubShader
	{
		Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
		LOD 100
		Zwrite Off Cull Off
		Blend SrcAlpha OneMinusSrcAlpha
		

		Pass
	{
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag

		#include "UnityCG.cginc"

		struct appdata
	{
		float4 vertex : POSITION;
		float2 uv : TEXCOORD0;
	};

	struct v2f
	{
		float2 uv : TEXCOORD1;
		float2 uv2 : TEXCOORD2;
		float4 vertex : SV_POSITION;

	};

	float _SpeedX, _SpeedY;
	sampler2D  _NoiseTex, _DistortTex;
	float4 _DistortTex_ST, _NoiseTex_ST;
	float _Height, _Edge, _Distort, _MainAlphaControl, _EdgeAlphaControl;
	float4 _MainColor;
	float4 _EdgeColor;

	v2f vert(appdata v)
	{
		v2f o;
		o.vertex = UnityObjectToClipPos(v.vertex);
		o.uv = TRANSFORM_TEX(v.uv, _NoiseTex);
		o.uv2 = TRANSFORM_TEX(v.uv, _DistortTex);
		return o;
	}

	fixed4 frag(v2f i) : SV_Target
	{
		//可控制的渐变纹理
		float4 gradientBlend = lerp(float4(2,2,2,2), float4(0,0,0,0), (i.uv2.y + _Height));

		fixed4 distort = tex2D(_DistortTex, i.uv2) * _Distort;
		//使用扭曲纹理来取样噪音纹理
		fixed4 noise = tex2D(_NoiseTex,fixed2((i.uv.x + _Time.x * _SpeedX) + distort.g  ,(i.uv.y + _Time.x * _SpeedY) + distort.r));

		noise += gradientBlend;
		noise += gradientBlend;

		float4 flame = float4(noise.rgb, saturate(noise.a * _MainAlphaControl));
		float4 flamecolor = flame * _MainColor;
		float4 flameedge = saturate((flame + _Edge) * _EdgeAlphaControl) - flame;
		flameedge.a = 1 - flameedge.a;
		float4 edgecolor = flameedge * _EdgeColor;
		float4 finalcolor = flamecolor + edgecolor;
		return flameedge;
	}
		ENDCG
	   }
	}
}

 

学生党一枚,文章中的错误,不足诚请各位指点!!

参考:https://www.patreon.com/posts/quick-game-art-17021975

 

更新:

最近在学UE4,这里也提供一种类似火焰实现的效果

同样先上最终效果图

这里选择用溶解的方法实现火焰效果,原理和之前提到的类似。混合模式为translucent,无光照。

首先是UV处理部分,简单的实现UV流动。

其次我们来实现火焰的主体,这里我们使用减法实现溶解。贴图首先乘上给定的EdgeSharp变量,用于控制外焰边缘的软硬程度,从上图看即其值越大火焰边缘的值越白。然后用减法减去变量值,并由Mask过通道的UV来控制。最左边减EdgeSharp保证其小于等于0。最右边则减去-1,这是因为我们要保证最右边都为白色,所以减-1可以保证右侧原本为0值的黑色部分都变白。然后再通过add一个变量值用来控制火焰整体的移动,就和之前unity中实现的height控制一样。最后的图像有小于0的部分也有大于1的部分所以再通过clamp钳制。

最后再加上折射效果,最左侧的折射率为1即不折射,靠近右侧的折射率由参数控制即可。然后再加上法线贴图和颜色控制即可完成火焰效果。

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,下面是一个简单的火焰shader示例: 首先,在Unity中创建一个新的Shader文件。然后将以下代码复制并粘贴到Shader文件中: ``` Shader "Custom/Fire" { Properties { _MainTex ("Texture", 2D) = "white" {} _Speed ("Speed", Range(0.1, 10)) = 1 _Scale ("Scale", Range(0.1, 10)) = 1 _Intensity ("Intensity", Range(1, 10)) = 1 _Color ("Color", Color) = (1, 0.5, 0, 1) } SubShader { Tags { "Queue"="Transparent" "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float _Speed; float _Scale; float _Intensity; fixed4 _Color; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); float noise = _Intensity * (_Scale * sum(noise(3, 0.5, 0.1, i.uv * _Speed)) + 1); col.rgb += _Color.rgb * noise; return col; } ENDCG } } FallBack "Diffuse" } ``` 这个shader包含了以下几个属性: - `_MainTex`: 火焰的纹理图像。 - `_Speed`: 火焰动画的速度。 - `_Scale`: 火焰的大小。 - `_Intensity`: 火焰的强度。 - `_Color`: 火焰的颜色。 然后在一个材质上使用这个shader,将纹理图像设置为火焰图像,调整其他属性以获得所需的火焰效果。 希望这个示例对你有所帮助! ### 回答2: 火焰shader一种用于在游戏或动画中渲染逼真火焰效果的技术。在Unity中编写火焰shader需要以下步骤: 1. 创建一个新的Shader。在Unity的项目资源管理器中,右键点击创建一个新的Shader,并为其命名。 2. 在shader中定义属性。使用Properties块来定义火焰所需的所有属性,如火焰贴图、颜色、尺寸等。 3. 编写顶点和片段着色器。在SubShader块中编写顶点和片段着色器。顶点着色器用于传递顶点位置和法线等信息,片段着色器用于计算每个像素的颜色。 4. 使用噪声函数生成动态效果。使用Simplex Noise和Perlin Noise等噪声算法,在片段着色器中生成火焰的动态效果。可以根据时间、位置等参数调整生成的噪声,实现动态火焰效果。 5. 计算火焰颜色。使用颜色插值来实现火焰颜色的变化。可以根据火焰高度、密度等属性,将火焰渐变为黄色、橙色、红色等。 6. 添加光照效果。可以根据火焰法线向量和光照信息,计算光照对火焰的影响,使火焰看起来更真实。 7. 调试和优化。在调试过程中,可以根据实际效果对火焰shader进行优化,比如减少计算量、调整颜色变化等。 8. 在游戏中应用。将编写好的火焰shader应用到游戏中的火焰模型上。可以通过将shader附加到渲染器组件或材质上来实现。 通过以上步骤,我们可以在Unity中编写一个基本的火焰shader实现逼真的火焰效果。根据需要,还可以进一步调整参数和效果,以达到更加细致和生动的火焰效果。 ### 回答3: 在Unity中写一个火焰shader是一个很有趣的挑战。一个火焰shader需要模拟出火焰的效果,包括不断变化的颜色,流动的形状和闪烁的光亮。 首先,我们需要定义火焰所在的位置,可以使用一个二维纹理图像来表示。纹理图像中的每一个点代表火焰的某一个位置,其颜色值代表火焰的强度。 接下来,我们可以通过在shader中使用噪声函数来创建火焰的形状。噪声函数可以生成具有随机性的数值,用于模拟火焰的起伏形状。 然后,我们可以使用一些算法来模拟火焰的运动。一个常见的方法是使用流体动力学方程来模拟火焰的流动,通过在shader中使用这些算法,可以让火焰看起来具有流动感。 除了形状和运动,火焰的颜色也是非常重要的一部分。我们可以通过在shader中创建一个渐变效果,根据火焰的强度来决定火焰的颜色。从红色到橙色再到黄色,再到白色,可以使火焰看起来非常真实。 最后,我们可以通过在shader中使用一些技巧,模拟火焰的闪烁效果。通过颜色的变化和强度的调整,让火焰看起来具有动态和变化的光亮。 总结起来,编写一个火焰shader需要考虑到火焰的形状、颜色、流动和闪烁效果。通过使用噪声函数、渐变效果和流体动力学方程,我们可以在Unity中创建出逼真的火焰效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值