Взрывная волна в Unity3D (displacement shader)

от автора

Всем привет, пишу небольшую 2D игру и параллельно хотел бы рассказывать о реализации некоторых вещей в Unity3D.
Программирование графики само по себе очень интересное занятие с безграничным количеством вариаций результата. В этой статье опишу реализацию искажения пространства от взрывной волны.


Обычно любые искажения в плоскостях x,y делают с помощью карты нормалей, которая в компоненте цветов хранит величину искажений. Посредством этого реализовывают поверхность воды, взрывные волны, горячий воздух и т.д.

В игре, которую пишу очень много выстрелов, в связи с этим количество искажений тоже большое:

Один из вариантов: математическая модель искажения. Мы прямо в шейдере считаем по формулам искажение в конкретной точке. Минусом такого подхода есть излишняя нагрузка. Ведь все эти просчеты будут выполняться для каждого пикселей, поэтому в программировании графики часто используют текстуры, внутри которых заранее просчитаны математические значения чего-либо. В случае со взрывной волной я взял такую текстуру:

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

Shader "Hidden/DisplacementEffect" { 	Properties { 		_MainTex ("Base (RGB)", 2D) = "white" {} 		_DisplacementTex ("Displacement rt", 2D) = "white" {} 		_DisplacementPower ("Displacement power", Float) = 0.025 	}  	SubShader { 		Pass { 			CGPROGRAM             #pragma vertex vert             #pragma fragment frag  			#include "UnityCG.cginc"  			uniform sampler2D _MainTex; 			uniform sampler2D _DisplacementTex; 			uniform float _DisplacementPower;  			struct vin_vct 			{ 				float4 vertex : POSITION; 				float4 color : COLOR; 				float2 texcoord : TEXCOORD0; 			};   			struct v2f_vct 			{ 				float4 vertex : POSITION; 				fixed4 color : COLOR; 				float2 texcoord : TEXCOORD0;   				float4 uvgrab : TEXCOORD1; 			};  			v2f_vct vert (vin_vct v) 			{ 				v2f_vct o; 				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); 				o.color = v.color;   				o.texcoord = v.texcoord;   				o.uvgrab = ComputeScreenPos(o.vertex); 				return o; 			}  			half4 frag (v2f_vct i) : COLOR 			{ 				float4 displacementVector = tex2D(_DisplacementTex, i.uvgrab); 				float2 uv_distorted = i.uvgrab + _DisplacementPower * displacementVector.xy;  				return tex2D(_MainTex, uv_distorted); 			} 			ENDCG 		} 	} }  

На вход два параметра: _DisplacementTex и _DisplacementPower. Первая и есть наша текстура искажения, а второе — сила искажения.

Получаем силу искажения в текущем пикселе:

float4 displacementVector = tex2D(_DisplacementTex, i.uvgrab); 

Смещаем uv-координаты текущего пикселя с указанной силой и направлением, полученным выше.

float2 uv_distorted = i.uvgrab + _DisplacementPower * displacementVector.xy; return tex2D(_MainTex, uv_distorted); 

Иными словами, каждый пиксель в displacement текстуре хранит в цвете вектор, на который мы должны сдвинуть пиксель картинки.

Следующая проблема: как расширить код на бесконечное количество взрывов. На помощь приходит рендер в текстуру. Создаем новую камеру, которая видит только определенный слой (layer), который я назвал displacements.

В момент взрыва вы создаете на сцене в точке взрыва спрайт displacement текстуры, который помещается в слой displacements. Этот слой видит только его отдельная камера, которая рендерит в другую текстуру.

На скрине выше Camera Preview показывает то, что «видит» камера слоя displacements, а внизу уже игровой результат, куда слой displacements не попадает, но уже видно результат обработки шейдером.

В шейдер, который мы уже написали выше в параметр _DisplacementTex попадет примерно такая текстура (при множественных выстрелах):

По сути, черный цвет текстуры это ноль, в этом месте цвета результирующей текстуры не сдвигаются. Там же, где прорисована текстура искажения цвета другие. Как результат, любое количество взрывов и искажений рисуются ровно за два прохода:

  • Первый проход это рендер отдельной камеры слоя displacements всех искажений в одну текстуру. Материал текстуры для всех взрывов один, поэтому и проход один
  • Второй проход, это эффект поверх сцены, который на вход получает рендер-текстуру искажений и за один раз сдвигает все пиксели во всех точках взрывов

Если вам интересна эта тема, продолжу описывать эффекты, которые вы видите на фото:

— Old TV, RGB Shift и другие постпроцесс эффекты
— Гравитационные искажения (физическая часть и визуальная)
— Уникальный паттерн фона с использованием Wang Tiles
— 2D тени от физических объектов

ссылка на оригинал статьи https://habrahabr.ru/post/282604/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *