2
$\begingroup$

I am building an XAML export script for Blender. I want to rotate the scene 90 degrees in the X axis to make it Y-up.

Currently I am using a matrix on a BMesh and that is rotating the models, but not the entire scene.

I've been looking at the ExportHelper method axis_conversion but I can't find an example of how you implement this. Not sure it's the correct thing to use in the first place.

Does anyone know of an example of using ExportHelper to do this, or know if I am on the right track using it.

$\endgroup$
2
$\begingroup$

Convert the axes of a scene using bpy_extras.io_utils.axis_conversion.

To convert such that both objects and their data, mesh in this case follow the new axis conversion, need to apply the conversion to both the object and its mesh data.

Image below shows Suzanne in blender default of Z up and -Y forward. With some translation, rotation and scale. Camera and Lamp are from default file.

Before

Lets change the axis As you pointed out in your answer the axis_conversion to Z forward Y up is a matter of rotating the axes -90 degrees about X.

>> [degrees(axis) for axis in axis_conversion("-Y", "Z", "Z", "Y").to_euler()]
[-90.00000250447816, -0.0, 0.0] 

For example sake: Lets apply this axis conversion to all objects in the scene

import bpy
from bpy_extras.io_utils import axis_conversion
context = bpy.context
m = axis_conversion(from_forward='-Y', 
        from_up='Z',
        to_forward='Z',
        to_up='Y').to_4x4()

scene = context.scene
for o in scene.objects:
    o.matrix_world = m * o.matrix_world

Image below shows the result. Globally all objects are transformed to our new global scheme of Y up and Z forward. Locally though, Suzanne is still Z up -Y forward.

After object axis tranforms

To locally transform Suzanne to our new system rotate her vertex coordinates by the rotation, then rotate the object coordinates back accordingly. In this answer I prattled on about local and global coordinates. What we are doing here ultimately is applying the axis conversion rotation to Suzanne.

To apply rotation I've rotated the vertex coordinates by the axis transform rotation. (In bmesh could use bmesh.ops.rotate(bm, geom=bm.verts[:], matrix = rot))

import bpy
from bpy_extras.io_utils import axis_conversion
context = bpy.context
m = axis_conversion(from_forward='-Y', 
        from_up='Z',
        to_forward='Z',
        to_up='Y').to_4x4()

rot = m.to_quaternion().to_matrix()
irot = rot.to_4x4().inverted()     

scene = context.scene
for o in scene.objects:
    o.matrix_world = m * o.matrix_world
    if o.type == 'MESH':
        # apply to mesh
        o.data.transform(rot)
        '''
        for v in o.data.vertices:
            v.co = rot * v.co
        '''
        # rotate globally inverse.
        o.matrix_world *= irot

Image below shows the result, now our axis conversion has been applied to both the objects globally, and mesh objects locally.

After object and mesh axis transforms

| improve this answer | |
$\endgroup$
  • $\begingroup$ What a great answer. Well done. $\endgroup$ – Haydn Mar 6 '18 at 11:59
  • $\begingroup$ Thankyou. Good luck with the importer, don't see much xaml since I went linux. $\endgroup$ – batFINGER Mar 6 '18 at 12:24
  • $\begingroup$ I don't understand this, why do you go through to_quaternion conversion? Why not use rot = m? I already run both ways and inspected the matrices in console and saw that quaternion conversion gave basically a different matrix, just don't get it... $\endgroup$ – Arise Feb 9 at 15:07
  • 1
    $\begingroup$ Could have also used rot = m.to_3x3() was only after the rotation part. Ultimately prob should have used m as sometimes it has a negating scale component. (when inspecting remember to consider a number like -1.3435885648505064e-07 to be 0) $\endgroup$ – batFINGER Feb 9 at 15:30
  • $\begingroup$ Oh you are right, after quaternions conversion, the matrix is kinda same only not perfect 0 or 1. The scientific notation tricked me here. $\endgroup$ – Arise Feb 9 at 17:59
0
$\begingroup$

The axis_conversion method is not the right method for me to use.

It basically takes a bunch of current and target axis's and gives a matrix, which basically says you need to rotate 90 degrees around the X axis.

To use its:

    matrix = mathutils.Matrix() 
    matrix = matrix * axis_conversion("-Y", "Z", "Z", "Y").to_4x4()

Example is from Nullege

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.