matrix rotation for uvs

I’m learning about matrices currently using this cool video series. However, I have not gotten far enough along yet to know if what I am asking about is the right way of going about things.

What I want is a texture to rotate. I found this other thread, but I think it would be way faster to set up a rotation matrix, and multiply the UVs by it. What I don’t know is whether or not it it possible to do this efficiently and still make it framerate-independent. That is, I can pre-create a rotation matrix that rotates by a given amount, but in order to keep the rotating consistent, I think I will need to compute sines and cosines each frame. Is this incorrect?

Another problem is that the non-iPhone doucmentation doesn’t even mention the matrix command, whereas the iPhone docs do.

Any advice is appreciated, and the more code you can offer, the better, considering I was only introduced to rotation matrices yesterday, so I am not knowledgeable enough to formulate them myself yet.

Edit:
Wow, how completely relevant this page is. Should I report a bug about the 2.5 documentation not including the command, then? Also, is this the fastest method of computation?

210484--7732--$screen_shot_2009_10_18_at_54846_pm_536.png

I don’t really see a big problem in constructing a matrix from code each frame, even if that involves a sine and cosine. Would that actually be a bottleneck?

The website docs will be update with Unity 2.6 release soon.

Shameless plug: transformation matrices explained.

I’m way too inexperienced to know! :o Your lack of belief in that encourages me, however!

Thanks! That is a good companion to the third lecture of that video series to which I linked.

Jessy, nice find on that course material!!

IByte

I’d also recommend The Matrix and Quaternion FAQ Matrix and Quaternion FAQ

OW, MY EYES! :shock:

Heheheheheheh, thanks, though. I also like this one:

http://www.itk.org/CourseWare/Training/QuaternionsI.pdf

I have yet to absorb all of this information. Can someone tell me if it is possible to have a matrix that rotates the UVs around their center, and if so, how to construct that matrix?

Don’t know is it helpful to you. I use this code to do all kind of rotation in Cg sharder.

float4 v = somewhere;
//v = mul(_Object2World, v); // enable this ...		
  v = mul(rotate(ws_rot, ws_pos), v);
//v = mul(_World2Object, v); // ... and this for rotate in world space, if needed
float4x4 rotate(float3 r, float4 d)
{
	float cx, cy, cz, sx, sy, sz;
	sincos(r.x, sx, cx);
	sincos(r.y, sy, cy);
	sincos(r.z, sz, cz);					
	return float4x4( cy*cz,   -sz,    sy, d.x,
                       sz, cx*cz,   -sx, d.y,
                      -sy,    sx, cx*cy, d.z,
                        0,     0,     0, d.w );					
}

Since GPU always using float4 internally, I guess, it will not cost more even only process float2 object. ie UV :slight_smile:

Antonio Hui

Yes, it’s possible. Start at Q26 on the page that Per linked you.

That hint is not helping me. There’s a ton of information in that PDF, and I hardly understand any of it yet.

Antonio, I’m not sure how to incorporate that into a fixed function pipeline.

Did you read from Q26? It’s entitled “What is a rotation matrix?” and it explains them in two dimensions, then in three, and shows you where to plug your values in for rotations about the three base axes. Because you want your coordinates in the XY plane, you should be generating a matrix that rotates around the Z axis. If the terms aren’t clear, start from Q1. It’s a very good document, and while it is long because it covers a lot of different things, you should be able to get everything you need out of it by reading the appropriate sections.

If you don’t want to understand rotation matrices, just use the ready-made example on the page you already linked: Material.SetMatrix(), which uses the matrix command for fixed function that you already found. You can put a non-zero vector as the first argument to Matrix.TRS() if you want an offset. If you want to rotate about another point, you’ll have to generate three matrices: one to translate to the rotation point, another to rotate, and a third to translate back from the rotation point. Matrix.TRS() is a really easy-to-use function for creating transformation matrices.

Daniel, I’m sorry! I misread this statement:

I didn’t realize that “Per” was a person who posted in this thread, and thought you were just using an odd phrasing “per linked you”, to say, “that you linked”. I was trying to glean information from the PDF to which I linked, starting on page 26! I didn’t find anything useful there! :sweat_smile:

Of course I do! :smile: I got my first taste of matrix rotation from that iTunes U video, and I think I at least understand rotating in 2D, about the origin, fairly well, now.

