美文网首页Unity Shader
[Unity Shader] 高级护罩Shader

[Unity Shader] 高级护罩Shader

作者: m969 | 来源:发表于2019-02-04 22:02 被阅读0次
    MagicShield.png MagicShield3.gif MagicShield.gif

    C#脚本代码(需要导入DOTween插件):

    这个脚本用于监听检测球体的射线碰撞事件,然后把碰撞的点存到数组里传给shader

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using DG.Tweening;
    
    
    public class MagicShield : MonoBehaviour {
        public Material shieldMaterial;
        public int pointsCount = 20;
        public float pointRange = 0.5f;
        public float inTime = 0.5f;
        public float outTime = 0.5f;
        public Ease ease;
        public List<HitPoint> hitPoints = new List<HitPoint>();
        public List<Vector4> vecArray = new List<Vector4>();
    
    
        void Start () {
            for (int i = 0; i < pointsCount; i++)
            {
                hitPoints.Add(new HitPoint());
                vecArray.Add(Vector4.zero);
            }
        }
    
        void Update () {
            if (Input.GetMouseButtonDown(0))
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit raycastHit;
                if (Physics.Raycast(ray, out raycastHit, 100))
                {
                    var index = -1;
                    foreach (var item in hitPoints)
                    {
                        if (item.complete)
                        {
                            index = hitPoints.IndexOf(item);
                            break;
                        }
                    }
                    if (index >= 0)
                    {
                        var hitPoint = new HitPoint();
                        hitPoint.complete = false;
                        hitPoint.position = new Vector4(raycastHit.point.x, raycastHit.point.y, raycastHit.point.z, 0);
                        hitPoints[index] = hitPoint;
                        DOTween.To(() => hitPoint.range, x => hitPoint.range = x, pointRange, inTime).OnComplete(() => { DOTween.To(() => hitPoint.range, x => hitPoint.range = x, 0f, outTime).OnComplete(() => { hitPoint.complete = true; }).SetEase(ease); }).SetEase(ease);
                    }
                }
            }
            foreach (var item in hitPoints)
            {
                var p = item.position;
                item.position = new Vector4(p.x, p.y, p.z, item.range);
                vecArray[hitPoints.IndexOf(item)] = item.position;
            }
            shieldMaterial.SetVectorArray("_Array", vecArray);
        }
    }
    
    public class HitPoint
    {
        public Vector4 position = Vector4.zero;
        public float time = 0;
        public float range = 0.1f;
        public bool complete = true;
    }
    

    Shader代码:

    Shader "MagicFire/MagicShield"
    {
        Properties
        {
            _Main("Main", 2D) = "bump" {}
            _Emission("Emission", Color) = (0,0,0,0)
            _Light("Light", Range(0 , 2)) = 0.4
            _Opacity("Opacity", Range(0 , 1)) = 0.4823529
            _Eimssion("Eimssion", Range(0 , 1)) = 2
            _Smoothness("Smoothness", Range(0 , 1)) = 1
            [HideInInspector] _texcoord("", 2D) = "white" {}
            [HideInInspector] __dirty("", Int) = 1
        }
    
        SubShader
        {
            Tags{ "RenderType" = "Transparent"  "Queue" = "Transparent+0" "IgnoreProjector" = "True" "IsEmissive" = "true"  }
            Cull Back
            CGPROGRAM
            #include "UnityPBSLighting.cginc"
            #include "UnityShaderVariables.cginc"
            #pragma target 3.0
            #pragma surface surf StandardCustomLighting alpha:fade keepalpha noshadow 
            struct Input
            {
                float2 uv_texcoord;
                float3 worldNormal;
                float3 worldPos;
            };
    
            struct SurfaceOutputCustomLightingCustom
            {
                half3 Albedo;
                half3 Normal;
                half3 Emission;
                half Metallic;
                half Smoothness;
                half Occlusion;
                half Alpha;
                Input SurfInput;
                UnityGIInput GIData;
            };
    
            uniform float4 _Emission;
            uniform float _Eimssion;
            uniform sampler2D _Main;
            uniform float4 _Main_ST;
            uniform float _Opacity;
            uniform float _Light;
            uniform float _Smoothness;
            uniform float4 _Array[20];
    
            void surf(Input i , inout SurfaceOutputCustomLightingCustom o)
            {
                float dist = 0;
                float4 color = float4(0.0, 0.0, 0.0, 1.0);
                float4 color1 = float4(1.0, 1.0, 1.0, 1.0);
                float3 ase_vertex3Pos = mul(unity_WorldToObject, float4(i.worldPos, 1));
    //下面的for循环是实现碰撞点高亮功能的主要代码
                int count = 0;
                for (count = 0; count < 20; count++)
                {
                    float3 hitPos = mul(unity_WorldToObject, float4(_Array[count].xyz, 1));
                    dist = distance(ase_vertex3Pos, hitPos);
                    color = (((dist < _Array[count].w) ? ((_Array[count].w - dist) * color1 * 10) : float4(0.0, 0.0, 0.0, 1.0))).xxxx + color;
                }
                o.SurfInput = i;
                o.Emission = (_Emission * _Eimssion).rgb + color;
            }
    
            inline void LightingStandardCustomLighting_GI(inout SurfaceOutputCustomLightingCustom s, UnityGIInput data, inout UnityGI gi)
            {
                s.GIData = data;
            }
    
            inline half4 LightingStandardCustomLighting(inout SurfaceOutputCustomLightingCustom s, half3 viewDir, UnityGI gi)
            {
                UnityGIInput data = s.GIData;
                Input i = s.SurfInput;
                half4 c = 0;
                float2 uv_Main = i.uv_texcoord * _Main_ST.xy + _Main_ST.zw;
                float2 panner72 = (0.5 * _Time.y * float2(0.1, 0.1) + uv_Main);
                float4 tex2DNode69 = tex2D(_Main, panner72);
                SurfaceOutputStandard s82 = (SurfaceOutputStandard)0;
                float4 temp_output_75_0 = ((tex2DNode69 * _Emission) + _Light);
                s82.Albedo = temp_output_75_0.rgb;
                float3 ase_worldNormal = i.worldNormal;
                s82.Normal = ase_worldNormal;
                s82.Emission = temp_output_75_0.rgb;
                s82.Metallic = 0.0;
                s82.Smoothness = _Smoothness;
                s82.Occlusion = 1.0;
    
                data.light = gi.light;
    
                UnityGI gi82 = gi;
    #ifdef UNITY_PASS_FORWARDBASE
                Unity_GlossyEnvironmentData g82 = UnityGlossyEnvironmentSetup(s82.Smoothness, data.worldViewDir, s82.Normal, float3(0, 0, 0));
                gi82 = UnityGlobalIllumination(data, s82.Occlusion, s82.Normal, g82);
    #endif
    
                float3 surfResult82 = LightingStandard(s82, viewDir, gi82).rgb;
                surfResult82 += s82.Emission;
    
                c.rgb = surfResult82;
                c.a = (tex2DNode69 * _Opacity).r;
                return c;
            }
            ENDCG
        }
    }
    

    贴图素材:

    dissolve-guide.png

    总结与发现

    这个护罩shader我是在ASE里拖出一个大概的护罩效果,然后再在源码的基础上套一个for循环实现碰撞点高亮的效果的。我看了它生成的源码发现Unity的Standard光照模型还可以这样套用,get到了。

    相关文章

      网友评论

        本文标题:[Unity Shader] 高级护罩Shader

        本文链接:https://www.haomeiwen.com/subject/zrpusqtx.html