Spine 局部高亮 - daaoling/daaoling.github.io GitHub Wiki

Spine 局部高亮

效果示意图

一个摄像机照出 正常 一个摄像机照出的人渲黑 一个摄像机只照人物身上的白色小球

取黑色和白色的的交集 白色color+正常区域的颜色 其他区域取正常区域的颜色

mTestRenderImageV2.cs 挂摄像机

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using com.kuxiong.battlemodule;

/// <summary>
/// 远程英雄局部高亮管理
/// </summary>
public class mTestRenderImageV2 : View 
{


    public Dictionary<string, RenderUnit> renderUnits = new Dictionary<string, RenderUnit>();
    public class RenderUnit
    {
        public Renderer renderer;

        public Material[] initMaterials;

        public Material[] replaceMaterials;

        public GameObject instanceHightPoint;
    }


    private Camera camera;
    private Camera _setShotHeroBlackCamera; //不照光晕 打枪英雄变黑
    private Camera _onlySeePointLightCamera;//只照光晕

    public Shader outlineRepShader;
    private Material outlineRepMaterial; //如果导出的不止一个 renader 每一个render需要的replace material 都要生成一份


    public Shader outlineBiltShader;      //shader for blit
    private Material outlineBiltMaterial; //material for blit


    public RenderTexture renderTexture { get; set; }
    public RenderTexture renderTextureV2 { get; set; } 
    void Start()
    {
        if (!SystemInfo.supportsImageEffects)  {
            this.enabled = false;
            return;
        }

        RegisterMessage(this, this.notist);

        //cache
        camera = Camera.main;
        outlineRepShader = Resources.Load<Shader>(ResourcePath.FxTmp.highlight.OutLineBuff2_Shader);
        outlineBiltShader = Resources.Load<Shader>(ResourcePath.FxTmp.highlight.LocalHighLightImageEffect);
        
        CreateMaterialsIfNeeded();
    }

    void OnPreCull()
    {
        if (this.renderUnits.Count > 0)
        {
            int width = (int)camera.pixelWidth;
            int height = (int)camera.pixelHeight;
            renderTexture = RenderTexture.GetTemporary(width, height, 32, RenderTextureFormat.Default);
            renderTextureV2 = RenderTexture.GetTemporary(width, height, 32, RenderTextureFormat.Default);

            /// Create Render Camera
            if (_setShotHeroBlackCamera == null)
            {
                GameObject cameraGameObject = new GameObject("setShotHeroBlack");
                cameraGameObject.hideFlags = HideFlags.HideAndDontSave;
                _setShotHeroBlackCamera = cameraGameObject.AddComponent<Camera>();

            }

            if (_onlySeePointLightCamera == null)
            {
                GameObject cameraGameObject = new GameObject("onlySeePointLight");
                cameraGameObject.hideFlags = HideFlags.HideAndDontSave;
                _onlySeePointLightCamera = cameraGameObject.AddComponent<Camera>();
            }

            _setShotHeroBlackCamera.CopyFrom(camera); // is copy pos
            _setShotHeroBlackCamera.enabled = false;

            _onlySeePointLightCamera.CopyFrom(camera);
            _onlySeePointLightCamera.enabled = false;
            _onlySeePointLightCamera.renderingPath = RenderingPath.Forward;
            _onlySeePointLightCamera.backgroundColor = new Color(0.0f, 0.0f, 0.0f, 0.0f);
            _onlySeePointLightCamera.clearFlags = CameraClearFlags.SolidColor;
            int layerMask = 1 << ((int)com.kuxiong.battlemodule.Layers.HeroOutLine);
            _onlySeePointLightCamera.cullingMask = layerMask;


            foreach (var curKey in this.renderUnits.Keys)
            {
                RenderUnit unit = this.renderUnits[curKey];

                unit.initMaterials = unit.renderer.sharedMaterials;

                for (int z = 0; z < unit.replaceMaterials.Length; z++)
                {
                    Material curMaterial = unit.replaceMaterials[z];
                    var texture = unit.initMaterials[z].GetTexture("_MainTex");
                    curMaterial.SetTexture("_MainTex", texture);
                    unit.replaceMaterials[z] = curMaterial;
                }
                unit.renderer.sharedMaterials = unit.replaceMaterials;
            }


            _setShotHeroBlackCamera.targetTexture = renderTexture;
            _setShotHeroBlackCamera.Render();

            _onlySeePointLightCamera.targetTexture = renderTextureV2;
            _onlySeePointLightCamera.Render();

            foreach (var curKey in this.renderUnits.Keys)
            {
                RenderUnit unit = this.renderUnits[curKey];
                unit.renderer.sharedMaterials = unit.initMaterials;
            }
        }
        else {
            if (this.enabled) this.enabled = false;
        }
    }

