2

Question:

My question is, how can I convert a Blender Z-Up RH rotation to Y-Up RH (Maya, Houdini, etc.) rotation?

(I believe Blender uses a Right-Handed Z-Up orientation... correct me if wrong)

Details:

Position seems pretty basic. I am simply getting the position column of the world matrix like so:

posX = lightObj.matrix_world[0][3]
posY = lightObj.matrix_world[2][3]
posZ = lightObj.matrix_world[1][3]

(swizzling Z and Y)

Rotations on the other hand seem to need more than a simple swizzle. I have figured out how to get the Blender world space rotation in XYZ by doing this:

lightObj.matrix_world.to_euler('XYZ')

Now if only I knew what to do with it... I have searched for conversion formulas online and come up with several incomplete/incorrect implementations.

PolyMesh
  • 645
  • 8
  • 17

1 Answers1

3

Finally got it! There were a few problems with my earlier attempts. The one that was throwing me off the most was incorrect position (because the rotations never looked consistently right with a wrong position)

It turns out I had the position wrong because the +Y in Blender is actually -Z in a Y-Up RH coordinate system. Or in other words when converting the code is:

posX = lightObj.matrix_world[0][3]
posY = lightObj.matrix_world[2][3]
posZ = -lightObj.matrix_world[1][3] # note the negative

(swizzle YZ and negate Z)

Another problem I encountered... It turns out there is a special case when exporting lights, which I didn't realize earlier. In Blender, the cone of a spotlight with zero rotations aims straight down, where in Maya, Houdini, and my game engine, spotlights face down the -Z. (If blender were to match this it would aim down the +Y)

So with these in mind, I came to this for rotations:

# for objects
obj = bpy.data.objects['objName']
mm = bpy_extras.io_utils.axis_conversion(from_forward='Y', from_up='Z', to_forward='-Z', to_up='Y')
om = obj.matrix_world.to_3x3()
t = mm * om
v = t.to_euler('XYZ')
print('pos:(%s, %s, %s)' % (obj.matrix_world.translation.x, obj.matrix_world.translation.z, -obj.matrix_world.translation.y))
print('rot:(%s, %s, %s)' % (degrees(v.x) + 90.0, degrees(v.y), degrees(v.z)))
# not totally sure why we need the +90 in X, but assume it has something to do with compensating for the axis_conversion

# for spot lights (they face straight down in Blender)
obj = bpy.data.objects['spotLightName']
mm = bpy_extras.io_utils.axis_conversion(from_forward='Y', from_up='Z', to_forward='-Z', to_up='Y')
om = obj.matrix_world.to_3x3()
t = mm * om
v = t.to_euler('XZY') # not sure why this needs to be XZY for spot lights and XYZ for objects
print('pos:(%s, %s, %s)' % (obj.matrix_world.translation.x, obj.matrix_world.translation.z, -obj.matrix_world.translation.y))
print('rot:(%s, %s, %s)' % (degrees(v.x), degrees(v.y), degrees(v.z)))
# note: there is no need for the axis_conversion rotation compensation due to the spotlight facing down already

As you can see in the comments, there are still things I am not clear on and not sure I am doing right, so please feel free to comment/correct me where wrong.

I have a feeling something might be off with my rotation order stuff, but I don't know what it should be. All I know intuitively is that it makes sense to use XZY since that is what I am swizzling to, that should match the post-swizzled rotation order so it is XYZ in both systems right?

PolyMesh
  • 645
  • 8
  • 17