unity3d 实现残影特效

c#脚本 挂相机下

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

//[ExecuteInEditMode]

[RequireComponent(typeof(Camera))]
public class TestMRT : MonoBehaviour
{
    public Material testMRTMaterial = null;
    public RenderTexture[] mrtTex   = new RenderTexture[2];
    public RenderTexture[] TextureA = new RenderTexture[2];
    RenderBuffer[] mrtRB = new RenderBuffer[2];


    public Camera effectCame;

    public Texture texture0;
    public Texture texture1;
    public RenderTexture sourTexture;
    public RenderTexture canYanTexture;
    public RenderTexture curTexture;
    public Material CreateCanYinMaterial;
    void Start()
    {
        TextureA[0] = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
        TextureA[1] = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);

        Shader testMRT = Shader.Find("Custom/TestMRT");
        if (testMRT.isSupported)
            testMRTMaterial = new Material(testMRT);
        else
            return;
        Shader CanyanCreat = Shader.Find("Custom/CanyanCreat");
        if (CanyanCreat.isSupported)
            CreateCanYinMaterial = new Material(CanyanCreat);
        else
            return;
        StartCoroutine(ShowEffect());
    }


    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        sourTexture = source;
        //Graphics.Blit(sourTexture, source, testMRTMaterial, 0);
        if (!testMRTMaterial.shader.isSupported)
        {
            Graphics.Blit(source, destination);
            return;

        }

        //Show the result
        testMRTMaterial.SetTexture("_Tex0", sourTexture);
        testMRTMaterial.SetTexture("_Tex1", curTexture);
        //Graphics.Blit(curTexture, destination, testMRTMaterial, 2);
        Graphics.Blit(null, destination, testMRTMaterial, 2);

    }

    Dictionary<Renderer, Material[]> rendToMat = new Dictionary<Renderer, Material[]>();

    void Clear(RenderTexture destTexture)
    {
        Graphics.SetRenderTarget(destTexture);
        GL.PushMatrix();
        GL.Clear(true, true, Color.white);
        GL.PopMatrix();
    }

    void InitCanYanTexture()
    {
        playRoot = GameObject.Find("Players").transform;
        Transform[] chs = playRoot.GetComponentsInChildren<Transform>();
        int effectLayer = LayerMask.NameToLayer("ImageEffect");
        for (int i = 0, iMax = chs.Length; i < iMax; i++)
        {
            chs[i].gameObject.layer = effectLayer;
            Renderer red = chs[i].GetComponent<Renderer>();
            if (red != null)
            {
                if (red.sharedMaterial.shader.name == "Toon/Basic" ||
                    red.gameObject.name == "m_battle_box01")
                {
                    Material newMt = GameObject.Instantiate(CreateCanYinMaterial) as Material;
                    newMt.mainTexture = red.sharedMaterial.mainTexture;
                    rendToMat.Add(red, new Material[] { red.sharedMaterial, newMt });
                }
                else
                    Debuger.Log(red.sharedMaterial.shader.name);
            }

        }
        effectCame.cullingMask = 1 << effectLayer;
        canYanTexture = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
        effectCame.targetTexture = canYanTexture;
    }
    void CreateCanYanTexture()
    {
        int colorId = Shader.PropertyToID("_Color");
        Shader sd = CreateCanYinMaterial.shader;
        float i = 0;
        foreach (KeyValuePair<Renderer, Material[]> pair in rendToMat)
        {
            i += 1f;
            Renderer rd = pair.Key;
            rd.sharedMaterial = rendToMat[rd][1];
            rd.sharedMaterial.SetColor(colorId, new Color(0, 0, 1,0.7f+0.1f*i));
        }
        //GL.Clear(true, true, Color.clear);
        effectCame.Render();
        foreach (KeyValuePair<Renderer, Material[]> pair in rendToMat)
        {
            Renderer rd = pair.Key;
            rd.sharedMaterial = rendToMat[rd][0];
        }


    }
    private Transform playRoot;
    IEnumerator ShowEffect()
    {
        InitCanYanTexture();
        int ii = 0;
        while(true)
        {
            CreateCanYanTexture();
            yield return new WaitForSeconds(0.01f);
            int a = ii % 2;//0;//
            int b = ++ii % 2;//1;//
            curTexture = TextureA[a];
            Graphics.SetRenderTarget(curTexture);
            GL.Clear(false, false, Color.clear);
            testMRTMaterial.SetTexture("_Tex0", sourTexture);
            testMRTMaterial.SetTexture("_Tex1", TextureA[b]);
            testMRTMaterial.SetTexture("_MainTex", canYanTexture);

            GL.PushMatrix();

            GL.LoadOrtho();

            testMRTMaterial.SetPass(1);     //Pass 0 outputs 2 render textures.

            GL.Begin(GL.QUADS);

            GL.TexCoord2(0.0f, 0); GL.Vertex3(0.0f, 0.0f, 0.1f);

            GL.TexCoord2(1.0f, 0); GL.Vertex3(1.0f, 0.0f, 0.1f);

            GL.TexCoord2(1.0f, 1); GL.Vertex3(1.0f, 1.0f, 0.1f);

            GL.TexCoord2(0.0f, 1); GL.Vertex3(0.0f, 1.0f, 0.1f);

            GL.End();

            GL.PopMatrix();

        }
    }
}


