Unity制作护盾——3、蜂窝晶体护盾

Unity制作晶格护盾

大家好,我是阿赵。
继续来做护盾,这一期做一个蜂窝晶体护盾的效果。

一、效果展示

  这个晶体护盾的特点是,整个护盾是由很多五边形和六边形的晶体构成,每一块晶体的颜色都在不停的变化,然后每一块晶体都可以单独的浮动。
在这里插入图片描述

根据设置的偏移值不一样,晶体可以往外扩散
在这里插入图片描述

也可以往内聚合
在这里插入图片描述

当鼠标点击模拟攻击护盾的时候,被攻击的护盾会浮起来做一个波浪往四周扩散。
在这里插入图片描述

二、原理分析

要做这个效果,需要美术资源和shader相结合。

1、美术资源准备

1.制作球体

这里要先准备一个由五边形和六边形组成的球体
在这里插入图片描述

怎样制作这个球体呢?可以参考一下这个步骤:
(1)创建一个GeoSphere
(2)塌陷为EditablePoly
(3)选择所有顶点
(4)给所有顶点做一个倒角
在这里插入图片描述

2.分离多边形面

接下来我们要把这些五边形和六边形的面分离,具体做法是选择所有的顶点,然后break一下。
在这里插入图片描述
在这里插入图片描述

现在所有的面都是独立的了。

3.展UV

这个效果的一个重点,就是展UV。我们先把刚才所有的面正常的展开,不要重叠。
在这里插入图片描述

然后选中所有的面,使用Tools/Relex工具,类型选中Relex By Centers,点击Start Relex按钮
在这里插入图片描述
在这里插入图片描述

结束后,所有的面都按照中心点缩放成一个点了。
在这里插入图片描述

2、制作晶体颜色闪烁

  这里其实很简单,就是用一张噪声图做UV动画而已。那么为什么看起来是每一个晶体的颜色都是整体变化,而看不出来是噪声图渐变呢?这是因为上面把所有面的UV都缩成一个点了,所以每个面在采样的时候,只会采样到噪声图的一个像素,看起来就是每个面的颜色都是独立的。
在这里插入图片描述
在这里插入图片描述

3、制作晶体扩散

  还是刚才那张噪声图,然后在顶点着色器程序进行采样,得到了每个晶体不同深浅的颜色,然后根据这个不同深浅,沿着法线方向做偏移而已。
  不过这里有一个问题,tex2D采样只能用在片段着色器程序,如果我们想在顶点着色器程序采样,要用tex2Dlod方法。

4、制作点击扩散

  点击扩散,其实就是上一篇文章里面的冲击波护盾的做法了。只不过冲击波护盾改变的是颜色,我们这里改变的是形状,所以需要在顶点着色器程序里面写。同意通过数组传入最多10个顶点信息和扩散大小。

三、代码

C#代码和冲击波护盾的时候一样。下面提供一下Shader的写法

Shader "azhao/GridShield"
{
    Properties
    {
		_NoiseTex("NoiseTex", 2D) = "white" {}
		_dir("dir", Vector) = (0,0,0,0)
		_speed("speed", Range(0 , 2)) = 1
		_offsetVal("offsetVal", Range(-1 , 1)) = 1
		[HDR]_baseColor("baseColor", Color) = (1,1,1,0)
		_alphaMul("alphaMul", Range(0 , 1)) = 0

		_diffuse("diffuse", Range(0 , 1)) = 0
		_gradient("gradient", 2D) = "white" {}
		_minOffset("minOffset",float) = 0.1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
		Blend SrcAlpha OneMinusSrcAlpha, SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;

				float2 uv :TEXCOORD0;
				float3 normal: NORMAL;

            };

            struct v2f
            {
				float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
				float3 vertex_world:TEXCOORD1;
				float3 normal_world:TEXCOORD2;
                
            };

			uniform sampler2D _NoiseTex;
			SamplerState sampler_NoiseTex;
			uniform float2 _dir;
			uniform float _speed;
			uniform float _offsetVal;
			uniform sampler2D _gradient;
			SamplerState sampler_gradient;

			uniform float _diffuse;
			uniform float4 _baseColor;
			uniform float _alphaMul;
			float3 _hitCenter[10];
			float _hitSize[10];
			float _minOffset;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
				float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				o.normal_world = UnityObjectToWorldNormal(v.normal);
				float4 tex2DNode2 = tex2Dlod(_NoiseTex, float4((v.uv + (_dir * frac((_Time.y * _speed)))), 0, 0.0));
				float3 vertexValue = float3(0, 0, 0);
				for (int i = 0; i < 10; i++)
				{
					float2 appendResult = (float2(((distance(_hitCenter[i], worldPos) - _hitSize[i]) / _diffuse), 0.0));
					float clampResult = clamp((tex2Dlod(_gradient, float4(appendResult, 0, 0.0)).r + (max(_hitSize[i], 0.0) * -1.0)), 0.0, 1.0);
					clampResult = max(clampResult, _minOffset);
					vertexValue += (o.normal_world * tex2DNode2.r * _offsetVal * (clampResult * 0.5));
				}

				o.uv = v.uv;
				v.vertex.xyz += vertexValue;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.vertex_world = mul(unity_ObjectToWorld, v.vertex).xyz;
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
				float4 tex2DNode2 = tex2D(_NoiseTex, (i.uv + (_dir * frac((_Time.y * _speed)))));
				half4 finalColor = (float4((_baseColor * tex2DNode2).rgb , max((max(tex2DNode2.r , 0.1) * _alphaMul) , 0.0)));

				return finalColor;
            }
            ENDCG
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liweizhao/article/details/132221220