D
D
Danil Chekalin2018-03-12 22:05:21
C++ / C#
Danil Chekalin, 2018-03-12 22:05:21

How to register texture rotation in Unity shader?

There is a shader supplied by Tiled2Unity:

// Upgrade NOTE: upgraded instancing buffer 'MyProperties' to new syntax.

Shader "Tiled2Unity/Default (Instanced)"
{
    Properties
    {
        _MainTex ("Tiled Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    }

    SubShader
    {
        Tags
        { 
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile DUMMY PIXELSNAP_ON
            #include "UnityCG.cginc"
            #include "Tiled2Unity.cginc"

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                half2 texcoord  : TEXCOORD0;
            };


            UNITY_INSTANCING_BUFFER_START(MyProperties)
                UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
#define _Color_arr MyProperties
            UNITY_INSTANCING_BUFFER_END(MyProperties)

            v2f vert(appdata_t In)
            {
                UNITY_SETUP_INSTANCE_ID(In);

                v2f Out;
                Out.vertex = UnityObjectToClipPos(In.vertex);
                Out.texcoord = In.texcoord;
                Out.color = In.color * UNITY_ACCESS_INSTANCED_PROP(_Color_arr, _Color);

                #ifdef PIXELSNAP_ON
                Out.vertex = UnityPixelSnap (Out.vertex);
                #endif

                return Out;
            }

            sampler2D _MainTex;

            fixed4 frag(v2f In) : COLOR
            {
                half4 texcol = tex2D(_MainTex, In.texcoord);
                texcol = texcol * In.color;
                return texcol;
            }
        ENDCG
        }
    }

    Fallback "Sprites/Default"
}

Here is the render:
5aa6cf133a836110555941.png
How to implement a random rotate of (0, 90, 180, 270 degrees) for a material? I want the grass sprite to not be monotonous.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Daniil Basmanov, 2018-03-13
@dakiesse

There are several solutions for your problem. The simplest thing is to add three rotated pictures of grass to the atlas and use them in a brush that paints with random tiles. So in the future you will be able to redraw graphics without rebuilding the map and you will not have to support special shaders or manually rotate something on the stage.
The second easiest solution is to take advantage of Tiled's capabilities and rotate tiles there, Tiled can do this, Tiled2Unity, too, most likely.
If you really really want a shader, then you can, for example, use two flags to rotate uv in all four directions.

Custom/RotationExample
Shader "Custom/RotationExample"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}

        // Волшебные свойства для инспектора
        [Toggle] _RotateCW90("Rotate Clockwise 90", Float) = 0.0
        [Toggle] _Rotate180("Rotate 180", Float) = 0.0
        ////////////////////////////////////
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "PreviewType" = "Plane" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            // Флаги для компиляции нескольких вариантов шейдера
            #pragma multi_compile __ _ROTATECW90_ON
            #pragma multi_compile __ _ROTATE180_ON
            ////////////////////////////////////////////////////
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {

                // Собственно код вращения uv
#if _ROTATECW90_ON
                i.uv = float2(1 - i.uv.y, i.uv.x);
#endif
#if _ROTATE180_ON
                i.uv = float2(1 - i.uv.x, 1 - i.uv.y);
#endif
                /////////////////////////////

                fixed4 color = tex2D(_MainTex, i.uv);
                return color;
            }
            ENDCG
        }
    }
}

I have commented three important pieces that can be put into any shader to rotate the texture. The code above works only for quads with the simplest square uv-map stretched over the entire range from zero to one, for atlases you need to come up with a different solution. Well, do not forget that these flags will need to be set somehow.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question