Пишим Dissolve Shader

от автора

Введение

Перед новым годом, я решил попробовать себя в написании шейдеров. В качестве цели я избрал для себя шейдер растворяющегося объекта. 31 декабря я его успешно закончил, и теперь пришло время что-то с ним делать. На ассет сторе сказали что всё отлично но уже парочка похожих есть, по этому я постараюсь разобрать его в этой статье. В итоге у нас должно получиться вот это:



Путей реализации есть несколько:

  • Alpha
  • CutOff
  • Grab Texture

В итоге у нас получится 3 шейдера, 2 использующие только альфу и которые могут взлететь на моб. девайсах. И один с AlphaTest который выглядит посимпатичней но более прожорливый. Благодаря AlphaTest мы можем отключить отсечение невидимых полигонов и не получать наслоение. Но заплатить придётся шейдерной моделью 2.0 и использовать 3.0 из-за чего нельзя будет использовать на моб. девайсах.

Каркас

Общий алгоритм примерно такой:

  • Берём яркость пикселя с маски разрушения или прямо с главной текстуры
  • Сравниваем эту яркость с N
  • Если яркость больше N то альфу пикселя ставим в нолик

В итоге получится не так красиво как на первом видео.

Нам не хватает нормал мап, и самого крутого. Линий!
Алгоритм инлайнов у меня такой:

  • Берём яркость пикселя с маски разрушения, но с оффсетом по UV + LineSize. И ещё один но оффсет уже UV — LineSize
  • Если хотя бы один из пикселей меньше N, то мы устанавливаем цвет пикселя из текстуры для линий
  • Иначе ставим альфу в ноль (Это как замена аналогичной операции в первом алгоритме)

Резюмирую выше сказанное, мы получаем отсечение по маске и если пиксели отсекаем то проверяем нету ли впритык к нему не отсечённые, если они есть мы становимся краем и ставим себе определённый цвет.

Ближе к телу коду

Если прибавить ко всему выше сказанному наложение нормалек и смещение текстуры линии ещё по синусоидальному времени. То получится вот такое вот полотно.

