Немного о дематериализации в нашей игре

А мы все еще работаем в гараже над графической частью игры!

Работа над скетчами вроде завершена! Набралась целая стопка изображений и чертежей игровых обьектов, идей по тому как это все подключается и взаимодействует, теперь осталось главное - собрать :)

Перед вами результат работы моего geometry - шейдера :

Смещение кубиков волнами
Смещение кубиков волнами
Немного о дематериализации в нашей игре
Немного о дематериализации в нашей игре

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

А вот и обобщенное видео процесса:

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

Знаю, часто хочется получить готовый шейдер и использовать его в своем проекте.

Вот одна из версий шейдера (если кому пригодится). Здесь основа эффекта, пользуйтесь :)<Шейдер не должен работать на OGL и Metal>

Properties { _MainTex("SliceTex", 2 D) = "white" {} _GridTex("_GridTex", 2 D) = "white" {} _IntersectionColor("_IntersectionColor", Color) = (0, 1, 1, 1) _HighlightThresholdMax("Highlight Threshold Max", Float) = 1 _Burn("_Burn", Range(0, 2)) = 0.0 _SplashAlpha("_SplashAlpha", Range(0, 1)) = 1.0 // Geometry! _Factor("Factor", Range(0., 20.)) = 20 } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma geometry geom // sets the compilation target to 4.0. #pragma multi_compile_instancing //<====== #include "UnityCG.cginc" struct appdata { float4 vertex: POSITION; float3 normal: NORMAL; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID // Need this for basic functionality }; struct v2g { float4 vertex: POSITION; float3 normal: NORMAL; float2 uv: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID // Need this for basic functionality }; struct g2f { float4 pos: SV_POSITION; float2 uv: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID // Need this for basic functionality }; sampler2D _MainTex, _GridTex; // , _WaveTex; fixed _HighlightThresholdMax; fixed4 _IntersectionColor; UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float, _Burn) UNITY_DEFINE_INSTANCED_PROP(float, _SplashAlpha) UNITY_INSTANCING_BUFFER_END(Props) // Geom: float _Factor; static const int MIP = 5; //2^5 = 32; v2g vert(appdata v) { // appdata_base v2g o; // set all values in the v2g o to 0.0 UNITY_INITIALIZE_OUTPUT(v2g, o); // setup the instanced id to be accessed UNITY_SETUP_INSTANCE_ID(v); // copy instance id in the appdata v to the v2g o UNITY_TRANSFER_INSTANCE_ID(v, o); o.vertex = v.vertex; o.uv = v.texcoord; o.normal = v.normal; // o.burn = UNITY_ACCESS_INSTANCED_PROP(Props, _Burn); return o; } [maxvertexcount(20)] //20 3//18 // 24 void geom(triangle v2g IN[3], inout TriangleStream < g2f > tristream) { g2f o; //[20];// 24 //for CUBE // set all values in the g2f o to 0.0 UNITY_INITIALIZE_OUTPUT(g2f, o); // setup the instanced id to be accessed UNITY_SETUP_INSTANCE_ID(IN[0]); // copy instance id in the v2f IN[0] to the g2f o UNITY_TRANSFER_INSTANCE_ID(IN[0], o); //float3 edgeA = IN[1].vertex - IN[0].vertex; //float3 edgeB = IN[2].vertex - IN[0].vertex;// 2 - 0 float3 normalFace = IN[0].normal; // normalize(cross(edgeA, edgeB));// IN[0].normal;// IN[0].normal;// const float f = 0.131447; // 0.262894*0.5;blender;//0.1;// 25;//_Factor/2; //half size // Local vertices: const float4 vc[8] = { float4(-0, -0, -2. * f, 0.0 f), // + float4(normalFace*_Factor, 0), //0 float4( -f, -f, -f, 0.0f ) float4(-0, -0, +0, 0.0 f), // + float4(normalFace*_Factor, 0), //1 float4( -f, -f, +f, 0.0f ) float4(-0, +f, -2. * f, 0.0 f), // + float4(normalFace*_Factor, 0), //2 float4(-0, +f, +0, 0.0 f), // + float4(normalFace*_Factor, 0), //3 float4(+2. * f, -0, -2. * f, 0.0 f), // + float4(normalFace*_Factor, 0), //4 float4( +f, -f, -f, 0.0f ) float4(+2. * f, -0, +0, 0.0 f), // + float4(normalFace*_Factor, 0), //5 float4( +f, -f, +f, 0.0f ) float4(+2. * f, +f, -2. * f, 0.0 f), // + float4(normalFace*_Factor, 0), //6 float4(+2. * f, +f, +0, 0.0 f) // + float4(normalFace*_Factor, 0) //7 }; const int VERT_ORDER[24] = { 0, 1, 3, 2, // left 0, 2, 6, 4, // front 4, 6, 7, 5, // right 7, 3, 1, 5, // back 2, 3, 7, 6, // top 0, 4, 5, 1 // bottom }; fixed burn = 0.99 * UNITY_ACCESS_INSTANCED_PROP(Props, _Burn); //_Burn; // Assign new vertices positions (24 new tile vertices, forming CUBE) for (int i = 0; i < 17; i += 4) { // 20// ++i // 24 //XXXX 0 o.uv = IN[2].uv; // [i] fixed mask = tex2Dlod(_MainTex, float4(IN[2].uv, 0, MIP)).r; // o[i].uv fixed tmp = burn - (mask); fixed a = (tmp < 0 ? 0 : (tmp > 0.5 ? 0 : tmp * tmp)); // tmp=1 fixed tmp2 = (2 - burn) - (1 - mask); fixed a2 = (tmp2 < 0 ? 0 : (tmp2 > 0.5 ? 0 : tmp2 * tmp2)); // tmp=1 fixed up = (a + a2) * 0.5; fixed3 vert = vc[VERT_ORDER[i]]; vert.y *= up * _Factor * mask; // tex2Dlod(_MainTex,float4(o[i].uv, 0, MIP)).r; o.pos = UnityObjectToClipPos(fixed3(IN[1].vertex.x, 0, IN[2].vertex.z) + vert); // Position in view space// [0-2] tristream.Append(o); //=== //XXXX 1 o.uv = IN[1].uv; // [i+1] // vert = vc[VERT_ORDER[i+1]]; mask = tex2Dlod(_MainTex, float4(IN[1].uv, 0, MIP)).r; // tex2Dlod(_MainTex,float4(o[i].uv, 0, MIP)).r; tmp = burn - (mask); a = (tmp < 0 ? 0 : (tmp > 0.5 ? 0 : tmp * tmp)); // tmp=1 tmp2 = (2 - burn) - (1 - mask); a2 = (tmp2 < 0 ? 0 : (tmp2 > 0.5 ? 0 : tmp2 * tmp2)); // tmp=1 up = (a + a2) * 0.5; vert = vc[VERT_ORDER[i + 1]]; vert.y *= up * _Factor * mask; // tex2Dlod(_MainTex,float4(o[i+1].uv, 0, MIP)).r;; o.pos = UnityObjectToClipPos(fixed3(IN[1].vertex.x, 0, IN[2].vertex.z) + vert); // Position in view space// [0-2] tristream.Append(o); //=== //XXXX 3 o.uv = IN[0].uv; // [i+3] // vert = vc[VERT_ORDER[i+3]]; mask = tex2Dlod(_MainTex, float4(IN[0].uv, 0, MIP)).r; // tex2Dlod(_MainTex,float4(o[i+1].uv, 0, MIP)).r; tmp = burn - (mask); a = (tmp < 0 ? 0 : (tmp > 0.5 ? 0 : tmp * tmp)); // tmp=1 tmp2 = (2 - burn) - (1 - mask); a2 = (tmp2 < 0 ? 0 : (tmp2 > 0.5 ? 0 : tmp2 * tmp2)); // tmp=1 up = (a + a2) * 0.5; vert = vc[VERT_ORDER[i + 3]]; vert.y *= up * _Factor * mask; //tex2Dlod(_MainTex,float4(o[i+3].uv, 0, MIP)).r; o.pos = UnityObjectToClipPos(fixed3(IN[1].vertex.x, 0, IN[2].vertex.z) + vert); // Position in view space// [0-2] tristream.Append(o); //=== //XXXX 2 o.uv = IN[2].uv; // [i+2] // vert = vc[VERT_ORDER[i+2]]; mask = tex2Dlod(_MainTex, float4(IN[2].uv, 0, MIP)).r; // tex2Dlod(_MainTex,float4(o[i+1].uv, 0, MIP)).r; tmp = burn - (mask); a = (tmp < 0 ? 0 : (tmp > 0.5 ? 0 : tmp * tmp)); // tmp=1 tmp2 = (2 - burn) - (1 - mask); a2 = (tmp2 < 0 ? 0 : (tmp2 > 0.5 ? 0 : tmp2 * tmp2)); // tmp=1 up = (a + a2) * 0.5; vert = vc[VERT_ORDER[i + 2]]; vert.y *= up * _Factor * mask; // tex2Dlod(_MainTex,float4(o[i+2].uv, 0, MIP)).r; o.pos = UnityObjectToClipPos(fixed3(IN[1].vertex.x, 0, IN[2].vertex.z) + vert); // Position in view space// [0-2] tristream.Append(o); tristream.RestartStrip(); } } fixed4 frag(g2f i): SV_Target { // setup instance id to be accessed UNITY_SETUP_INSTANCE_ID(i); fixed2 mask = tex2D(_MainTex, i.uv).rg; // fixed up = mask.r; // 2 - max BURN! // INNER : fixed burn = 0.99 * UNITY_ACCESS_INSTANCED_PROP(Props, _Burn); / fixed tmp = burn - (mask.r); fixed a = (tmp < 0 ? 0 : (tmp > 0.5 ? 0 : tmp * tmp)); // OUT: fixed tmp2 = (2 - burn) - (1 - mask.r); fixed a2 = (tmp2 < 0 ? 0 : (tmp2 > 0.5 ? 0 : tmp2 * tmp2)); // tmp=1 fixed up = (a + a2) * 0.5; fixed grid = tex2D(_GridTex, i.uv * 32).r * 25; return (grid * up * mask.g + up * 10 * mask.g) * _IntersectionColor * UNITY_ACCESS_INSTANCED_PROP(Props, _SplashAlpha); // } ENDCG } }

Обновления по проекту обычно выкладываем здесь:

На этом все, всем хорошего вечера :)

55 показов
654654 открытия
2 комментария

Круто))

Ответить

код фур фри

Ответить