Sigmmma / Blendkrieg

Halo Model importer and exporter for Blender.
GNU General Public License v3.0
11 stars 3 forks source link

Support rotation in test mock #18

Closed Mimickal closed 4 years ago

Mimickal commented 5 years ago

Rotation in Blender is more complicated than it first appears. The rotation mode an individual object uses is set as follows:

# Self-explanatory
object.rotation_mode = 'QUATERNION'

# These are both Euler systems. Every permutation of XYZ is supported
object.rotation_mode = 'XYZ'
object.rotation_mode = 'ZYX' 

Through a little bit of experimentation, we've discovered the following:

These quirks need to be (somewhat) accurately captured by the test mocks. Accurately enough that a script run against the mocks produces nearly-identical results to running that same script against real Blender.

Mimickal commented 5 years ago

Something helpful here to emulate the recalculation on rotation_mode assignment:

    @property
    def x(self): return self[0]
    @x.setter
    def x(self, new_val): self[0] = float(new_val)
Mimickal commented 5 years ago

Some functions that will be very helpful

def euler_to_quaternion(y, p, r):
    '''Angles are expected to be in radians.'''
    c0, c1, c2 = cos(y / 2), cos(p / 2), cos(r / 2)
    s1, s2, s3 = sin(y / 2), sin(p / 2), sin(r / 2)
    return (s1*s2*c2*+ c0*c1*s3,
            s1*c1*c2 + c0*s2*s3,
            c0*s2*c2 - s1*c1*s3,
            c0*c1*c2 - s1*s2*s3)
def quaternion_to_euler(i, j, k, w):
    '''Angles returned are in radians.'''
    p_sin = 2*(i * j + k * w);
    # check for singularities at north and south poles
    if p_sin > 0.99999999999999:
        return 2 * atan2(i, w),   pi / 2, 0
    elif p_sin < -0.99999999999999:
        return -2 * atan2(i, w), -pi / 2, 0
    else:
        y = atan2(2*(j*w - i*k), 1 - 2*(j**2 - k**2));
        p = asin(p_sin);
        r = atan2(2*(i*w - j*k), 1 - 2*(i**2 - k**2))
        return y, p, r
Mimickal commented 4 years ago

mathutils handles almost all of this for us. There's an Euler and Quaternion class that handles all the math for converting between the two, the same way Blender does it.

The only trick right now is it seems the standalone version of mathutils we're using seems to be outdated, and doesn't yet support the Euler((1, 2, 3), 'XYZ') constructor. Or if it does, it expects it in a way different than Blender 2.80's scripting terminal does.