Animating UV transforms in Shader

I am looking for a way to make a little propeller rotate. The propeller is a texture placed on a mesh using an ordinary UV-map.
I know, I could just create a movie-texture which is animated itself, but I was wondering if it is possible to do it without going through the process of making a movie first. I have recently made my own moving water-texture using a JS-script that animates the offset-placement. So I see no reason why a rotation should not be possible just as well.

Possible starting-point:
I have read that it is possible to do matrix-calculations within a shader, so I basicly need to know if I can implement a rotation-transform (either in the shader or as an external script) and then send that translation (e.g. as matrix) to the texture.

The script in istself seems logical, but I think _Matrix is not actually influencing anything. I got it to work creating a custom shader:

Shader "Custom/rotationShader" {
 Properties 
 {
 _MainTex ("Base (RGB)", 2D) = "white" {}
 }
 SubShader {
 Tags { "RenderType"="Opaque" }
 
 Pass {
         Material { Diffuse (1,1,1,0) Ambient (1,1,1,0) }
 Lighting On
 
 SetTexture [_MainTex] 
 {
 matrix [_Rotation]
 combine texture * primary double, texture
 }
 }
 } 
 FallBack "Diffuse"
}

Then I changed renderer.material.SetMatrix ("_Matrix", matrix); to renderer.material.SetMatrix ("_Rotation", matrix); and it started turning!

There is one problem though: the pivot of the turning-motion is 0/0 (should have expected that…). To make it turn around the texture’s center I would have to change the first parameter of Matrix4x4.TRS to the maps center. Has anybody got an idea how to automati this, so it will automaticly update this position depending on the texturemaps size?

What I thought was the center parameter is just the translation vector. Should have read the documentation more carefully ^^. But inspired by my ‘discovery’ I tried this:

var speed : float = 1.0;
var rot : float;

function Update () 
{
    rot += speed*Time.deltaTime;
    if (rot>360) rot=0;

 displaceMatrix(); // move texture, so that 0/0 matches the center of the image
    RotateMatrix(); // turn texture
    replaceMatrix(); // reset to normal placement
}

function displaceMatrix () {
    var move = Vector3(-0.5,-0.5,0);
 
    var matrix : Matrix4x4 = Matrix4x4.TRS(move, Quaternion.Euler (0, 0, 0), Vector3.one);

    renderer.material.SetMatrix ("_Rotation", matrix);
    print("move 1 complete!");
}

function RotateMatrix () {

    var rotate = Quaternion.Euler (0, 0, rot);
 
    var matrix : Matrix4x4 = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler (0, 0, rot), Vector3.one);

    renderer.material.SetMatrix ("_Rotation", matrix);
    print("turn complete!");
}

function replaceMatrix () {
    var move = Vector3(0,0,0); 
    var matrix : Matrix4x4 = Matrix4x4.TRS(move, Quaternion.Euler (0, 0, 0), Vector3.one);

   renderer.material.SetMatrix ("_Rotation", matrix);
    print("move 2 complete!");
}

As you can see, my logic was “move texture so its center is at 0/0, then turn it, then move it back to original location”. It should work, but it doesn’t. In the property inspector I see the angle growing, but the turning seems to be undone by replaceMatrix(). Probably to do it I would have to use an additional matrix which only handles the placement. Unfortunately I have no idea how to implement this into the shader.

Not sure if this is what you are looking for. But here is a script that will take a texture and rotate it about a specified position on the texture. Just drag the script on the gameobject. Then attach a texture to the script, adjust the speed and set the position. If you want the texture to rotate from its center set x = 0.5 and y = 0.5.

//here is the script below

var rotateSpeed = 30;
var texture : Texture;
var rotationCenter = Vector2.zero;

function Start() {
    // Create a new material with a shader
    // that rotates the texture. Texture rotation
    // is performed with a _Rotation matrix.
    var m : Material = new Material (
        "Shader \"Rotating Texture\" {" +
        "Properties { _MainTex (\"Base\", 2D) = \"white\" {} }" +
        "SubShader {" +
        "    Pass {" +
        "        Material { Diffuse (1,1,1,0) Ambient (1,1,1,0) }" +
        "        Lighting On" +
        "        SetTexture [_MainTex] {" +
        "            matrix [_Rotation]" +
        "            combine texture * primary double, texture" +
        "        }" +
        "    }" +
        "}" +
        "}"
    );
    m.mainTexture = texture;
    renderer.material = m;
}

function Update() {
    // Construct a rotation matrix and set it for the shader
    var rot = Quaternion.Euler (0, 0, Time.time * rotateSpeed);
    var m = Matrix4x4.TRS ( Vector3.zero, rot, Vector3(1,1,1) );
    var t = Matrix4x4.TRS (-rotationCenter, Quaternion.identity, Vector3(1,1,1));
    var t_inverse = Matrix4x4.TRS (rotationCenter, Quaternion.identity, Vector3(1,1,1));
    renderer.material.SetMatrix ("_Rotation", t_inverse*m*t);
}

That is indeed exactly what I was looking for. Shame on me for not remembering matrices can simply be multiplied to combine the transitions. At least I was on the right track basicly.

Thanks for the help!