用到的shader

Shader "Custom/CanyanCreat" {
    Properties {
        _MainTex ("", 2D) = "" {}
		_Color ("Main Color", Color) = (1,1,1,1)
    }
   
    CGINCLUDE
    #include "UnityCG.cginc"
    struct v2f {
        float4 pos : POSITION;
        float2 uv : TEXCOORD0;
    };

   	uniform float4 _Color;
    sampler2D _MainTex;

    v2f vert( appdata_img v )
    {
        v2f o;
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        o.uv = v.texcoord.xy;
        return o;
    }
    float4 fragCanYenCreate(v2f pixelData) : COLOR0
    {
		float4 col1 = tex2D(_MainTex, pixelData.uv);//上一帧的累加图
		//float4 col = _Color.a*(col1*0.8f+_Color*(1 - col1.a));
		float4 col = _Color+col1;
		col.a = _Color.a;//1.0f;//0.1f;
        return col;
    }
    ENDCG
   
Subshader {
   Pass {
      ZTest Always Cull Off ZWrite Off
      Fog { Mode off }
	  //Blend one zero 
      CGPROGRAM
      #pragma glsl
      #pragma fragmentoption ARB_precision_hint_fastest
      #pragma vertex vert
      #pragma fragment fragCanYenCreate
      #pragma target 3.0
	  
      ENDCG
  }

 

}
 
Fallback off
   
}

Shader "Custom/TestMRT" {
    Properties {
        _MainTex ("", 2D) = "" {}
    }
   
    CGINCLUDE
    #include "UnityCG.cginc"
    struct v2f {
        float4 pos : POSITION;
        float2 uv : TEXCOORD0;
    };

	struct PixelOutput {
		float4 col0 : COLOR0;
		float4 col1 : COLOR1;
	};

    sampler2D _MainTex;
	sampler2D _Tex0;
	sampler2D _Tex1;
    v2f vert( appdata_img v )
    {
        v2f o;
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        o.uv = v.texcoord.xy;
        return o;
    }
	//可以返回多个颜色,对应的
	//public static void SetRenderTarget(RenderBuffer[] colorBuffers, RenderBuffer depthBuffer); 可用多个buff接受
	//Graphics.SetRenderTarget(mrtRB, mrtTex[0].depthBuffer);
	PixelOutput fragTestMRT(v2f pixelData)
	 {
		PixelOutput o;
		o.col0 = float4(1.0f, 0.0f, 0.0f, 1.0f);
		o.col1 = float4(0.0f, 1.0f, 0.0f, 1.0f);
		return o;
	 }

	float4 fragCanYenAdd(v2f pixelData) : COLOR0
    {
		//float4 col0 = tex2D(_Tex0, pixelData.uv);//当前场景原图
		float4 col1 = tex2D(_Tex1, pixelData.uv);//上一帧的累加残影图
		float4 colM = tex2D(_MainTex, pixelData.uv);//当前场景新的残影图原图,a通道存放 衰减系数这样就可以控制 残影的长度
		float4 col; 
		//col = colM + col1*(1 - colM)*0.9f;//通过*0.9f的衰减系数,控制残影销毁
		col.rgb = colM.rbg + col1.rgb*(1 - colM.rgb)*0.9;
		//col.a = colM.a + col1.a;
        return col;
    }
    float4 fragCanYenBind(v2f pixelData) : COLOR0
    {
		float2 uuv = float2(pixelData.uv.x,1- pixelData.uv.y);
		float4 col0 = tex2D(_Tex0, uuv);//当前场景原图
		float4 col1 = tex2D(_Tex1, pixelData.uv);//上一帧的累加残影图

		float4 col; 
		col = col0 + col1*(1 - col0.a);
        return col;
    }
    ENDCG
   
Subshader {
 
	Pass {
		ZTest Always Cull Off ZWrite Off
		Fog { Mode off }

		CGPROGRAM
		#pragma glsl
		#pragma fragmentoption ARB_precision_hint_fastest 
		#pragma vertex vert
		#pragma fragment fragTestMRT
		#pragma target 3.0
		ENDCG
	}
	Pass {

		ZTest Always Cull Off ZWrite Off
		Fog { Mode off }
		//Blend one zero 
		CGPROGRAM
		#pragma glsl
		#pragma fragmentoption ARB_precision_hint_fastest 
		#pragma vertex vert
		#pragma fragment fragCanYenAdd
		#pragma target 3.0
		ENDCG
	}
	Pass {

		ZTest Always Cull Off ZWrite Off
		Fog { Mode off }
		//Blend one zero 
		CGPROGRAM
		#pragma glsl
		#pragma fragmentoption ARB_precision_hint_fastest 
		#pragma vertex vert
		#pragma fragment fragCanYenBind
		#pragma target 3.0
		ENDCG
	}
}
 
Fallback off
   
}



