VR 射击馆(二)射箭逻辑、后处理

2020-12-07  本文已影响0人  烂醉花间dlitf

写在前面

这个系列我删掉了一些东西,所以变成了碎碎念 + 收集癖的记录而已。en... 参考意义不大,建议随便看看...

射箭逻辑

一开始是完全没有用动画,后来加上动画之后出现了很多相应的问题,比如动画没有执行完就执行了后面的代码导致的空指针,比如协程重复被开启,比如目标转换和现在的旋转是一样的话,就会原地转一圈.....通过一次次断点和猜测全部解决之后发现,有动画的效果并没有没有动画的好,于是又把很多地方的动画持续时间设为了0......
整体思路就是:
左手在碰到弓的时候按住 Trigger 可以拿起来,右手直接按 Trigger 可以从空中飞来一只箭握到手中(?牛顿不重要,游戏体验好就 Ok!)

    // 抖动采样相关
    public float SampleJitterTime = 1; // 采样 1s 内的抖动,单位:秒
    private const int sampleTimes = 10;
    public float MinJitterDistance = 0.002f;
    public float MaxJitterDistance = 0.01f;
    public Queue<Vector3> controller0HeadJitterDueue = new Queue<Vector3>(sampleTimes); // 左手头抖动,采样 10 次,不能只采样手柄的位置,不然旋转检测不出来,
                                                                                        // 虽然现在也检测不出来 Y 轴方向的抖动,但是一般也不会按照这个方向旋转

    public Queue<Vector3> controller0TailJitterDueue = new Queue<Vector3>(sampleTimes);
    public Queue<Vector3> controller1HeadJitterDueue = new Queue<Vector3>(sampleTimes);
    public Queue<Vector3> controller1TailJitterDueue = new Queue<Vector3>(sampleTimes);
    private float lastSampleTime;
        // 根据抖动系数让箭稍微偏一点点
        CheckJitter(out float controller0JitterK, out float controller1JitterK);
        float angle = (controller0JitterK + controller1JitterK) /2 * 7f * Mathf.PI / 180; // 最大偏移 7 度
        DebugText.Instance().SetInfo("angle", angle.ToString());
        float random_angle = new System.Random().Next(0,360) * Mathf.PI / 180; // 随机向一个方向偏移
        Vector3 offset_point = new Vector3(Mathf.Sin(random_angle), 1.0f / Mathf.Tan(angle), Mathf.Cos(random_angle)); // 因为箭的 up 是朝前的,
                                                                                                      // 而且 sin(random_angle)平方 + cos(random_angle)平方 = 1

后处理(Bloom 效果)

因为模型有事情,所以自己找的模型搭建了如下场景,增色的就是发光效果,实现如下(这个我是直接 Copy 来着,先记录一下,再仔细研究)

using UnityEngine;

[ExecuteInEditMode]
//屏幕后处理效果主要是针对摄像机进行操作,需要绑定摄像机
[RequireComponent(typeof(Camera))]
public class ScreenEffectBase : MonoBehaviour
{
    public Shader shader;
    private Material material;
    protected Material Material
    {
        get
        {
            material = CheckShaderAndCreatMat(shader, material);
            return material;
        }
    }

    //用于检查并创建临时材质
    private Material CheckShaderAndCreatMat(Shader shader, Material material)
    {
        Material nullMat = null;
        if (shader != null)
        {
            if (shader.isSupported)
            {
                if (material && material.shader == shader) { }
                else
                {
                    material = new Material(shader) { hideFlags = HideFlags.DontSave };
                }
                return material;
            }
        }
        return nullMat;
    }
}
场景
using UnityEngine;

public class BloomCtrl : ScreenEffectBase
{
    private const string _LuminanceThreshold = "_LuminanceThreshold";
    private const string _BlurSize = "_BlurSize";
    private const string _Bloom = "_Bloom";

