# 【Shader练习-血条】

全屏显示

包括了以下练习内容:

  1. 裁剪圆角矩形。
  2. 血量少于一定百分比时闪烁。
  3. 血条使用位图采样纹理。
  4. 通过C#代码修改材质参数。

该图片用于采样血量颜色。

Markdown 图片

Shader "Examples/BloodBarAlpha/Shader/Healthbar" {
    Properties {
        _HP("血量百分比",Range(0.0,1.0)) = 0.5
        _BorderSize("边界距离",Range(0.0,0.5)) = 0.1
        _Tex("渐变纹理",2D) = "white" {}
    }
    SubShader {
        Tags {
            "RenderType"="Transparent"
            "ForceNoShadowCasting" = "True"             // 不捕获阴影
            "IgnoreProjector"= "True"                   // 忽略投影
        }
        Pass {
            Zwrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            // 当前的显示血量百分比
            uniform float _HP;
            uniform float _BorderSize;
            uniform sampler2D _Tex;

            struct VertexInput {
                float4 vertex : POSITION;
                float4 uv0 : TEXCOORD0;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float4 uv0 : TEXCOORD0;
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.pos = UnityObjectToClipPos( v.vertex );
                o.uv0 = v.uv0;
                return o;
            }

            half4 frag(VertexOutput i) : COLOR {
                ///////////////////////////////////// 圆角部分 /////////////////////////////////////
                // 坐标由0~1扩展成0~8
                float2 coords = i.uv0;
                coords.x *= 8;
                // 一条线段,x值是 0.5~7.5之间 y值是 0.5
                float2 pointOnLineSeg = float2(clamp(coords.x,0.5,7.5),0.5);
                // 使用距离函数,获取当前坐标点与线段之间的距离
                // 乘以2 -1 可以让圆角内的值为正数,圆角外的值为负数
                float sdf = distance(coords,pointOnLineSeg)*2-1;
                // 剪裁负数部分,也就是去掉圆角外的像素
                clip(-sdf);

                // 边界
                float borderSdf = sdf + _BorderSize;
                float pd = fwidth(borderSdf);
                // 这样处理的边界,显得更加圆滑
                // saturate 函数可以把值限制在0~1之间,大于1为1,小于0为0
                float borderMask = 1 - saturate(borderSdf / pd);

                ////////  血量部分 //////////////////////////
                // 显示血量为1,显示空为0
                bool b = i.uv0.x < _HP;

                // 根据血量百分比采样颜色,健康绿色,危险红色。
                half4 bloodColor = tex2D(_Tex,float2(_HP,i.uv0.y));

                ////////  血量不足时候闪烁动画显示
                float flash = 1;
                if(_HP <= 0.2){
                    flash = 1 + cos(_Time.y*4) * 0.5;
                }
                bloodColor = bloodColor * flash;

                // 背景的颜色
                half4 bgColor = half4(0,0,0,1);
                // 插值背景颜色和血量颜色
                half4 endColor = lerp(bgColor,bloodColor,b);
                return half4(endColor.rgb * borderMask,1);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}
using UnityEngine;
public class ControlBloodScript : MonoBehaviour
{
    public Material material;
    void Start()
    {
        ChangeBi(0.5f);
    }
    
    public void ChangeBi(float value)
    {
        if(material == null)
        {
            material = GetComponent<MeshRenderer>().material;
        }
        material.SetFloat("_HP",value);
    }
}

度盘:https://pan.baidu.com/s/13fxLg3j9xMGfKdpHEH1zhw?pwd=66a1 (opens new window)