Делаем «туман войны» как в стратегии

Туман войны – это закрашенное черным цветом поле карты. Используется для того чтобы скрыть действия игроков друг от друга, в том случае если «туман войны» динамический, то есть, видимым остается только определенный радиус, вокруг юнита. Но не только в стратегии может пригодиться такая штука, например, статический «туман» отлично подойдет к ролевой игре с видом сверху, когда нужно чтобы открытые области, более не скрывались. Впрочем, можно сочетать оба типа и добиться неплохого эффекта. В этом уроке попробуем разобраться, как вообще можно это сделать. Затронем основы, так сказать.


Так, делаем всё по порядку, а затем разберемся в логике работы.

Нарисуем маску, чистого зеленого цвета, на прозрачном фоне, в разрешении 250х250:


Примерно вот такого вида. И сохраняем в формате png.

Затем в редакторе импортируем как текстуру и ставим Wrap Mode > Clamp, всё остальное по умолчанию.

Создаем обычный Plane, делаем его дочерним к персонажу, потом создаем материал и выбираем шейдер Particles > Alpha Blended и кидаем в него нашу текстуру маски. Должно получится примерно вот так:

Делаем «туман войны» как в стратегии

Создадим еще один слой FogOfWar_Mask и назначим маске его:


Окей, с этим всё. Маска готова.

Создаем новый шейдер FogOfWar:

Shader "Custom/FogOfWar" {

	Properties 
	{
		_Color("Main Color", Color) = (1,1,1,1)
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_Blur("Blur", Range(0,0.003)) = 0.0015
	}
	
	SubShader 
	{
		Tags { "Queue"="Transparent" "RenderType"="Transparent" "LightMode"="ForwardBase" }
		Blend SrcAlpha OneMinusSrcAlpha
		Lighting Off
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert alpha
		#pragma target 3.0
		
		fixed4 LightingNoLighting(SurfaceOutput s, fixed3 lightDir, float aten)
		{
			fixed4 color;
			color.rgb = s.Albedo;
			color.a = s.Alpha;
			return color;
		}

		fixed4 _Color;
		sampler2D _MainTex;
		float _Blur;

		struct Input 
		{
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) 
		{
		        half4 baseColor1 = tex2D (_MainTex, IN.uv_MainTex + float2(-_Blur, 0));
			half4 baseColor2 = tex2D (_MainTex, IN.uv_MainTex + float2(0, -_Blur));
			half4 baseColor3 = tex2D (_MainTex, IN.uv_MainTex + float2(_Blur, 0));
			half4 baseColor4 = tex2D (_MainTex, IN.uv_MainTex + float2(0, _Blur));
			half4 baseColor = 0.25 * (baseColor1 + baseColor2 + baseColor3 + baseColor4);
			o.Albedo = _Color.rgb * baseColor.b;
			o.Alpha = _Color.a - baseColor.g;
		}
		
		ENDCG
	} 
	Fallback "Diffuse"
}

И сразу создаем материал с таким же именем и выберем в нем наш шейдер, который будет по адресу Custom > FogOfWar.

Далее, добавим на сцену Plane, это будет "туман". Растягиваем его так, чтобы он покрывал карту (сохраняя форму квадрата). По высоте настраиваем, чтобы он был выше зданий, игрока и т.п., но не слишком высоко, главное - скрыть объекты. Кидаем на Plane материал FogOfWar, который мы создали ранее. А в качестве текстуры к нашему материалу у нас будет Render Texture.

Создаем ее с параметрами, как на скриншоте:


Переименуем в FogOfWarRT и кидаем в материал "тумана":


Настраиваем цвет и прозрачность по вкусу.

Настроим главную камеру, Depth = 0, а Culling Mask выбираем всё кроме маски:


Добавим еще одну камеру и делаем всё - как показано ниже:


Суть в том, что она должна смотреть на карту сверху вниз, а параметр Size увеличиваем, чтоб в поле камеры уместился "туман" и карта соответственно. Не стоит переживать за дополнительную нагрузку, потому как камера будет обрабатывать только один слой с масками.

Вешаем на эту камеру скрипт FogOfWarMode:

using UnityEngine;
using System.Collections;

[RequireComponent (typeof(Camera))]

public class FogOfWarMode : MonoBehaviour {

	public bool isDynamic;
	private Camera _camera;

	void Start () 
	{
		_camera = GetComponent<Camera>();
		_camera.clearFlags = CameraClearFlags.Color;
	}

	void OnPostRender () 
	{
		if(!isDynamic)
		{
			_camera.clearFlags = CameraClearFlags.Depth;
		}
	}
}

Если поставить галочку isDynamic, то туман будет динамический.

Собственно, если всё сделано правильно, то должно работать.

Теперь о том как это работает. Дополнительная камера обновляет Render Texture, фон рисует синий, а на нем зеленую маску. Эту текстуру мы используем на Plane, где шейдер вырезает маску и мы получаем прозрачную область. Как-то так...

Скачать этот проект можно тут:

Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.


Внимание! У Вас нет прав для просмотра скрытого текста.

Комментариев 27