Основной шейдер

 Shader "HolyMonkey/Dissolve/Bumped" {  	Properties { 	    _MainColor ("Main Color", Color) = (1,1,1,1) 		_MainTex ("Base (RGB)", 2D) = "white" {} 		_Mask("Mask To Dissolve", 2D) = "white" {} 		_LineTexture("Line Texture", 2D) = "white" {} 		_Range ("Range", Range(0,3)) = 0 		_LineSize ("LineSize", Float) = 0.001 		_Color ("Line Color", Color) = (1,1,1,1) 		_BumpMap ("Normalmap", 2D) = "bump" {} 		_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 	} 	 	SubShader { 		Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"} 		LOD 300 		ZWrite On 		Cull Off 		CGPROGRAM  		#pragma target 3.0 		#include "UnityCG.cginc" 		#pragma surface surf Lambert alphatest:_Cutoff           		sampler2D _MainTex; 		sampler2D _LineTexture; 		sampler2D _BumpMap; 		sampler2D _Mask; 		half4 _Color; 		half4 _MainColor; 		float _Range; 		float _LineSize; 		            		struct Input { 			float2 uv_MainTex; 			float2 uv_BumpMap;                         float2 uv_Detail; 		};              		void surf (Input IN, inout SurfaceOutput o) { 			half4 c = tex2D (_MainTex, IN.uv_MainTex); 			half4 m = tex2D (_Mask, IN.uv_MainTex); 		        half4 lc =  tex2D (_Mask, IN.uv_MainTex - _LineSize); 		        half4 lc2 = tex2D (_Mask, IN.uv_MainTex + _LineSize); 			half4 lc3 = tex2D(_LineTexture, IN.uv_MainTex + _SinTime) * _Color;     			  		        o.Albedo = c *  _MainColor; 		        o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap)); 		        o.Alpha = 1; 		     			float factor = m.rgb.x + m.rgb.y + m.rgb.z; 			if(factor >= _Range) 			{ 			   float factor2 = lc.rgb.x + lc.rgb.y + lc.rgb.z; 			   float factor3 = lc2.rgb.x + lc2.rgb.y + lc2.rgb.z; 			   if(factor2 < _Range || factor3 < _Range) 			   { 			      o.Albedo = lc3; 			   } 			   else 			   {                   o.Alpha = 0.0;                }             } 		} 		ENDCG 	}  	Fallback "Diffuse" } 

Ещё можно поиграться с не которыми аспектами и получить следующее

С включённым кулингом

Shader "HolyMonkey/Dissolve/Culling-Mobile" {  	Properties { 	    _MainColor ("Main Color", Color) = (1,1,1,1) 		_MainTex ("Base (RGB)", 2D) = "white" {} 		_Mask("Mask To Dissolve", 2D) = "white" {} 		_LineTexture("Line Texture", 2D) = "white" {} 		_Range ("Range", Range(0,3)) = 0 		_LineSize ("LineSize", Float) = 0.001 		_Color ("Line Color", Color) = (1,1,1,1) 		_BumpMap ("Normalmap", 2D) = "bump" {} 	} 	 	SubShader { 		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} 		LOD 300 		CGPROGRAM  		#pragma target 2.0 		#include "UnityCG.cginc" 		#pragma surface surf Lambert alpha            		sampler2D _MainTex; 		sampler2D _LineTexture; 		sampler2D _BumpMap; 		sampler2D _Mask; 		half4 _Color; 		half4 _MainColor; 		float _Range; 		float _LineSize; 		            		struct Input { 			float2 uv_MainTex; 			float2 uv_BumpMap;             float2 uv_Detail; 		};              		void surf (Input IN, inout SurfaceOutput o) { 			half4 c = tex2D (_MainTex, IN.uv_MainTex); 			half4 m = tex2D (_Mask, IN.uv_MainTex); 		    half4 lc =  tex2D (_Mask, IN.uv_MainTex - _LineSize); 		    half4 lc2 = tex2D (_Mask, IN.uv_MainTex + _LineSize); 			half4 lc3 = tex2D(_LineTexture, IN.uv_MainTex + _SinTime) * _Color;     			  		    o.Albedo = c *  _MainColor; 		    o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap)); 		    o.Alpha = 1; 		     			float factor = m.rgb.x + m.rgb.y + m.rgb.z; 			if(factor >= _Range) 			{ 			   float factor2 = lc.rgb.x + lc.rgb.y + lc.rgb.z; 			   float factor3 = lc2.rgb.x + lc2.rgb.y + lc2.rgb.z; 			   if(factor2 < _Range || factor3 < _Range) 			   { 			      o.Albedo = lc3; 			   } 			   else 			   {                   o.Alpha = 0.0;                }             } 		} 		ENDCG 	}  	Fallback "Diffuse" } 

С ещё одной текстурой вместо прозрачности

Shader "HolyMonkey/Dissolve/NotTransparent" {  	Properties { 	    _MainColor ("Main Color", Color) = (1,1,1,1) 		_MainTex ("Base (RGB)", 2D) = "white" {} 		_BackTexture ("Back Texture", 2D) = "white" {} 		_Mask("Mask To Dissolve", 2D) = "white" {} 		_LineTexture("Line Texture", 2D) = "white" {} 		_Range ("Range", Range(0,3)) = 0 		_LineSize ("LineSize", Float) = 0.001 		_Color ("Line Color", Color) = (1,1,1,1) 		_BumpMap ("Normalmap", 2D) = "bump" {} 	} 	 	SubShader { 		LOD 300 		ZWrite On 		Cull Off 		 		CGPROGRAM  		#pragma target 2.0 		#include "UnityCG.cginc" 		#pragma surface surf Lambert           		sampler2D _MainTex; 		sampler2D _LineTexture; 		sampler2D _BumpMap; 		sampler2D _Mask; 		sampler2D _BackTexture; 		half4 _Color; 		half4 _MainColor; 		float _Range; 		float _LineSize; 		            		struct Input { 			float2 uv_MainTex; 			float2 uv_BumpMap;             float2 uv_Detail; 		};              		void surf (Input IN, inout SurfaceOutput o) { 			half4 c = tex2D (_MainTex, IN.uv_MainTex); 			half4 m = tex2D (_Mask, IN.uv_MainTex); 		    half4 lc =  tex2D (_Mask, IN.uv_MainTex - _LineSize); 		    half4 lc2 = tex2D (_Mask, IN.uv_MainTex + _LineSize); 			half4 lc3 = tex2D(_LineTexture, IN.uv_MainTex + _SinTime) * _Color;     			half4 bc  = tex2D(_BackTexture, IN.uv_MainTex); 		    o.Albedo = c *  _MainColor; 		    o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap)); 		     			float factor = m.rgb.x + m.rgb.y + m.rgb.z; 			if(factor >= _Range) 			{ 			   float factor2 = lc.rgb.x + lc.rgb.y + lc.rgb.z; 			   float factor3 = lc2.rgb.x + lc2.rgb.y + lc2.rgb.z; 			   if(factor2 < _Range || factor3 < _Range) 			   { 			      o.Albedo = lc3; 			   } 			   else 			   { 			      o.Albedo = bc; 			      o.Normal = float3(1,1,1); 			   }             } 		} 		ENDCG 	}  	Fallback "Diffuse" } 

Заключение

Написать получилось мало, но думаю дедуктивный код это искупает. Там используются простые вещи, и на хабре есть статьи с их ним разбором. По этому решил не катать вату. Исходники со всеми нужными ресурсами Вы можете скачать из репозитория на GitHub

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


Комментарии

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

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