The fixed function matrix command only allows for multiplication by a single matrix, as far as I can tell. I took what you answered before to mean that there is a way to use a single matrix to rotate a point about an arbitrary origin, not just the actual origin. Please let me know if you know if that is true or false.

As for now, I’ve come up with a hack. I set up a matrix in the Inspector, as shown below. I set up UVs in my modeling program, and after I’m happy with them, translate them by (-.5, -.5). Then I use this code, and get the result I want. The translation is built into the rotation matrix, so I only need to use one in total.

I’d love some advice about how to improve things, without having to modify UVs on the CPU. I really only use Unity iPhone, so CG/GLSL is not an option.

void Update ()
{	
	timeXMagicRate = Time.time * magicRate;
	sine = Mathf.Sin(timeXMagicRate);
	cosine = Mathf.Cos(timeXMagicRate);
	
	pulsateMatrix[0] = pulsateMatrix[5] = cosine;
	pulsateMatrix[4] = -sine;
	pulsateMatrix[1] = sine;
	material.SetMatrix("_PulsateMatrix", pulsateMatrix);
}

212052--7799--$screen_shot_2009_10_22_at_31022_pm_220.png

You can definitely represent a rotation about an arbitrary point with just one matrix, but the way I would do it is to create those three matrices and multiply them together. There is probably a way to generate the final matrix all at once, without using the intermediate matrices. I just don’t know how to do that. However, you’re not generating the matrix per-vertex or per-fragment, so the amount of work you do to generate it every frame doesn’t really matter. Multiplying three matrices together sixty times a second or whatever is pretty cheap.

I tried doing that a couple days ago and had no success. I’ll keep doing what I’m doing unless someone can teach me how to construct it.

This code shows how to make a translation matrix, a rotation matrix, and the inverse translation. We multiply them right-to-left to perform the steps in order. Note that the translation is negative because we are moving everything such that this point is now at the origin, about which the rotation will occur. The inverse translation is just the original vector, as we move everything back.

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);
	}
}

Very cool. Thank you. However, I would like to understand it better. I observed that the values for the translation of x and y in the final matrix are clamped by .5 plus or minus the square root of .5, which makes some intuitive sense to me, considering that’s the farthest that any corner in 0 to 1 space can get. However, I do not yet understand the relationship that they have to the sin and cosine waves. It seems like it might take twice as long for their “waves” to propagate as do the “rotation waves”?

Also, what does “protected” do for Update()? I’ve never used protected before, and from reading the MSDN page, it wasn’t apparent to me how it would be useful.

Also, the reason that my previous efforts failed is that even though I constructed the matrices the same way you did, I multiplied them in the reverse order, because I still don’t have a wonderful grasp of them.

Okay, so I just multiplied out the matrices using a pencil and paper.

matrix[12] = -.5 * (cosine - sine) + .5;
and
matrix[13] = -.5 * (cosine + sine) - .5;

Either one of those equals -cosine minus the other. Handy.

So, if I don’t want to offset my UVs to start off with, I can do a couple calculations, but by just offsetting the UVs to begin with, I can keep the code cleaner and have it execute a little faster. So I’ll stick with that for now, and use this kind of thing if I want to have the center of rotation be dynamic. Thanks for the enlightenment!

(I actually tried modulating the center of rotation by a sine wave, and that almost made me throw up from motion sickness! :shock:)

I really don’t try and understand concatenated matrices except as products of rigid transforms. They can get arbitrarily complicated, and breaking them down will usually make a lot more sense.

That’s just a standard thing in my Update macro. It hardly ever matters, but in cases where you’re inheriting from that script it makes sure you don’t accidentally override the parent’s function. The compiler requires that you make the override explicit, so you’ll get an error if you do it unintentionally. The take-away is that functions should be protected unless they have to be something else.

This wasn’t the case, by the way. The waves I listed in my last post were just out of phase with sine cosine, so it was hard to figure out what was going on, just by watching floats update in the Editor.

If you’re using a Mac, then a very useful programming tool is Grapher (in Applications/Utilities). You can type in one or more functions and see the graph plotted. This is very handy for sanity-checking formulae you are unsure about, seeing the relationship between trig functions, etc. Highly recommended!