Єдність туман війни підручник. Частина 2. Мобільна версія (демонстрація)

Ця стаття є розширенням мого попереднього посібника про реалізацію туману війни в Unity. Моя попередня техніка хороша для мобільного пристрою, але все ще занадто важка для нього. Ось чому я напишу мобільну версію fog of war для Unity в цьому маленькому посібнику.  Це буде виглядати інакше, помилка працюватиме швидше.

Автор: Сергій Тарабан

Частина 1

Демонстрація веб-плеєра

fog_of_war_vertex

Використовуйте кнопки WASD для керування рухом гравця.

Завантажити файл пакета: fog_of_war_tutorial.unitypackage

Для Unity 5 додайте “alpha:blend” до рядка #pragma surface surf Lambert vertex:vert

Новий шейдер діафрагми

Для збільшення кадрів в секунду я переміщую алгоритм обчислення діафрагми від фрагментного до вершинного шейдера. Це зробить мій шейдер більш легким.  Після цього кількість проходів шейдера буде залежати від номера вершини в 3D-моделі, а не від кількості фрагментів на екрані. 3D модель у зовнішньому корпусі - туман бойового літака.

Вам потрібно створити новий шейдер і скопіювати в нього наведений нижче код. Потім прикріпіть шейдер до туману військового матеріалу.

// Шейдер FogOfWarVertex
// Copyright (C) 2013 Сергій Тарабан 
//
// Цим надається безкоштовний дозвіл будь-якій особі, яка отримує копію цього програмного забезпечення та пов’язаних файлів документації («Програмне забезпечення»), працювати з Програмним забезпеченням без обмежень, включаючи, без обмежень, права на використання, копіювання, зміну, об’єднання, публікацію, розповсюдження, субліцензування та/або продаж копій Програмного забезпечення, а також дозволяти особам, яким надано Програмне забезпечення, робити це за таких умов:
// Наведене вище повідомлення про авторські права та це повідомлення про дозвіл мають бути включені до всіх копій або значних частин Програмного забезпечення.
// ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ НАДАЄТЬСЯ «ЯК Є», БЕЗ БУДЬ-ЯКИХ ГАРАНТІЙ, ЯВНИХ АБО НЕПРЯМИХ, ВКЛЮЧАЮЧИ, АРЕМЕ ОБМЕЖУЮЧИСЬ, ГАРАНТІЇ ПРИДАТНОСТІ ДЛЯ ПРОДАЖУ, ВІДПОВІДНОСТІ ДЛЯ КОНКРЕТНОЇ МЕТИ ТА ВІДСУМНОСТІ ПРАВ. АВТОРИ АБО ВЛАСНИКИ АВТОРСЬКИХ ПРАВ НЕ НЕСУТЬ ВІДПОВІДАЛЬНОСТІ ЗА БУДЬ-ЯКІ ПРЕТЕНЗІЇ, ЗБИТКИ АБО ІНШУ ВІДПОВІДАЛЬНІСТЬ В наслідок КОНТРАКТНОЇ ДІЇ, ДЕЛІКТУ ЧИ В ІНШОМУ ВИПАДКУ, ЩО ВИНИКАЄ ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ, ВИКОРИСТАННЯ АБО ІНШИМИ ОПЕРАЦІЯМИ, ЧИ У ЗВ’ЯЗКУ З НИМ ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ.
//

Шейдер "Custom/FogOfWarGeom" {
    Властивості {
        _Color ("Основний колір", колір) = (1,1,1,1)
        _MainTex ("Колір (RGB) Альфа (A)", 2D) = "білий"
        _FogRadius ("FogRadius", Float) = 1,0
        _FogMaxRadius ("FogMaxRadius", Float) = 0,5
        _Player1_Pos ("UnitPos1", вектор) = (0,0,0,1)
        _Player2_Pos ("UnitPos2", вектор) = (0,0,0,1)
        _Player3_Pos ("UnitPos3", вектор) = (0,0,0,1)
    }

    SubShader {
        Теги { "Queue"="Прозорий" "RenderType"="Прозорий" }
        Суміш SrcAlpha OneMinusSrcAlpha
        ZWrite On
        Відбір 

        CGPROGRAM
        #pragma target 3.0
        #pragma surface surf Lambert vertex:vert alpha:blend

        sampler2D _MainTex;
        fixed4 _Color;
        float4 _Player1_Pos;
        float4 _Player2_Pos;
        float4 _Player3_Pos;
        float _FogRadius;
        float _FogMaxRadius;        struct Input {
            float4 pos;
            поплавок альфа;
            розташування float2;
        };

        float powerForPos(float4 pos, float2 nearVertex);

        void vert (inout appdata_full vertexData, out Input outData)
        {
            float2 posVertex = mul (_Object2World, vertexData.vertex).xz;
            outData.alpha = (1.0 - затискач (_Color.a 
                        + ( powerForPos(_Player1_Pos, posVertex) 
                        + powerForPos(_Player2_Pos, posVertex)
                        + powerForPos(_Player3_Pos, posVertex) ), 0, 1.0));
        }

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = _Color.rgb;
            o.Alpha = IN.alpha;
        }

        float powerForPos(float4 pos, float2 nearVertex) {
             float attenumat = clamp(_FogRadius - abs(length(pos.xz - nearVertex.xy)), 0.0, _FogRadius);
             if(attenumat > _FogRadius*_FogMaxRadius) {
                 attenumat = _FogRadius*_FogMaxRadius;  
             }
            return (1.0/_FogMaxRadius)*(attenumat/_FogRadius);
        }

        ENDCG
    }

Запасний варіант "Прозорий/VertexLit"
}

Скрипт для генерації площини

Тепер нам потрібно написати скрипт для генерації площини з різною кількістю вершин. За основу я використав сценарій редактора CreatePlane з вікіпедії Unity. Я змінив його на сценарій MonoBehaviour.

Скопіюйте наведений нижче код до нового сценарію та прикріпіть його до об’єкта бойового літака. Якщо у вас є Mesh Collider, змініть його на Box Collider із розміром (1, 0,01, 1). Потім встановіть необхідний масштаб об’єкта.

використання UnityEngine;
використання System.Collections;

відкритий клас CreatePlaneScript: MonoBehaviour
{

    загальнодоступний перелік Орієнтація
    {
        Горизонтальний,
        Вертикальний
    }

    публічний перелік AnchorPoint
    {
        Верхній лівий,
        верхня половина,
        Верхній правий,
        RightHalf,
        BottomRight,
        нижня половина,
        BottomLeft,
        LeftHalf,
        центр
    }

    public int widthSegments = 1;
    public int lengthSegments = 1;
    public float width = 1.0f;
    публічна довжина float = 1.0f;
    публічна орієнтація orientation = Orientation.Horizontal;
    public AnchorPoint anchor = AnchorPoint.Center;
    public bool addCollider = false;
    public bool createAtOrigin = true;
    відкритий рядок optionalName;

    void Start()
    {
        BuildPlane();
    }

    void Update()
    {
        widthSegments = Mathf.Clamp(widthSegments, 1, 254);
        lengthSegments = Mathf.Clamp(lengthSegments, 1, 254);
    }

    public void BuildPlane()
    {        Vector2 anchorOffset;
        string anchorId;
        перемикач (якір)
        {
        case AnchorPoint.TopLeft:
            anchorOffset = new Vector2(-width/2.0f,length/2.0f);
            anchorId = "TL";
            розрив;
        case AnchorPoint.TopHalf:
            anchorOffset = новий Vector2(0.0f,length/2.0f);
            anchorId = "TH";
            розрив;
        case AnchorPoint.TopRight:
            anchorOffset = новий Vector2(ширина/2.0f,довжина/2.0f);
            anchorId = "TR";
            розрив;
        case AnchorPoint.RightHalf:
            anchorOffset = new Vector2(width/2.0f,0.0f);
            anchorId = "RH";
            розрив;
        case AnchorPoint.BottomRight:
            anchorOffset = new Vector2(width/2.0f,-length/2.0f);
            anchorId = "BR";
            розрив;
        case AnchorPoint.BottomHalf:
            anchorOffset = new Vector2(0.0f,-length/2.0f);
            anchorId = "BH";
            розрив;
        case AnchorPoint.BottomLeft:
            anchorOffset = new Vector2(-width/2.0f,-length/2.0f);
            anchorId = "BL";
            розрив;            
        case AnchorPoint.LeftHalf:
            anchorOffset = новий Vector2(-width/2.0f,0.0f);
            anchorId = "LH";
            розрив;            
        випадок AnchorPoint.Center:
        за замовчуванням:
            anchorOffset = Vector2.zero;
            anchorId = "C";
            розрив;
        }

        MeshFilter meshFilter = this.GetComponent();

        Сітка m = нова сітка();
        m.name = this.name;

        int hCount2 = widthSegments+1;
        int vCount2 = lengthSegments+1;
        int numTriangles = widthSegments * lengthSegments * 6;
        int numVertices = hCount2 * vCount2;

        Vector3[] vertices = new Vector3[numVertices];
        Vector2[] uvs = new Vector2[numVertices];
        int[] triangles = новий int[numTriangles];

        індекс int = 0;
        float uvFactorX = 1.0f/widthSegments;
        float uvFactorY = 1.0f/lengthSegments;
        float scaleX = width/widthSegments;
        float scaleY = довжина/довжина сегментів;
        for (float y = 0.0f; y < vCount2; y++)
        {
            for (float x = 0.0f; x < hCount2; x++)
            {
                if (orientation == Orientation.Horizontal)
                {
                    vertices[index] = new Vector3(x*scaleX - width/2f - anchorOffset.x, 0.0f, y*scaleY - length/2f - anchorOffset.y);
                }
                інше
                {
                    vertices[index] = new Vector3(x*scaleX - width/2f - anchorOffset.x, y*scaleY - length/2f - anchorOffset.y, 0.0f);
                }
                uvs[індекс++] = новий Вектор2(x*uvFactorX, y*uvFactorY);
            }
        }

        індекс = 0;
        for (int y = 0; y < lengthSegments; y++)
        {
            for (int x = 0; x < widthSegments; x++)
            {
                трикутники[індекс]   = (y     * hCount2) + x;
                трикутники[індекс+1] = ((y+1) * hCount2) + x;
                triangles[index+2] = (y     * hCount2) + x + 1;

                трикутники[індекс+3] = ((y+1) * hCount2) + x;
                трикутники[індекс+4] = ((y+1) * hCount2) + x + 1;
                triangles[index+5] = (y     * hCount2) + x + 1;
                індекс += 6;
            }
        }

        m.vertices = вершини;
        m.uv = uvs;
        m.triangles = трикутники;
        m.RecalculateNormals();

        meshFilter.mesh = m;
        m.RecalculateBounds();        if (addCollider) {
            this.gameObject.AddComponent(typeof(BoxCollider));
        }

        //Selection.activeObject = площина;
    }
}

 

Схожі посилання