    void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
    {
        outlineBiltMaterial.SetTexture("_heroWithBlackArea", renderTexture);
        outlineBiltMaterial.SetTexture("_pointLightArea", renderTextureV2);
        Graphics.Blit(sourceTexture, destTexture, this.outlineBiltMaterial);
        RenderTexture.ReleaseTemporary(renderTexture);
        RenderTexture.ReleaseTemporary(renderTextureV2);
    }

    void OnDestroy()
    {
        RemoveMessage(this, this.notist);

        if (_setShotHeroBlackCamera)
        {
            DestroyImmediate(_setShotHeroBlackCamera.gameObject);
            _setShotHeroBlackCamera = null;
        }
        if (_onlySeePointLightCamera)
        {
            DestroyImmediate(_onlySeePointLightCamera.gameObject);
            _onlySeePointLightCamera = null;
        }

        DestroyMaterials();
    }


    public List<string> notist = new List<string>() { NotiConst.hL };

    public override void OnMessage(IMessage message)
    {
        switch (message.Name)
        {
            case NotiConst.hL:

                object[] args = (object[])message.Body;
                string name = args[0] as string; ///高亮预设名字
                Transform invoker = args[1] as Transform; 

                ///加载高亮预设
                string prefabPath = ResourcePath.FxTmp.highlight.prefabPrePath + "/" + name;
                GameObject prefab = NGUITools.LoadAsset<GameObject>(prefabPath);
                GameObject instance = NGUITools.AddChild(invoker.transform.Find("graphic").gameObject, prefab);
                instance.transform.localPosition = prefab.transform.localPosition;
                instance.transform.localRotation = prefab.transform.localRotation;
                instance.transform.localScale = prefab.transform.localScale;
                instance.layer = prefab.layer;

                ///加载高亮预设配置
                string configPath = ResourcePath.FxTmp.highlight.configPrePath + "/" + name;
                trigger_highlight_effect hightLight_effect_cofig = NGUITools.LoadAsset<trigger_highlight_effect>(configPath);

                ///新加一个枪口火花光晕特效
                AddStartShotEffect(
                    invoker.name, 
                        invoker.transform.Find("graphic/renderer").renderer,
                            hightLight_effect_cofig.delay, instance);
                break;
            default:
                break;
        }
    }
    /// <summary>
    /// 新加一个枪口火花光晕特效
    /// </summary>
    /// <param name="nowOutlineRenders"></param>
    void AddStartShotEffect(string key, Renderer renderer, float delayTime, GameObject highLight)
    {
        if (!SystemInfo.supportsImageEffects) return;

        if (!this.enabled) this.enabled = true;

        RenderUnit resUnit = new RenderUnit()
        {
            renderer = renderer,
            initMaterials = null,
            replaceMaterials = null
        };
        //set replaceMaterials
        resUnit.replaceMaterials = new Material[resUnit.renderer.sharedMaterials.Length];
        for (int i = 0; i < resUnit.replaceMaterials.Length; i++)
        {
            resUnit.replaceMaterials[i] = new Material(this.outlineRepMaterial);
            resUnit.replaceMaterials[i].hideFlags = HideFlags.HideAndDontSave;
        }
        //set 设置高亮图片
        resUnit.instanceHightPoint = highLight;
        renderUnits.Add(key, resUnit);
        
        vp_Timer.In(delayTime, delegate() { 
            renderUnits.Remove(key);

            for (int i = 0; i < resUnit.replaceMaterials.Length; i++)
            {
                DestroyImmediate(resUnit.replaceMaterials[i]);
                resUnit.replaceMaterials[i] = null;
            }

            UnityEngine.Object.Destroy(resUnit.instanceHightPoint);
        });
    }



