Rotation of Texture/UVs directly from a shader

I have been looking through the forums and google for ages to find a way of rotating a texture from within the shader. Is there some sort of built in texture handling for this or some operation that can be used on the UVs? Panning is quite simple as just adding to the UVs essentially but for rotation i cannot even begin to figure out a way to do it.

I have read through many posts with no answers so i figured i would try a post on it myself, any help at all would be welcome but know that i fully understand how to rotate it from script but that is definitely not what i want for specific reasons.

So to summarize: I want to rotate a texture/uvs in a CG shader and NOT through script (though i realize and acknowledge it is fully possible to do so and it has many merits.)

1 Like

You have to apply a rotation matrix to your texture coordinates in the Cg shader before doing the texture lookup.

This should do it…

Shader "Custom/RotateUVs" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_RotationSpeed ("Rotation Speed", Float) = 2.0
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert vertex:vert

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		float _RotationSpeed;
		void vert (inout appdata_full v) {
			float sinX = sin ( _RotationSpeed * _Time );
			float cosX = cos ( _RotationSpeed * _Time );
			float sinY = sin ( _RotationSpeed * _Time );
			float2x2 rotationMatrix = float2x2( cosX, -sinX, sinY, cosX);
			v.texcoord.xy = mul ( v.texcoord.xy, rotationMatrix );
		}

		void surf (Input IN, inout SurfaceOutput o) {	
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}
11 Likes

Farfarer thansk for your support.

I need to move my texture rotation and I try so use your shader mixed with my CG shader
But I have a problem.

I use this C# script to calculate my rotationMatrix

using UnityEngine;

using System.Collections;
public class RotateUVs : MonoBehaviour {
    public float rotateSpeed = 10f;
    public Vector2 pivot = new Vector2(0.5f, 0.5f);

    protected void Update() {
        // Construct a rotation matrix and set it for the shader
        Matrix4x4 t = Matrix4x4.TRS(-pivot, Quaternion.identity, Vector3.one);
        Quaternion rotation = Quaternion.Euler(0, 0, Time.time * rotateSpeed);
        Matrix4x4 r = Matrix4x4.TRS(Vector3.zero, rotation, Vector3.one);   
        Matrix4x4 tInv = Matrix4x4.TRS(pivot, Quaternion.identity, Vector3.one);
        renderer.material.SetMatrix("_Rotation", tInv*r*t);
    }

}

and my shader piece is

#include "UnityCG.cginc"		

sampler2D _MainTex;
..

CGINCLUDE		

struct v2f 
{
	half4 pos : SV_POSITION;
	half4 uv : TEXCOORD0;
};
..
 ---> uniform float2x2 _Rotation;  

ENDCG 

SubShader {
	Tags { "RenderType"="Opaque" }
	LOD 300 
	
	Pass {
		CGPROGRAM
...		
		v2f_full vert (appdata_full v) 
		{
			v2f_full o;	
			o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
			o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex) 
			 ---> v.texcoord.xy = mul ( v.texcoord.xy, _Rotation );
....

Ok ,after this nothing happen!!! No texture move. How is it possibile? Can you help me please? I’m going crazy because of this!!!

Thank you Albergine for your interest but I don’t need all these shades.

Then this CG code line is a part of a complicated CG Bumped VertexPerPixelSpecular shader.

If you can help me just with this part of code, I would be very grateful.
Thanks

Hi Farfarer,

After a loto of testing, I have put my rotationMatrix Matrix4x4 from script to my shader.

However I think your shader is more interesting. But it has a problem. The rotation pivot is located on the corner of my plane and not in the middle.

Is it possibile center the rotation matrix pivot in CG Shader?

Thanks

Can just use the shader to make object move around like a circle ?

Try this one

    Shader "Custom/RotateUVs" {
        Properties {
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _RotationSpeed ("Rotation Speed", Float) = 2.0
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 200
           
            CGPROGRAM
            #pragma surface surf Lambert vertex:vert
     
            sampler2D _MainTex;
     
            struct Input {
                float2 uv_MainTex;
            };
     
            float _RotationSpeed;
            void vert (inout appdata_full v) {
                v.texcoord.xy -=0.5;
                float s = sin ( _RotationSpeed * _Time );
                float c = cos ( _RotationSpeed * _Time );
                float2x2 rotationMatrix = float2x2( c, -s, s, c);
                rotationMatrix *=0.5;
                rotationMatrix +=0.5;
                rotationMatrix = rotationMatrix * 2-1;
                v.texcoord.xy = mul ( v.texcoord.xy, rotationMatrix );
                v.texcoord.xy += 0.5; 
            }
     
            void surf (Input IN, inout SurfaceOutput o) {   
                half4 c = tex2D (_MainTex, IN.uv_MainTex);
                o.Albedo = c.rgb;
                o.Alpha = c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
1 Like

Rea thank you soo much!!! I want know where you can find this solution because I try to implement this by wikipedia Rotation matrix - Wikipedia and after a lot of time I coldnot found any solution!!!

Thanks

This Shader works great, however I would like for this same exact thing except for the texture to go around the xaxis rather then the Y axis, how would I go about doing that?

You want this? Are you sure?

Shader “Custom/RotateUVs” {

Properties {

_MainTex (“Base (RGB)”, 2D) = “white” {}

_RotationSpeed (“Rotation Speed”, Float) = 2.0

}

SubShader {

Tags { “RenderType”=“Opaque” }

LOD 200

CGPROGRAM

#pragma surface surf Lambert vertex:vert

sampler2D _MainTex;

struct Input {

float2 uv_MainTex;

};

float _RotationSpeed;

void vert (inout appdata_full v) {

v.texcoord.xy -=0.5;

float s = -sin ( _RotationSpeed * _Time );

float c = cos ( _RotationSpeed * _Time );

float2x2 rotationMatrix = float2x2( c, -s, s, c);

rotationMatrix *=0.5;

rotationMatrix +=0.5;

rotationMatrix = rotationMatrix * 2-1;

v.texcoord.xy = mul ( v.texcoord.xy, rotationMatrix );

v.texcoord.xy += 0.5;

}

void surf (Input IN, inout SurfaceOutput o) {

half4 c = tex2D (_MainTex, IN.uv_MainTex);

o.Albedo = c.rgb;

o.Alpha = c.a;

}

ENDCG

}

FallBack “Diffuse”

}

This thread has the closest solution to what I’m looking for and I thank everyone for their contributions!

I’m stuck trying to incorporate MULTIPLE textures in this shader that all rotate at speeds independent from each other.

I’m realizing my problem lies with in the vert function, I would need to somehow modify two sets of uv’s one for each texture since it’s not the texture that’s rotating but the uv’s correct? I’ve tried creating a new uvset in struct Input but I wasn’t able to get that to work.

Any ideas? I would be for ever grateful!

Thats correct, simply repeat the cos and sin calculation, and apply it to a different uv

Hi everyone,

This thread was very useful for me. I used a shader to rotate a texture to show it on my GUI with Graphics.DrawTexture.
However I don’t want the texture to rotate forever, but just a certain amount of degrees on demand. I know I can access the shader properties to modify, for example, a variable let’s say “RotateDegrees”. But, which code should I write on the Shader? Anyone?
Thanks a lot

                float s = -sin ( _RotationSpeed * _Time );

                float c = cos ( _RotationSpeed * _Time );

Thank you rea,
sorry but I am comlpetely new with shaders. What do you mean by “B”? The degrees I want to rotate? and “/B”?

Those are forum tags for bold. So those are just to make the “-sin” bold.

To not make it time dependent in the shader, just replace _RotationSpeed * _Time with _RotateDegrees for example and make _RotateDegrees your input property.

Thanks a lot jvo3dc!! I got it!!

Woops sorrry bout that, didn’t realize about the bold tag :stuck_out_tongue: