Unity Shader 如何实现火焰特效

发表于2018-06-13
评论1 6.5k浏览
为了让游戏中的角色技能更加多样化,有时候会给角色加一些火焰特效,下面就用给大家分享下shader实现火焰特效的方法。

效果图如下:

火焰效果制作方法

1、C#部分的代码如下:
using UnityEngine;  
using System.Collections;  
[ExecuteInEditMode]  
public class CamRendImage : MonoBehaviour {  
    [SerializeField]  
    private Material m_mat;  
    // Use this for initialization  
    void Start () {   
    }  
    // Update is called once per frame  
    void Update () {  
    }  
    void OnRenderImage(RenderTexture src,RenderTexture dest)  
    {  
        Graphics.Blit (src,dest,m_mat);  
    }  
    void OnMouseDown()  
    {  
    }  
    void OnMouseUp()  
    {  
    }  

2、Shader代码如下:
Shader "Unlit/Flame"  
{  
    Properties{  
    }  
    CGINCLUDE      
    #include "UnityCG.cginc"     
    #pragma target 3.0        
    #define vec2 float2  
    #define vec3 float3  
    #define vec4 float4  
    #define mat2 float2x2  
    #define mat3 float3x3  
    #define mat4 float4x4  
    #define iGlobalTime _Time.y  
    #define mod fmod  
    #define mix lerp  
    #define fract frac  
    #define texture2D tex2D  
    #define iResolution _ScreenParams  
    #define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy)  
    #define PI2 6.28318530718  
    #define pi 3.14159265358979  
    #define halfpi (pi * 0.5)  
    #define oneoverpi (1.0 / pi)  
    vec4 main(in vec2 fragCoord );  
    struct v2f {      
        float4 pos : SV_POSITION;      
        float4 scrPos : TEXCOORD0;     
    };                
    v2f vert(appdata_base v) {    
        v2f o;  
        o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
        o.scrPos = ComputeScreenPos(o.pos);  
        return o;  
    }    
    fixed4 frag(v2f _iParam) : COLOR0 {   
        vec2 fragCoord = gl_FragCoord;  
        return main(gl_FragCoord);  
    }    
    float noise(vec3 p) //Thx to Las^Mercury  
{  
    vec3 i = floor(p);  
    vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);  
    vec3 f = cos((p-i)*acos(-1.))*(-.5)+.5;  
    a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);  
    a.xy = mix(a.xz, a.yw, f.y);  
    return mix(a.x, a.y, f.z);  
}  
float sphere(vec3 p, vec4 spr)  
{  
    return length(spr.xyz-p) - spr.w;  
}  
float flame(vec3 p)  
{  
    float d = sphere(p*vec3(1.,.5,1.), vec4(.0,-1.,.0,1.));  
    return d + (noise(p+vec3(.0,iGlobalTime*2.,.0)) + noise(p*3.)*.5)*.25*(p.y) ;  
}  
float scene(vec3 p)  
{  
    return min(100.-length(p) , abs(flame(p)) );  
}  
vec4 raymarch(vec3 org, vec3 dir)  
{  
    float d = 0.0, glow = 0.0, eps = 0.02;  
    vec3  p = org;  
    bool glowed = false;  
    for(int i=0; i<64; i++)  
    {  
        d = scene(p) + eps;  
        p += d * dir;  
        if( d>eps )  
        {  
            if(flame(p) < .0)  
                glowed=true;  
            if(glowed)  
                glow = float(i)/64.;  
        }  
    }  
    return vec4(p,glow);  
}  
vec4 main(in vec2 fragCoord )  
{  
    vec4 fragColor;  
    vec2 v = -1.0 + 2.0 * fragCoord.xy / iResolution.xy;  
    v.x *= iResolution.x/iResolution.y;  
    vec3 org = vec3(0., -2., 4.);  
    vec3 dir = normalize(vec3(v.x*1.6, -v.y, -1.5));  
    vec4 p = raymarch(org, dir);  
    float glow = p.w;  
    vec4 col = mix(vec4(1.0,0.5,0.1,1.0), vec4(0.1,0.5,1.0,1.0), p.y*0.02+0.4);  
    fragColor = mix(vec4(0,0,0,0), col, pow(glow*2.,4.));  
    //fragColor = mix(vec4(1.), mix(vec4(1.,.5,.1,1.),vec4(0.1,.5,1.,1.),p.y*.02+.4), pow(glow*2.,4.));  
    return fragColor;  
}  
    ENDCG      
    SubShader {      
        Pass {      
            CGPROGRAM      
            #pragma vertex vert      
            #pragma fragment frag      
            #pragma fragmentoption ARB_precision_hint_fastest   
            ENDCG      
        }      
    }       
    FallBack Off      
}  

将1中的C#脚本赋给主摄像机,然后将附有2中的Shader的材质赋值给C#脚本中的“m_mat”变量。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引