    [Range(0, 4)]
    public int iterations = 3;
    [Range(0.2f, 3.0f)]
    public float blurSize = 0.6f;
    [Range(1, 8)]
    public int dowmSample = 2;
    [Range(0.0f, 10.0f)]
    public float luminanceThreshold = 0.6f;//控制Bloom效果的亮度阈值,因为亮度值大多数时不大于1,故该值超过1时一般无效果,但开启HDR后图像的亮度取值范围将扩大

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (Material != null)
        {
            Material.SetFloat(_LuminanceThreshold, luminanceThreshold);

            int rth = source.height / dowmSample;
            int rtw = source.width / dowmSample;

            RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
            buffer0.filterMode = FilterMode.Bilinear;

            //第1个Pass中提取纹理亮部,存到buffer0中,以便后面进行高斯模糊处理
            Graphics.Blit(source, buffer0, Material, 0);

            for (int i = 0; i < iterations; i++)
            {
                Material.SetFloat(_BlurSize, blurSize * i + 1.0f);

                //第2,3个Pass中对亮部分别进行纵向和横向的渲染处理(高斯模糊)
                RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, 0);
                Graphics.Blit(buffer0, buffer1, Material, 1);
                RenderTexture.ReleaseTemporary(buffer0);//临时创建的渲染纹理不能直接释放 x: buffer0.Release();

                buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
                Graphics.Blit(buffer1, buffer0, Material, 2);
                RenderTexture.ReleaseTemporary(buffer1);
            }

            //第4个Pass将buffer0高斯模糊后的结果传给_Bloom以进行最后的混合
            Material.SetTexture(_Bloom, buffer0);
            Graphics.Blit(source, destination, Material, 3);//注意这里用原始纹理作为源纹理而不是buffer0,因为buffer0已经作为另一个参数进行了传递,而这里还需要原始的纹理以进行混合
            RenderTexture.ReleaseTemporary(buffer0);
        }
        else
            Graphics.Blit(source, destination);
    }
}
Shader "MyUnlit/Bloom"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Bloom("Bloom",2D)="black"{}
        _LuminanceThreshold("Luminance Threshold",Float)=0.5
        _BlurSize("Blur Size",Float)=1.0
    }
    SubShader
    {
        CGINCLUDE

        #include "UnityCG.cginc"

        sampler2D _MainTex;
        half4 _MainTex_TexelSize;
        sampler2D _Bloom;
        float _LuminanceThreshold;
        float _BlurSize;

        struct v2f
        {
           half2 uv : TEXCOORD0;
           float4 pos : SV_POSITION;
        };

        struct v2fBloom
        {
           //half4是因为这里还要存储_Bloom纹理
           half4 uv:TEXCOORD0;
           float4 pos:SV_POSITION;
        };

        v2f vert(appdata_img v)
        {
           v2f o;
           o.pos=UnityObjectToClipPos(v.vertex);
           o.uv=v.texcoord;
           return o;
        }

        v2fBloom vertBloom(appdata_img v)
        {
           v2fBloom o;
           o.pos=UnityObjectToClipPos(v.vertex);

           //xy存储主纹理,zw存储_Bloom纹理,这样不必再申请额外空间
           o.uv.xy=v.texcoord;
           o.uv.zw=v.texcoord;

           //纹理坐标平台差异化判断,主要针对DirectX,因为DirectX与OpenGL纹理坐标原点不同(分别在左上和左下)
           //同时Unity平台对于主纹理已经进行过内部处理,因此这里只需要对_Bloom纹理进行平台检测和翻转
           //主要表现为进行y轴方向的翻转(因为y轴方向相反),对于_Bloom纹理来说也就是w
           #if UNITY_UV_STARTS_AT_TOP
           if(_MainTex_TexelSize.y<0){
                  o.uv.w=1.0-o.uv.w;
           }
           #endif

           return o;
        }

        //提取超过亮度阈值的图像
        fixed4 fragExtractBright(v2f i):SV_Target
        {
            fixed4 col=tex2D(_MainTex,i.uv);
            fixed val=clamp(Luminance(col)-_LuminanceThreshold,0.0,1.0);
            return col*val;
        }

        //对xy和zw对应的纹理采样进行混合
        fixed4 fragBloom(v2fBloom i):SV_Target
        {
            return tex2D(_MainTex,i.uv.xy)+tex2D(_Bloom,i.uv.zw);
        }

        ENDCG

        ZTest Always
        Cull Off
        ZWrite Off

        //Pass 1:提亮部
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment fragExtractBright
            ENDCG
        }

        //Pass 2,3:高斯模糊,这里直接调用以前写的Pass
        UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_V"

        UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_H"

        //Pass 4:混合原图和模糊后亮部
        Pass
        {
            CGPROGRAM
            #pragma vertex vertBloom
            #pragma fragment fragBloom
            ENDCG
        }
    }
    Fallback Off
}
上一篇 下一篇

猜你喜欢

热点阅读