Get Actor x, y, z rotation angle in shader

I need to get rotations angles in a shader. There is a node called “getFoliageZRotation” which gets the z rotation angle. But I would like to get all rotation angles, is this possible?

P.S Using Blueprints for this is not an option for my use case.

Actor rotation is a node in shaders.
it may be labeled Object rotation.
either way its an integral part of doing crazy stuff, so yes, it exists.

Alternatively, though you don’t need to. You can always use Material Parameter Collections and update the content with an unrelated BP.

Whats that mean??
You have an actor bp in the level with nothing at all that is simply in charge of writing the value of ItemA inside the MPC.

For things like actor location this is useful when you are dealing with shaders managing effects like foot prints or trails or any sort of thing that has to pan an image in world space around a material - where the actor location has nothing to do at all with the location you need.

Edit: the link you could have Googled…
https://docs.unrealengine.com/en-US/…tes/index.html

ObjectOrientation

Thanks for your reply. There is a node called ObjectOrientation. Its basically an up direction vector i think. What i need though, is either a quaternion rotation, or the x, y, z rotation in angles.

Blueprints and material parameter collections aren’t suitable for me, as i would be using this shader on thousands of objects.

1 Like

Depending on how you’re placing them you might be able to use custom primitive data.

What?
you have the up vector. Just dot between that and the world position…

I found the solution on this Japanese blog post:

Add a custom node with these contents to retrieve a Float3 containing the object’s rotation in radians (recommend making this a material function):

float3x3 WtoL = LWCToFloat(GetPrimitiveData(Parameters.PrimitiveId).WorldToLocal);
float3 R = float3(
atan2(WtoL[2].y,WtoL[2].z) * -1.0,
asin(WtoL[2].x),
atan2(WtoL[1].x,WtoL[0].x)
);
return R < 0 ? 2 * pi - abs(R) : R;

You will need to add pi as an argument to the custom node.
To convert to degrees, multiply the result by 57.2958.

Note that if you want to use this in the “RotateAboutAxis” material node, Component Mask out the degrees value of, for example, B (yaw), divide by 360 (RotateAboutAxis uses a 0-1 scale for rotation), and input it into RotationAngle. Add the result of the RotationAngle node to the initial vector that you’re rotating in order to acquire the final rotated vector.

1 Like

mpxc this piece of code helped me a lot, thanks!
However, the Y value was wrong so I modified code to work properly (UE5.1.1)

float3x3 WtoL = LWCToFloat(GetPrimitiveData(Parameters.PrimitiveId).WorldToLocal);
float3 R = float3(
atan2(WtoL[2].y,WtoL[2].z) * -1.0,
atan2(WtoL[2].x,WtoL[2].z),
atan2(WtoL[1].x,WtoL[0].x)
);
return R < 0 ? 2 * pi - abs(R) : R;
1 Like

Oh wow, thanks!!

I compared the two versions and you’re right that the Y value was totally broken in the original code.

Your version is giving much closer results, but it seems like the Y value still isn’t actually perfectly matching the Y value for the object’s rotation, although X and Z is correct, particularly when multiple axes are in a rotated state. I checked this by connecting the material function to a DebugFloat3Values node and comparing the displayed values to the actual values in the Actor Details while rotating the 3 axes of a sphere with the material set to it.

1 Like

Hello. I know this is an older thread, but was wondering if you happened to find a fix for the y value still not coming out quite right. I’ve been trying to get the roll of an object specifically and have been scratching my head trying to get it right.


This is what I’ve tried so far but it’s having issues. It’s not returning the proper values.

Here is an updated function which accounts for gimbal lock. Can you let me know if this works correctly?

float3x3 WtoL = LWCToFloat(GetPrimitiveData(Parameters.PrimitiveId).WorldToLocal);
float sy = sqrt(WtoL[0][0] * WtoL[0][0] +  WtoL[1][0] * WtoL[1][0]);

bool singular = sy < 1e-6; // If true, gimbal lock is likely

float x, y, z;
if (!singular) {
    x = atan2(WtoL[2][1], WtoL[2][2]);
    y = atan2(-WtoL[2][0], sy);
    z = atan2(WtoL[1][0], WtoL[0][0]);
} else {
    x = atan2(-WtoL[1][2], WtoL[1][1]);
    y = atan2(-WtoL[2][0], sy);
    z = 0;
}

float3 R = float3(x, y, z);
return R < 0 ? 2 * pi - abs(R) : R;

Hi, thanks for the reply.
It’s definitely a lot closer but looks like there’s still something off.

A rotation of 0 = 0.0,
A rotation of 90 = 0.75
A rotation of 270 = 0.25
So I would expect a rotation of 180 to equal 0.5, but it’s actually outputting 0.0 as well.

Hmm the results are somewhat different from the values displayed in the editor viewport, but I thought they were at least mathematically equivalent? Anyway, this is pretty much my limit for this kind of stuff, sorry. Maybe someone else can figure out a more comprehensive solution.

No problem. You helped a lot, thanks!

Hi !
I know it’s already an older post, but since Google took me here, here’s my solution to fix the weird values.
It’s not perfect, but there is only a couple of specific angles where the Y value is wrong, and it is only a few angles off.

float3x3 WtoL = LWCToFloat(GetPrimitiveData(Parameters.PrimitiveId).WorldToLocal);
float sy = sqrt(WtoL[0][0] * WtoL[0][0] +  WtoL[1][0] * WtoL[1][0]);

bool singular = sy < 1e-6; // If true, gimbal lock is likely

float x, y, z;
if (!singular) {
    x = -atan2(WtoL[2][1], WtoL[2][2]);
    y = -atan2(-WtoL[2][0], sy);
    z = atan2(WtoL[1][0], WtoL[0][0]);
} else {
    x = -atan2(-WtoL[1][2], WtoL[1][1]);
    y = -atan2(-WtoL[2][0], sy);
    z = 0;
}

float3 R = float3(x, y, z);
return R < 0 ? (2 * pi - abs(R)) : R;

There is probably a better way to fix this, as I am only barely cognisant when it comes to angular mathematics…