- Home /
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.
Can't you just rotate the mesh the propeller texture is on?
I could, but for two reasons it's not an option: 1. It's actually not a single mesh, it is part of a more complex mesh with multiple materials (O$$anonymous$$, I could separate it) but 2. It is a cylinder with just ten sides, so rotating it will show the low poly-count even more. Anyway, this is more the basic question whether or not such texture-manipulation is basicly possible and how to do it. $$anonymous$$essing with the placement rather than using movietextures could improve performance, I think.
You wouldn't use a movie texture, that would be far too expensive (perhaps you meant moving texture). For best visual and performance you would rotate the texture within the plane. I would have two textures in the material, one with a blurred set of the propeller which fades in when speed increases using the matrix transformation below. That way it will look good if you pause the game for instance.
Answer by ninjafish · Jul 10, 2012 at 06:54 PM
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);
}
Answer by Forrest_Gimp · Jul 05, 2012 at 11:00 AM
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?
Oh sorry yes, you would need a shader for this as you presumed. Will get back to you on the offset part, I don't have a solution at hand but we'll figure something out!
Great! Thanx for the help so far! I tried to work on it further, and have tried to initially set the center parameter of $$anonymous$$atrix4x4.TRS to something other than 0,0,0 by hand. So far I had no success.
Answer by Forrest_Gimp · Jul 06, 2012 at 06:58 AM
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.
Answer by Forrest_Gimp · Jul 11, 2012 at 11:28 AM
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!