//可适应 主相机 在运动的 残影cs
using UnityEngine;

using System.Collections;

using System.Collections.Generic;

//[ExecuteInEditMode]

[RequireComponent(typeof(Camera))]
public class TestMRT : MonoBehaviour
{
    public Material testMRTMaterial = null;
    public RenderTexture[] mrtTex   = new RenderTexture[2];
    public RenderTexture[] TextureA = new RenderTexture[2];
    RenderBuffer[] mrtRB = new RenderBuffer[2];


    public Camera effectCame;

    public Texture texture0;
    public Texture texture1;
    public RenderTexture sourTexture;
    public RenderTexture canYanTexture;
    public RenderTexture curTexture;
    public Material CreateCanYinMaterial;
    void Start()
    {
        TextureA[0] = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
        TextureA[1] = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);

        Shader testMRT = Shader.Find("Custom/TestMRT");
        if (testMRT.isSupported)
            testMRTMaterial = new Material(testMRT);
        else
            return;
        Shader CanyanCreat = Shader.Find("Custom/CanyanCreat");
        if (CanyanCreat.isSupported)
            CreateCanYinMaterial = new Material(CanyanCreat);
        else
            return;
        StartCoroutine(ShowEffect());
    }


    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        sourTexture = source;
        //Graphics.Blit(sourTexture, source, testMRTMaterial, 0);
        if (!testMRTMaterial.shader.isSupported)
        {
            Graphics.Blit(source, destination);
            return;

        }

        //Show the result
        testMRTMaterial.SetTexture("_Tex0", sourTexture);
        testMRTMaterial.SetTexture("_Tex1", curTexture);
        //Graphics.Blit(curTexture, destination, testMRTMaterial, 2);
        Graphics.Blit(null, destination, testMRTMaterial, 2);

    }

    Dictionary<Renderer, Material[]> rendToMat = new Dictionary<Renderer, Material[]>();

    void Clear(RenderTexture destTexture)
    {
        Graphics.SetRenderTarget(destTexture);
        GL.PushMatrix();
        GL.Clear(true, true, Color.white);
        GL.PopMatrix();
    }

    void InitCanYanTexture()
    {
        //effectCame;
        GameObject cameObj = new GameObject("effectCame");
        cameObj.transform.parent = Camera.main.gameObject.transform;
        cameObj.transform.localPosition = Vector3.zero;
        effectCame = cameObj.AddComponent<Camera>();
        effectCame.CopyFrom(Camera.main);
        effectCame.clearFlags = CameraClearFlags.SolidColor;
        effectCame.backgroundColor = Color.clear;
        effectCame.enabled = false;

        if (playRoot == null)
            if (GameObject.Find("Players"))
            playRoot = GameObject.Find("Players").transform;
        if (playRoot == null)
            playRoot = GameObject.Find("GameOnly").transform.FindChild("SceneParent/PlayerRoot");

        Transform[] chs = playRoot.GetComponentsInChildren<Transform>();
        int effectLayer = LayerMask.NameToLayer("ImageEffect");
        for (int i = 0, iMax = chs.Length; i < iMax; i++)
        {
            chs[i].gameObject.layer = effectLayer;
            Renderer red = chs[i].GetComponent<Renderer>();
            if (red != null)
            {
                if (red.sharedMaterial.shader.name == "Toon/Basic" ||
                    red.gameObject.name == "m_battle_box01"||
                    red is SkinnedMeshRenderer)
                {
                    Material newMt = GameObject.Instantiate(CreateCanYinMaterial) as Material;
                    newMt.mainTexture = red.sharedMaterial.mainTexture;
                    rendToMat.Add(red, new Material[] { red.sharedMaterial, newMt });
                }
                else
                    Debuger.Log(red.sharedMaterial.shader.name);
            }

        }
        effectCame.cullingMask = 1 << effectLayer;
        canYanTexture = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
        effectCame.targetTexture = canYanTexture;
        camePos = Camera.main.transform.position;
        tarPos = tarObj.position;
        ccpos = Camera.main.transform.position - tarObj.position;
    }

    void CreateCanYanTexture()
    {
        int colorId = Shader.PropertyToID("_Color");
        Shader sd = CreateCanYinMaterial.shader;
        float i = 0;
        foreach (KeyValuePair<Renderer, Material[]> pair in rendToMat)
        {
            i += 1f;
            Renderer rd = pair.Key;
            rd.sharedMaterial = rendToMat[rd][1];
            rd.sharedMaterial.SetColor(colorId, new Color(0, 0, 1,0.7f+0.1f*i));
        }
        //GL.Clear(true, true, Color.clear);
        effectCame.Render();
        foreach (KeyValuePair<Renderer, Material[]> pair in rendToMat)
        {
            Renderer rd = pair.Key;
            rd.sharedMaterial = rendToMat[rd][0];
        }
        
    }
    public Transform tarObj;
    Vector3 camePos = Vector3.zero;
    Vector3 tarPos = Vector3.zero;

    Vector3 ccpos = Vector3.zero;
    void Update()
    {
        //Camera.main.transform.position = tarObj.position + ccpos;
    }
    private Transform playRoot;
    IEnumerator ShowEffect()
    {
        InitCanYanTexture();
        int ii = 0;
        Vector4 cameMove = Vector4.zero;

        while(true)
        {
            CreateCanYanTexture();

            if (camePos != Camera.main.transform.position)
            {
                Vector3 newTarPos = tarObj.position;
                Vector2 pm1 = effectCame.WorldToScreenPoint(tarPos);
                Vector2 pm2 = effectCame.WorldToScreenPoint(newTarPos);
                tarPos = newTarPos;
                camePos = effectCame.transform.position;
                cameMove = pm2 - pm1;
            }
            cameMove.z = Screen.width;
            cameMove.w = Screen.height;

            yield return new WaitForSeconds(0.01f);
            int a = ii % 2;//0;//
            int b = ++ii % 2;//1;//
            curTexture = TextureA[a];
            Graphics.SetRenderTarget(curTexture);
            GL.Clear(false, false, Color.clear);
            GL.PushMatrix();

            GL.LoadOrtho();
            testMRTMaterial.SetTexture("_Tex0", sourTexture);
            testMRTMaterial.SetTexture("_Tex1", TextureA[b]);
            testMRTMaterial.SetTexture("_MainTex", canYanTexture);
            testMRTMaterial.SetVector("_cameMove", cameMove);

            testMRTMaterial.SetPass(1);     //Pass 0 outputs 2 render textures.

            GL.Begin(GL.QUADS);

            GL.TexCoord2(0.0f, 0); GL.Vertex3(0.0f, 0.0f, 0.1f);

            GL.TexCoord2(1.0f, 0); GL.Vertex3(1.0f, 0.0f, 0.1f);

            GL.TexCoord2(1.0f, 1); GL.Vertex3(1.0f, 1.0f, 0.1f);

            GL.TexCoord2(0.0f, 1); GL.Vertex3(0.0f, 1.0f, 0.1f);

            GL.End();

            GL.PopMatrix();

        }
    }
}


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值