    #region Util
    private void CreateMaterialsIfNeeded()
    {
        this.outlineBiltMaterial = new Material(this.outlineBiltShader);
        this.outlineBiltMaterial.hideFlags = HideFlags.HideAndDontSave;

        this.outlineRepMaterial = new Material(this.outlineRepShader);
        this.outlineRepMaterial.hideFlags = HideFlags.HideAndDontSave;
    }

    private void DestroyMaterials()
    {
        DestroyImmediate(outlineBiltMaterial);
        DestroyImmediate(outlineRepMaterial);

        this.outlineBiltMaterial = null;
        this.outlineRepMaterial = null;

        //this.outlineBiltShader = null;
        //this.outlineRepShader = null;
    }
    #endregion
}

LocalHighLightImageEffect.shader

Shader "Custom/LocalHighLightImageEffect" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader 
	{
		Cull Off
		Lighting Off
		ZWrite Off
		Fog { Mode Off }
		Blend SrcAlpha OneMinusSrcAlpha

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			sampler2D _MainTex; 
			sampler2D _heroWithBlackArea;
			sampler2D _pointLightArea;

			struct vertex_input
            {
               	float4 vertex : POSITION;
               	float2 texcoord : TEXCOORD0;
				float4 color : COLOR;
            };

			struct v2f {
				float4 position : SV_POSITION;
				float2 uv : TEXCOORD0;
				float4 color : COLOR;
			};

			v2f vert(vertex_input v)
			{
				v2f o;
				o.position = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = v.texcoord;
				o.color = v.color; 
				return o;
			}

			half4 frag (v2f input) : COLOR
			{   
				half4 initPixel = tex2D(_MainTex, input.uv);
				half4 heroWithBlackArea = tex2D(_heroWithBlackArea, input.uv);
				half4 pointLightArea = tex2D(_pointLightArea, input.uv);

				half4 result = initPixel;

				if(heroWithBlackArea.r == 0 && heroWithBlackArea.g == 0 && heroWithBlackArea.b == 0)
				{
					if(pointLightArea.a > 0)
					{
						result.rgb = initPixel.rgb + pointLightArea.rgb;
						//result.rgb = half3(0,0,0);
					}
				}

				return result;
			}
			ENDCG
		}
	} 
	FallBack "Diffuse"
}

spine人物渲黑shader

OutLineBuff2.shader

Shader "Custom/OutLineBuff2" {
	Properties {
		_MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
	}
	SubShader {
		
		Tags {
		   "Queue"="Transparent"
		   "IgnoreProjector"="False"
		   "RenderType"="Transparent"
		}
		Fog { Mode Off }
		Blend One OneMinusSrcAlpha
		ZWrite Off
		Cull Off
		
		Pass 
        {
			Tags {"LightMode" = "ForwardBase"}                      // This Pass tag is important or Unity may not give it the correct light information.
           	CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //#pragma multi_compile_fwdbase                       // This line tells Unity to compile this pass for forward base.
                
            #include "UnityCG.cginc"
            //#include "AutoLight.cginc"
                    
            struct vertex_input
            {
               	float4 vertex : POSITION;
               	float2 texcoord : TEXCOORD0;
				float4 color : COLOR;
            };
                
            struct vertex_output
            {
                float4  pos         : SV_POSITION;
                float2  uv          : TEXCOORD0;
				float4  color       : COLOR;
            };
                
            sampler2D _MainTex;

            vertex_output vert (vertex_input v)
            {
                vertex_output o;
                o.pos = mul( UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.texcoord.xy;
                o.color = v.color;         
                return o;
            }
                
            fixed4 frag(vertex_output i) : COLOR
            {
                fixed4 tex = tex2D(_MainTex, i.uv);

				fixed4 finalTex = tex * (i.color * tex.a);

				if(finalTex.a > 0) finalTex.rgb = fixed3(0,0,0);

				return finalTex;
			}
            ENDCG
        }
	}
}
⚠️ **GitHub.com Fallback** ⚠️