【《Unity 2018 Shaders and Effects Cookbook》提炼总结】(五)在地形周围创建一个圆圈

     许多RTS游戏通过在所选单元周围画一个圆圈来显示距离(攻击距离,移动距离,视线等)。如果地形是平坦的,这可以通过使用圆形纹理拉伸四轴来完成。如果不是这种情况,那么四轴很可能会被夹在山丘或其它几何体后面。那么怎么样我们可以在复杂的对象周围绘制圆圈。

     a.尽管处理了每一块几何体,但这种技术低面向地形。因此,第一步是在Unity 种设置地形,但不是使用模型,我们将在Unity编辑器中创建一个。

     b.创建一个shader命名为RadiusShader,并创建相关材质为RadiusMat.

     c.创建一个terrains或者下载一个,terrains是Unity中的特殊对象,纹理映射的方式与传统的3D模型不同,我们无法从shader提供_MainTex,因为它需要直接从地形本身提供,为此,选择"Paint Texture",然后单击 "Add Texture....";

     d.双击打开shader移走_Glossiness和_Metallc属性同时加入下面四个属性

     Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Center("Center",Vector) = (200,0,200,0)
        _Radius("Radius",Float) = 100
        _RadiusColor("Radius Color",Color) = (1,0,0,1)
        _RadiusWidth("Radius Width",Float) = 10
    }  

    e.在CGPROGRAM部分加入下列相关变量,同时移走_Glossiness和 _Metallic

        float3 _Center;
        float _Radius;
        fixed4 _RadiusColor;
        float _RadiusWidth;

    h.对surface function函数的输入不仅需要纹理的UV,还需要地形的每个点的位置(在世界坐标中).我们可以通过更改struct Input来检索此参数,如下所示:

       struct Input
        {
            float2 uv_MainTex;//the UV of the terrain texture
            float3 worldPos;//The in-world position
        };

    i.最后我们使用下面的surface function:

    void surf (Input IN, inout SurfaceOutputStandard o) {
            //Get the distance between the center of the place we wish to draw from and the input"s world position
            float d = distance(_Center, IN.worldPos);
            //if  the distance is larger than the radius and it is less than our radius + width change the color
            if ((d > _Radius) && (d < (_Radius + _RadiusWidth)))
            {
                o.Albedo = _RadiusColor;
            }
            //Otherwise,use the normal color
            else
            {
                o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
            }
        }

      返回到游戏场景可看到效果图如下:

源码如下:

Shader "Custom/RadiusShader" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
	    _Center("Center",Vector) = (200,0,200,0)
		_Radius("Radius",Float) = 100
		_RadiusColor("Radius Color",Color) = (1,0,0,1)
		_RadiusWidth("Radius Width",Float) = 10
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;

		struct Input
		{
			float2 uv_MainTex;//the UV of the terrain texture
			float3 worldPos;//The in-world position
		};

		float3 _Center;
		float _Radius;
		fixed4 _RadiusColor;
		float _RadiusWidth;
		fixed4 _Color;

		

		void surf (Input IN, inout SurfaceOutputStandard o) {
		    //Get the distance between the center of the place we wish to draw from and the input"s world position
			float d = distance(_Center, IN.worldPos);
			//if  the distance is larger than the radius and it is less than our radius + width change the color
			if ((d > _Radius) && (d < (_Radius + _RadiusWidth)))
			{
				o.Albedo = _RadiusColor;
			}
			//Otherwise,use the normal color
			else
			{
				o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
			}
		}
		ENDCG
	}
	FallBack "Diffuse"
}

移动圆圈

          上面已经实现了很好的效果,但是你可能还想下运行时更改圆圈的位置,我们可以通过代码执行此操作.如果你希望圆圈跟随你的角色,则需要执行其它步骤:

          a. 创建一个新的C#脚本命名为SetRadiusPropertied.

          b.由于我们可能希望在游戏中和外部都看到这种变化,我们可以在类的外部添加一个标记,表示在编辑器中执行此代码,此外还有Game正在播放时,添加以下内容标签:

          [ExecuteInEditMode]
          public class SetRadiusPropertied : MonoBehaviour 

          c.在脚本中添加以下变量

          public Material radiusMaterial;
          public float radius = 1;
          public Color color = Color.white;

          e.在Update()方法中,添加如下代码

       if(radiusMaterial != null)
        {
            radiusMaterial.SetVector("_Center", transform.position);
            radiusMaterial.SetFloat("_Radius", radius);
            radiusMaterial.SetColor("_RadiusColor", color);

        }

        h.把脚本附属到一个物体上面,然后移动物体.你会发现圆圈也会跟着移动.

它是如何运行的

        绘制圆的相关参数是其中心,半径和颜色.它们在Shader中均可,名称为 _Center,_Radius和_RadiusColor.通过将worldPos变量添加到Input结构,我们要求Unity向我们提供我们绘制的以世界坐标表示的像素的位置.这是编辑器中对象的实际位置.

        surf()函数是实际绘制圆的位置.它计算从绘制点到半径中心的距离,然后检查它是否在 _Radius和_Radius + _RadiusWidth之间,如果是这种情况,它会使用所选的颜色.在另一种情况下,它只是像我们目前所见的所有其它shader一样对纹理贴图进行采样.

以上均基于Unity2018.1.0f,源码可见我的GitHub:

https://github.com/xiaoshuivv/ShadersUnity2018.1.0f.git
 

猜你喜欢

转载自blog.csdn.net/qq_39218906/article/details/86714828
今日推荐