сегодня в 13:19
Введение
Перед новым годом, я решил попробовать себя в написании шейдеров. В качестве цели я избрал для себя шейдер растворяющегося объекта. 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
Нет времени
на счета?
MasterCard
Mobile
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers.
Комментариев нет:
Отправить комментарий