闲云野鹤:吃鸡(三)之场景制作:制作毒圈

先上最终效果图:

电弧为shader动态效果

交界处电弧高亮(也是动态)

上部全透明

 

        思路:毒圈为吃鸡比较有特色的元素,在3dmax里面做一个72段边的圆柱,半径5米,高度500米。去掉上下底面,用“展开UV”功能调整好UV,全部塌陷后导出预制体到unity,注意物体的中心要落在底面上,再写两个脚本,一个为viewAngle.cs,一个为IntersectHightLight.shader。将viewAngle.cs挂在毒圈物体上即可。

viewAngle.cs主要实现以下几个功能:

1、设置相机.depthTextureMode模式,为shader获取深度图做准备。

2、打开摄像机HDR模式增强电弧亮度的强度。

3、由于吃鸡游戏需要狙击开镜,那么毒圈的电弧的显示强度需要与相机的fieldOfView关联:随着fieldOfView的减小而越清晰(相当于走近)。

4、实现毒圈大小的接口(通过Mul变量值控制)

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class viewAngle : MonoBehaviour
{
    Camera _camera;
    Renderer _renderer;
    float TAnangle;
    float lastfieldOfView = 1;
    public float Mul = 1f;
    float lastMul = 0;
    void Start()
    {
        _camera = Camera.main.GetComponent<Camera>();
        _camera.depthTextureMode = DepthTextureMode.Depth;//设置相机.depthTextureMode模式,为shader获取深度图做准备
        _camera.allowHDR = true;//允许摄像机HDR模式增强电弧强度
        lastfieldOfView = _camera.fieldOfView;
        _renderer = GetComponent<Renderer>();
        transform.localScale = new Vector3(1, 1, 1) * Mul;
    }

    void Update()
    {
        if (lastfieldOfView != _camera.fieldOfView)//减少运行次数
        {
            TAnangle = Mathf.Tan(22.5f * 3.14159f / 180f) / Mathf.Tan(_camera.fieldOfView * 3.14159f / 360f);//以40度为基准,得到随视角变化的放大倍数
            _renderer.material.SetFloat("_viewAngle", TAnangle);//代入毒圈的shader,
            lastfieldOfView = _camera.fieldOfView;
        }
        if (lastMul != Mul)
        {
            transform.localScale = new Vector3(1, 1, 1/Mul) * Mul;//保持毒圈高度不变,只改变水平方向大小。
            _renderer.material.SetFloat("_Mul", Mul);//代入毒圈的shader
            lastMul = Mul;
        }
    }

}

IntersectHightLight.shader 主要实现毒圈的特效。下图是我的经验值:

代码如下:

