Туман войны в Unity. Часть 1 (видеоурок)

В этом видео уроке я расскажу о том как сделать туман войны в юнити. Для моего варианта тумана войны не нужен рендеринг в текстуру поэтому он может быть использован в бесплатной версии Unity. Также он неплохо работает на мобильных устройствах. Во второй части урока я расскажу как оптимизировать его для мобильных устройств.

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

:ad:

Демо в веб плеере.

fog of war play demo

Используйте клавиши WASD или стрелки для движения игрока

Скачать pack файл: fog_of_war_tutorial.unitypackage

Для работы в Unity 5 нужно во всех шейдерах добавить alpha:blend к строке #pragma surface surf Lambert vertex:vert

Видеоурок по туману войны.

Шейдер апертуры для тумана войны.

Тут я написал шейдер который я использовал в видеоуроке.
// FogOfWar shader
// Copyright (C) 2013 Sergey Taraban 
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

Shader “Custom/FogOfWar” { Properties {     _Color (“Main Color”, Color) = (1,1,1,1)     _MainTex (“Base (RGB) Trans (A)”, 2D) = “white” {}     _FogRadius (“FogRadius”, Float) = 1.0     _FogMaxRadius(“FogMaxRadius”, Float) = 0.5     _Player1_Pos ("_Player1_Pos", Vector) = (0,0,0,1)     _Player2_Pos ("_Player2_Pos", Vector) = (0,0,0,1)     _Player3_Pos ("_Player3_Pos", Vector) = (0,0,0,1) }

SubShader {     Tags {“Queue”=“Transparent” “IgnoreProjector”=“True” “RenderType”=“Transparent”}     LOD 200     Blend SrcAlpha OneMinusSrcAlpha     Cull Off

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

    sampler2D _MainTex;     fixed4     _Color;     float     _FogRadius;     float     _FogMaxRadius;     float4     _Player1_Pos;     float4     _Player2_Pos;     float4     _Player3_Pos;

    struct Input {         float2 uv_MainTex;         float2 location;     };

    float powerForPos(float4 pos, float2 nearVertex);

    void vert(inout appdata_full vertexData, out Input outData) {         float4 pos = mul(UNITY_MATRIX_MVP, vertexData.vertex);         float4 posWorld = mul(_Object2World, vertexData.vertex);         outData.uv_MainTex = vertexData.texcoord;         outData.location = posWorld.xz;     }

    void surf (Input IN, inout SurfaceOutput o) {         fixed4 baseColor = tex2D(_MainTex, IN.uv_MainTex) * _Color;

        float alpha = (1.0 - (baseColor.a + powerForPos(_Player1_Pos, IN.location) + powerForPos(_Player2_Pos, IN.location) + powerForPos(_Player3_Pos, IN.location)));

        o.Albedo = baseColor.rgb;         o.Alpha = alpha;     }

    //return 0 if (pos - nearVertex) > _FogRadius     float powerForPos(float4 pos, float2 nearVertex) {         float atten = clamp(_FogRadius - length(pos.xz - nearVertex.xy), 0.0, _FogRadius);

        return (1.0/_FogMaxRadius)*atten/_FogRadius;     }

    ENDCG }

Fallback “Transparent/VertexLit” }

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

using UnityEngine;
using System.Collections;

public class FogOfWarPlayer : MonoBehaviour {

public Transform FogOfWarPlane;
public int Number = 1;

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {
	Vector3 screenPos = Camera.mainCamera.WorldToScreenPoint(transform.position);
	Ray rayToPlayerPos = Camera.mainCamera.ScreenPointToRay(screenPos);
	int layermask = (int)(1<<8);
	RaycastHit hit;
	if(Physics.Raycast(rayToPlayerPos, out hit, 1000, layermask)) {
		FogOfWarPlane.GetComponent<Renderer>().material.SetVector("_Player" + Number.ToString() +"_Pos", hit.point);
	}
}

}

Почитать по теме

Ссылки