zoukankan      html  css  js  c++  java
  • [Unity]利用Mesh绘制简单的可被遮挡,可以探测的攻击指示器

    最近做一个小游戏的Demo,最终的效果是这样的

    主要是利用Mesh绘制三角形作为显示,然后使用后处理来制作探灯,注意,性能一般,仅仅适合小游戏

    分为3步

    1:利用mesh绘制三角形,原理很简单,利用三角函数Tan,给定一个角度计算三角形左或者右一个顶点,最后绘制即可

     1 void DrawIt()
     2     {
     3         if (distance > 0 && angle > 0)//angle角度的一半,distance指三角形起点到另外两点间的距离
     4         {
     5             Mesh mesh = new Mesh();
     6             float pointY = Mathf.Tan(angle * Mathf.Deg2Rad) * distance;//
     7             Vector3 p1 = new Vector3(distance, transform.localPosition.y, pointY);
     8             Vector3 p2 = new Vector3(distance, transform.localPosition.y, -pointY);
     9             mesh.vertices = new[] { transform.localPosition, p1, p2 };
    10             mesh.triangles = new[] { 0, 1, 2 };
    11             transform.GetComponent<MeshFilter>().mesh = mesh;
    12         }
    13     }

    2:为了制作出被墙壁阻挡得效果,用了最笨得方法,即按照每一度都计算一个点,最后连成三角形,上面得三角形只有三个点,这步制作得可能有N个点,然后从每个起点向终点发射射线,如果有碰撞就将顶点修改为碰撞点,为了让三角形每个点足够平滑,还是用了一个缩放来增加顶点数

     1     void DrawItMore()
     2     {
     3         if (distance > 0 && angle > 0)//distance:三角形起点到某点的距离,用在Tan函数,angle,三角形角度的一半
     4         {
     5             Mesh mesh = new Mesh();
     6             List<Vector3> point = new List<Vector3>();
     7             point.Add(transform.localPosition);
     8             List<Vector3> pointLeft = new List<Vector3>();
     9             List<Vector3> pointRight = new List<Vector3>();
    10             RaycastHit hit;
    11             for (int i = angle * LineScale; i > 0; i--)//LineScale,没一度都发射射线还不够细,一般这个值为5比较合适(缩放1的时候),性能消耗主要在这
    12             {
    13                 float index = i / (float)LineScale;
    14                 float pointY = Mathf.Tan(index * Mathf.Deg2Rad) * angle;
    15                 Vector3 p1 = new Vector3(distance, transform.localPosition.y, pointY);
    16                 Vector3 world = transform.TransformPoint(p1);
    17                 if (Physics.Linecast(transform.position, world, out hit, 1 << LayerMask.NameToLayer("Wall")))//只和Wall Layer进行检测
    18                 {
    19                     p1 = transform.InverseTransformPoint(hit.point);
    20                 }
    21                 Vector3 p2 = new Vector3(GameModel.Ins.MainRoleData.AtkRange, transform.localPosition.y, -pointY);
    22                 if (Physics.Linecast(transform.position, transform.TransformPoint(p2), out hit, 1 << LayerMask.NameToLayer("Wall")))
    23                 {
    24                     p2 = transform.InverseTransformPoint(hit.point);
    25                 }
    26                 pointLeft.Add(p1);
    27                 pointRight.Insert(0, p2);
    28             }
    29             point.AddRange(pointLeft);
    30             point.AddRange(pointRight);
    31             List<int> triangles = new List<int>();//简单设置顶点连接顺序,注意unity顺时针才是正面
    32             for (int i = 1; i < point.Count - 1; i++)
    33             {
    34                 triangles.Add(i);
    35                 triangles.Add(i + 1);
    36                 triangles.Add(0);
    37             }
    38             mesh.vertices = point.ToArray();
    39             mesh.triangles = triangles.ToArray();
    40             transform.GetComponent<MeshFilter>().mesh = mesh;
    41         }
    42     }

    3:遮挡完成了,最后一步就是制作三角形探测,大概原理是新建一个相机仅仅渲染绘制的三角形,并且修改相机设置为Don't Clear,然后将此相机渲染到纹理,最后和主相机利用屏幕后处理进行混合

    3.1:新建相机设置,主要是ClearFlags和CullingMask(裁剪设置,只渲染绘制的三角形),主相机叫相机A,新相机就是相机B

    3.2:将此相机渲染到纹理,并为混合Shader赋值

    1 void Start()
    2     {
    3         var t = new RenderTexture(Screen.width, Screen.height, 16);
    4         GetComponent<Camera>().targetTexture = t;
    5         Mat.SetTexture("_LOSMaskTexture", t);//Mat是后面用到的Shader,这里仅仅为Shader图片赋值,也可以不用代码创建RenderTexture,随意
    6     }

    3.3:编写混合Shader,就是单纯的根据某个通道值叠加

     1 Shader "Custom/LOSMaskShader"
     2 {
     3     Properties
     4     {
     5         _MainTex("MainTex",2D) = "white"{}
     6         _LOSMaskTexture("LOSMaskTexture",2D) = "white"{}//相机B生成的图
     7         _MaskScale("MaskScale", float) = 0.5//混合比例
     8     }
     9     SubShader
    10     {
    11         // No culling or depth
    12         Cull Off ZWrite Off ZTest Always//屏幕后处理的标配
    13 
    14         Pass
    15         {
    16             CGPROGRAM
    17             #pragma vertex vert
    18             #pragma fragment frag
    19             
    20             #include "UnityCG.cginc"
    21 
    22             struct appdata
    23             {
    24                 float4 vertex : POSITION;
    25                 float2 uv : TEXCOORD0;
    26             };
    27 
    28             struct v2f
    29             {
    30                 float2 uv : TEXCOORD0;
    31                 float4 vertex : SV_POSITION;
    32             };
    33 
    34             v2f vert (appdata v)
    35             {
    36                 v2f o;
    37                 o.vertex = UnityObjectToClipPos(v.vertex);
    38                 o.uv = v.uv;
    39                 return o;
    40             }
    41             
    42             sampler2D _LOSMaskTexture;
    43             sampler2D _MainTex;
    44             float _MaskScale;
    45 
    46             fixed4 frag (v2f i) : SV_Target
    47             {
    48                 float4 mask = tex2D(_LOSMaskTexture,i.uv);
    49                 float4 main = tex2D(_MainTex,i.uv);
    50 
    51                 main = main * saturate(mask.r + _MaskScale);    //这里提取相机B的R值作为混合,MsakScale越高自然整体越亮
    52                 return main;
    53             }
    54             ENDCG
    55         }
    56     }
    57 }

    3.4:最后一步,利用OnRenderImage应用屏幕后处理效果

    1 private void OnRenderImage(RenderTexture source, RenderTexture destination)
    2     {
    3         Graphics.Blit(source, destination, LOSMaskMaterial);//Mat是上面Shader的Mat
    4     }

    Over,对Shader不熟悉的可以看看资料,高性能的等以后有机会了专门研究下,完结撒花

  • 相关阅读:
    创建类type (底层代码)
    getitem, setitem, delitem (把类实例化成字典的类型)
    类的三种方法(静态方法,类方法,属性方法)
    class(类的使用说明)
    Java泛型
    Java时间操作常用api
    JVM加载class文件的原理机制
    int和Integer区别
    final
    Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
  • 原文地址:https://www.cnblogs.com/wayneWy/p/13496861.html
Copyright © 2011-2022 走看看