Shader "Unlit/IntersectHightLight"
{
    Properties
    {
		_MainTex ("Base (RGB)", 2D) = "white" {}//电弧
	    _MaskTex("MaskTexture", 2D) = "white" {}//电弧遮罩
	    _TurnTex("MaskTexture", 2D) = "white" {}//切换电弧
        _Color ("Color",Color) = (0,0,0,0)//毒圈颜色
        _IntersectWidth("Intersect Width",Range(0,5)) = 0.05 //相交宽度 Zintersect
        _IntersectColor("Intersect Color",Color) = (0,0,0,0) //交界颜色
		_Constrast("Constrast",Range(1,5))=3
		_lightNess("lightNess",Range(1,100))=50
		_viewAngle("ViewAngle",Range(1,500))=1
		_Mul("_Mul",Range(0,500))=1
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue" = "Transparent"}
        LOD 100
		
        Pass
        {
            //为了方便观察相交情况,设置半透,双面渲染
            ZWrite Off
            Cull off
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

			sampler2D _MainTex;
			sampler2D _MaskTex;
			sampler2D _TurnTex;
			fixed4 _MainTex_ST ;
		    fixed4 _MaskTex_ST ;
		    fixed4 _TurnTex_ST ;
			fixed _Constrast;
			fixed _lightNess;
			fixed _viewAngle;//来自unity脚本的视野放大倍数,倍数越大越近,越能看见电弧
			fixed _Mul;
            struct appdata
            {
                fixed4 vertex : POSITION;
				fixed4 texcoordMain : TEXCOORD0;
				fixed4 texcoordMask : TEXCOORD1;
				fixed4 texcoordTurn : TEXCOORD2;

            };

            struct v2f
            {
                fixed2 Z0 : TEXCOORD0;
                fixed4 scrPos : TEXCOORD1;
                fixed4 vertex : SV_POSITION;
				fixed4 uvMain : TEXCOORD3;
				fixed4 uvMask : TEXCOORD4;
				fixed2 uvTurn : TEXCOORD5;
				fixed2 uvTurnFast : TEXCOORD6;
				 fixed4 vert2world : TEXCOORD7;
				//fixed uvMain_y:TEXCOORD8;
            };

            fixed4 _Color;
            //获得深度图,注意摄像机需要设置 Camera.main.depthTextureMode = DepthTextureMode.Depth;
            
            sampler2D _CameraDepthTexture;
            fixed _IntersectWidth;
            fixed4 _IntersectColor;
           
            v2f vert (appdata v)
            {
                v2f o;
				//以下是边缘交界高亮
                o.vertex = UnityObjectToClipPos(v.vertex);
                COMPUTE_EYEDEPTH(o.Z0.x);// 在相机空间把顶点的深度存入ZO
                o.scrPos = ComputeScreenPos(o.vertex);//先把顶点在屏幕空间的位置存起来,用于片元着色器中获取深度图的深度

				o.vert2world=mul(unity_ObjectToWorld ,v.vertex);
				o.Z0.y=v.texcoordMain.y;
				//以下是电弧和频率
				_MainTex_ST.x=_Mul;//由于毒圈高度固定,所以x方向UV要随毒圈大小改变,以免电弧走形
				o.uvMain.xy = v.texcoordMain.xy * _MainTex_ST.xy + _MainTex_ST.zw;//电弧UV(空间)
				_MainTex_ST.w=-_Time.x*2;
				o.uvMain.zw = v.texcoordMain.xy * _MainTex_ST.xy*16 + _MainTex_ST.zw;//电弧UV(交界处)
				_MaskTex_ST.x=_Mul;
				o.uvMask.xy = v.texcoordMask.xy * _MaskTex_ST.xy + _MaskTex_ST.zw ;//遮罩1 UV
				_MaskTex_ST.zw=fixed2(666,666);
				o.uvMask.zw = v.texcoordMask.xy * _MaskTex_ST.xy + _MaskTex_ST.zw ;//遮罩2 UV
				_TurnTex_ST.zw += _Time.x*3;
				o.uvTurn = fixed2(0.1,0.1) * _TurnTex_ST.xy + _TurnTex_ST.zw;//用固定点按直线扫描(慢)
				_TurnTex_ST.z += _Time.w;
				o.uvTurnFast= fixed2(0.4,0.4) * _TurnTex_ST.xy + _TurnTex_ST.zw;//用固定点按直线扫描(快)
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
				//以下是电弧频率
				fixed4 albedo1 = fixed4(tex2D(_MainTex, i.uvMain.xy).rgb,0);//电弧采样
				fixed4 albedo5 =fixed4(tex2D(_MainTex, i.uvMain.zw).rgb,0);//交界处电弧采样
				fixed4 albedo2 = fixed4(tex2D(_MaskTex, i.uvMask.xy).rgb,0);//加上遮罩1
				fixed4 albedo4= fixed4(tex2D(_MaskTex, i.uvMask.zw).rgb,0);//加上遮罩2
				fixed4 albedo3 = tex2D(_MaskTex, i.uvTurnFast);//获得快闪动
				fixed3 turnRGB=step(fixed3(0.3,0.3,0.3), tex2D(_TurnTex, i.uvTurn).rgb);//根据采集rgb控制3种闪电交替闪烁


				fixed4 albedoA=pow( albedo1*albedo2*(albedo3.r+2),_Constrast)*_lightNess*15;//电弧1亮度对比度
				fixed4 albedoB=pow( albedo1*albedo4*(albedo3.g+2),_Constrast)*_lightNess*15;//电弧2亮度对比度

				fixed3 DistDir=i.vert2world-_WorldSpaceCameraPos;//受倍镜影响
				fixed sqDist= dot(DistDir,DistDir);

				                //以下是边缘交界高亮
                fixed ZdepthTexture = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture,UNITY_PROJ_COORD(i.scrPos)));
                fixed Zdiff = saturate(_IntersectWidth - abs(ZdepthTexture - i.Z0.x));//用模型的改片元的深度值 和 深度图的深度值 取差
				fixed4 junction=(albedo3+0.7).b*albedo5*Zdiff*5; //交界高亮
				
               float4 OutColor= _Color+junction+(albedoA*turnRGB.r+albedoB*turnRGB.g)*_viewAngle*_viewAngle*_IntersectColor/sqDist; //
			  // OutColor.a=(1-i.Z0.y)*(1-i.Z0.y)*(1-i.Z0.y)*(1-i.Z0.y)*0.4;
			   OutColor.a=pow(1-i.Z0.y,6)*0.4;
			   return OutColor;
            }
            ENDCG
        }
    }
}

说明:1、以上实现了基本的毒圈显示效果,也预留了毒圈在游戏中控制大小的接口:Mul变量值。但最终还要实现在游戏中按照一定规则变化,比如毒圈开始出现的位置、暂停、缩小、加速缩小等,以后再做。2、最后做了下效率测试,没多大影响,偷个懒不贴了。

所有资源(贴图、材质、代码等)已上传,可以下载:

https://download.csdn.net/download/qq_34593121/11982510

发布了13 篇原创文章 · 获赞 766 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_34593121/article/details/103111299
今日推荐