# Convert between 3 variable rotation and 2 variable rotation

I think this may be more of a math question than a blender question, but I'm trying to do it with python in blender, so I'll start here.

I work with a small theatre and am trying to use blender to do some visualization work. The moving head lights that they have have only two variables that determine their rotation. Pan and Tilt. (or X and Z I guess)

How can I convert the XYZ Euler rotation into only the XZ rotation? I am an engineering student and am not necessarily afraid of matrix math if it's involved, but I'm certainly no expert.

Edit: [The goal is to be able to quicky and easily point the light in a direction using the "look at" gizmo, and then retrieving the associated X and Z coords from where it ends up pointing.]

I just don't even know where to begin.

Here are two lights pointing the same direction but one where the Y variable is 0:

Edit: [This shows me that I can use X and Z only to get the same angle, even if the light is technically rotated a different way along the axis the arrow points in. Is there a way to do this kind of conversion?]

Thank you

There does not seem to be anything to convert. The lights are real so they are in 3d space and they can be rotated in 3 dimensions, but they are fixed and have mechanism made in a way so they only rotate in 2. If you only need 2 rotation axis, use only 2. You can lock the other one for convenience so you don't accidentally change it by clicking the lock icon near the property you want to lock:

• What you said makes perfect sense, but I think I may have asked my question wrong. I would prefer to manipulate the lights by using the "look at" gizmo (i think that's what it's called; the yellow ball control thing), except I can't lock the y axis out of that. So after I set the angle with the control, can I then figure out the equivalent values for rotation using only the x and z axis. The biggest reason for all of this is speed. It's so much faster to just point the light at something than it is to slide the sliders up and down until I get the desired angle. Thanks Commented Sep 27, 2022 at 5:25
• You can use Track To Constraint for that. Commented Sep 27, 2022 at 5:34
• Hi, @MartynasŽiemys ! ,, yesbut.. how do you extract the Wold Space rotations? Commented Sep 27, 2022 at 7:48
• Hi. Well... yes but.. does he need to?.. Commented Sep 27, 2022 at 8:33
• @MartynasŽiemys I think I do... I was able to set up a Track To Constraint with an empty, but part of the goal was to be able to get the rotation values for the X and Z so that I could feed them back into the real world light controller. Commented Sep 27, 2022 at 13:16

I finally figured it out. Basically, use the rotation matrix and a unit vector to find a different rotation matrix where angle β = 0

Start with this matrix R(α, β, γ), found on Wikipedia: Sorry, I don't really know how to use any math formatters.

plug in β = 0 to get a much more simplified matrix (since I want the rotation only in terms of X and Z, the Y value, or β, will be 0)

I then use the unit vector V(0,0,1) to find a system of three equations that can be used to solve for α and γ

Because the X and Y values in the unit vector are zero, everything simplifies down to R(α, γ) = V(x, y, z) where

x = sin(α)sin(γ)

y = -sin(α)cos(γ)

z= cos(α)

Now that I have these equations, I can grab the rotation matrix from the light I have the XYZ euler rotation for, multiply it by the unit vector to get an intermediate resultant, and extract the α and γ values using a bit of algebra.

Here is the Code:

import bpy

import math
from mathutils import *

RotMat = bpy.data.objects['XYZ Light'].rotation_euler.to_matrix()

Resultant = RotMat @ Vector((0,0,1))
alpha = math.acos(Resultant.z)
gamma = math.asin(Resultant.x/math.sin(alpha))
if Resultant.y > 0:
gamma = gamma *-1
alpha = alpha *-1
XZLight = bpy.data.objects['XZ Light']

XZLight.rotation_euler = Euler((alpha, 0, gamma), 'XYZ')


Note that because the Resultant.y is not used in the math, there is no way to know if it is negative or not. That's why I perform a simple check and flip the resulting directions if it's not.

The result of running this script is that you take one light that has coordinates in XYZ euler format and place another light in exactly the same angle, but only using the Z and X components. This is exactly the solution I was looking for.

• I don't understand why it has to be so complicated. If you use Track To Constraint it's easy to orient the light and then you can either apply the constraint or use object.matrix_world.to_euler() to get rotation euler in radians that you can then convert with math.degrees(). Am I missing something here? Commented Sep 28, 2022 at 7:40