Question regarding Unity_Rotate_Radians_float

Hi,

I started a deep dive into learning shaders and I stumbled upon the Unity_Rotate_Radians_float function and I have a question regarding the code. You can fine the code here, and I’ll also paste it below.

void Unity_Rotate_Radians_float(float2 UV, float2 Center, float Rotation, out float2 Out)
{
    UV -= Center;
    float s = sin(Rotation);
    float c = cos(Rotation);
    float2x2 rMatrix = float2x2(c, -s, s, c);
    rMatrix *= 0.5;
    rMatrix += 0.5;
    rMatrix = rMatrix * 2 - 1;
    UV.xy = mul(UV.xy, rMatrix);
    UV += Center;
    Out = UV;
}

My question is regarding the rMatrix calculations. So from what I understand we declare a 2x2 matrix that has only sin and cos as its elements. As we know both sin and cos have values in the [-1, 1] interval.
After that we have the linerMatrix *= 0.5
This line will place the values in the [-0.5, 0.5] interval.
After that we have rMatrix += 0.5;
This will place the values in the [0, 1] interval but after that we have rMatrix = rMatrix * 2 - 1;
which places the values in the [-1, 1] interval and we’re back where we started.
I removed these 3 lines from the code and I get the same behaviour with or without them. Clearly there must be a reason for these 3 lines being there but I can’t figure out the reason.

Can someone please explain this?

Thanks!

most probably the person implementing this function arrived at the solution using trial and error.

Yeah, I agree. It looks like someone who wasn’t entirely familiar with how transform matrices work trying to produce a transform matrix that rotated around the “center”. But you can’t do that with a 2x2 matrix, you need to use a 3x3 matrix.

Like this:

float2 rotateUV(float2 UV, float2 Center, float Rotation)
{
    float s = sin(Rotation);
    float c = cos(Rotation);
    float3x3 rotMat = float3x3(
        c, s, Center.x - (Center.x * c + Center.y * s),
        -s, c, Center.y + (Center.x * s - Center.y * c),
        0, 0, 1
    );
    return mul(rotMat, float3(UV, 1.0)).xy;
}

And that’s more expensive than just doing it the “simple” way of subtracting and adding the offset before and after the matrix multiply, which is what that above function is doing with a bunch of extra code that’s hopefully just getting removed by the shader compiler.

But yes, that function should look more like this:

float2 rotateUV(float2 UV, float2 Center, float Rotation)
{
    UV -= Center;
    float s = sin(Rotation);
    float c = cos(Rotation);
    float2x2 rotMat = float2x2(c, -s, s, c);
    UV = mul(UV, rotMat);
    return UV + Center;
}

Thanks! The code was used to rotate a texture, so in a 2D context. And as you can see in my post the code is taken from the ShaderGraph page on Unity. It is a possible version of generated code when using a UV Rotate Node.

So we’re my examples. It requires a float3x3 and float3 to do a 2D transform with a translations, just like it requires a float4x4 and float4 to do a 3D transform with translations.

Yep.

Someone at Unity didn’t know exactly what they were doing when they wrote that, and forgot or didn’t know to delete the unnecessary extra code before submitting that node. And no one has bothered to remove it in the 4 years since then.

To be fair, my code looks like that a lot until I figure out what I’m doing too.

Also that “possible version” line in the documentation is just a catch-all in case the documentation gets out of sync with the code (either on their end or the user’s). For that node that’s the only possible version of the generated code. And still is even in the latest versions of Shader Graph.

Yeah, mistakes do happen. Just wanted to be sure that I’m not missing something.
Thanks!