Офлайн
Light 10 марта 2018
aesee, ну это больше вопрос к экстрасенсу... Мне неведомо как и что в твоем проекте было сделано. Наш проект работает нормально? Если да, то просто возьми его как основу и всё.
Офлайн
aesee 10 марта 2018
Сделал все по статье, скачал пример и проверил, что все совпадает. Но почему-то в моем проекте не работает.
РендерТекстура не изменяется. Вернее, я на ней вижу только перемещение маски, но следа от нее нет, а соответственно и туман не рассеивается. В чем может быть проблема?
Офлайн
Light 3 мая 2017
ArturST, на юнити 5.6.0 делал сборку, запускал на андройде 4.1.2... вроде работает. Но в любом случаи, я шейдеры не пишу пока...
Офлайн
ArturST 2 мая 2017
в редакторе все четко работает , но после установки на планшет после загрузки уровня черный екран и только UI, почему-то шейдер не вырезает маску, в шейдере возможно под андроид нужно чет менять. В шейдерах не силен может есть какое решение или мысли по этому поводу , был бы благодарен за подсказку .
Офлайн
ArturST 2 мая 2017
не хочет работать на андроиде (черный екран) что может быть причиной?
Офлайн
Light 25 января 2017
cry_san, блюр выкрутить на ноль в шейдере.
Офлайн
cry_san 25 января 2017
А как у тумана сделать четкие границы?
Офлайн
Light 19 января 2017
cry_san, что тут маятся?) Меш поверх спрайтов, камеру "тумана" разворачиваем на меш, в остальном тоже самое, рендер текстура и маска без изменений.
Офлайн
cry_san 19 января 2017
Light,
Помаялся и плюнул. Вспомнил высшую математику и сделал расчеты самостоятельно ))
Офлайн
Light 16 января 2017
cry_san, конечно, всё тоже самое делать, а меш тумана выдвинуть на камеру, чтобы спрайты были на заднем плане.
Офлайн
cry_san 16 января 2017
А что насчет 2D? Такое возможно, если на карте только плоские спрайты?
Офлайн
Svvrvch 30 декабря 2016
Light, спасибо.
Офлайн
Light 30 декабря 2016
Svvrvch, во первых, нужно сделать так, чтобы маска не вращалась вместе с персом. Во вторых, позиция FogOfWarCamera по Х и Z, должна быть такой же как и у Plane. Далее, Orthographic Size камеры FogOfWarCamera высчитывается по формуле: Х * 0.5f * 10f где Х это Scale одной из сторон, квадрата Plane. Кстати эта формула годится только для стандартного объекта Plane в Юнити.

Главную камеру тоже можно перевести в режим Orthographic, раз она строго под прямым углом.
Офлайн
Svvrvch 30 декабря 2016
Вот сцена:
https://drive.google.com/file/d/0Bw8XK-ofukLnTm5Wd21ycXItX3M/view
Офлайн
Light 30 декабря 2016
Svvrvch, скинь сцену, посмотрим...
Офлайн
Svvrvch 30 декабря 2016
Сделал всё в точности по инструкции, но почему-то возникла такая проблема(на снимке):
http://savepic.ru/12521632.png
Свет находится в дали от игрока. Если нужно то скину демо сцену.
Офлайн
Light 3 октября 2016
And8, можно попробовать покрутить Blur в настройках шейдера.
Офлайн
And8 3 октября 2016
Подскажи, почему когда туман динамический, вокруг персонажа плавный контур, а когда нет - рваные края, как это исправить?
Офлайн
Light 12 марта 2016
GreatPasta, проверил на той же версии, проблем нет.
Офлайн
GreatPasta 11 марта 2016
Failed to import package with error: Couldn't decompress package =(

unity 5.3.3f1 Personal
Офлайн
Light 1 ноября 2015
Цитата: Виталий Дёмин
скажие а можно как нибдь сохранить раскрытые области в сейв?

Хм, ну возможно...
Надо сделать снимок RenderTexture, чтобы сохранить текущий рисунок, открытых областей. Затем, на старте сцены, поставить этот скриншот как текстуру, вместо RenderTexture. Камера по прежнему будет рендрить в RenderTexture и получится что изображение со скриншота будет передано туда. После, вернуть всё как было. Как-то так наверно...
Офлайн
скажие а можно как нибдь сохранить раскрытые области в сейв?
Офлайн
отличный туман войны огромное спасибо!!!
Офлайн
Light 24 октября 2015
Цитата: DayFall
Не работает.

Работает. Но если речь идет о постепенном затемнение, то его нет.

Цитата: DayFall
И хватит тереть мои каменты.

Я как нибудь сам решу, что мне делать.
Офлайн
DayFall 24 октября 2015
Цитата: Light
Цитата: DayFall
затемнение посещенных областей, которые затем покинул игрок

Опция public bool isDynamic;

Не работает. И хватит тереть мои каменты.
Офлайн
Light 21 октября 2015
Цитата: DayFall
затемнение посещенных областей, которые затем покинул игрок

Опция public bool isDynamic;
Офлайн
DayFall 20 октября 2015
В целом неплохо, но не хватает статичного тумана (затемнение посещенных областей, которые затем покинул игрок) и в шейдере есть лишний код:

fixed4 LightingNoLighting(SurfaceOutput s, fixed3 lightDir, float aten)
{
fixed4 color;
color.rgb = s.Albedo;
color.a = s.Alpha;
return color;
}

Функцию целиком можно убрать, не используется.
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика