ボーン/ボールジョイントのワールド座標での中心位置を計算 (スクリプト)
ボーン/ボールジョイントのワールド座標での中心位置をスクリプトで計算します。
共通部分
import numpy
import math
# --------------------------------------.
# クォータニオンから4x4回転行列を計算.
# --------------------------------------.
def quaternion_matrix4x4 (q):
    m = numpy.matrix(numpy.identity(4))
    # q(w,x,y,z)から(x,y,z,w)に並べ替え.
    q2 = range(4)
    q2[0] = q[1]
    q2[1] = q[2]
    q2[2] = q[3]
    q2[3] = q[0]
    m[0,0] = q2[3]*q2[3] + q2[0]*q2[0] - q2[1]*q2[1] - q2[2]*q2[2]
    m[0,1] = 2.0 * q2[0] * q2[1] - 2.0 * q2[3] * q2[2]
    m[0,2] = 2.0 * q2[0] * q2[2] + 2.0 * q2[3] * q2[1]
    m[0,3] = 0.0
    m[1,0] = 2.0 * q2[0] * q2[1] + 2.0 * q2[3] * q2[2]
    m[1,1] = q2[3] * q2[3] - q2[0] * q2[0] + q2[1] * q2[1] - q2[2] * q2[2]
    m[1,2] = 2.0 * q2[1] * q2[2] - 2.0 * q2[3] * q2[0]
    m[1,3] = 0.0
    m[2,0] = 2.0 * q2[0] * q2[2] - 2.0 * q2[3] * q2[1]
    m[2,1] = 2.0 * q2[1] * q2[2] + 2.0 * q2[3] * q2[0]
    m[2,2] = q2[3] * q2[3] - q2[0] * q2[0] - q2[1] * q2[1] + q2[2] * q2[2]
    m[2,3] = 0.0
    m[3,0] = 0.0
    m[3,1] = 0.0
    m[3,2] = 0.0
    m[3,3] = q2[3] * q2[3] + q2[0] * q2[0] + q2[1] * q2[1] + q2[2] * q2[2]
    k = m[3,3]
    for i in range(3):
        for j in range(3):
            m[i,j] /= k
    m[3,3] = 1.0
    return m
# --------------------------------------.
# translateを4x4行列に変換.
# --------------------------------------.
def translate_matrix4x4 (pos):
    m = numpy.matrix(numpy.identity(4))
    m[3,0] = pos[0]
    m[3,1] = pos[1]
    m[3,2] = pos[2]
    return m
ボールジョイントのワールド座標での中心位置を計算
def calcBallJointWorldCenter(shape):
    cPos = numpy.array([0.0, 0.0, 0.0, 1.0])
    lwMat = numpy.matrix(shape.local_to_world_matrix)
    pos = shape.ball_joint.position
    joint_offset = shape.ball_joint.offset
    joint_rotate = quaternion_matrix4x4(shape.ball_joint.rotation)
    cPos2 = numpy.dot(cPos, joint_rotate)
    cPos2 = numpy.dot(cPos2, translate_matrix4x4(numpy.array(joint_offset) + numpy.array(pos)))
    cPos2 = numpy.dot(cPos2, lwMat)
    return numpy.array([cPos2[0,0], cPos2[0,1], cPos2[0,2]])
この計算は、以下も同じ結果になります。
def calcBallJointWorldCenter(shape):
    lwMat = numpy.matrix(shape.local_to_world_matrix)
    pos = shape.ball_joint.position
    m = numpy.matrix(shape.transformation_matrix).I
    m = numpy.dot(m, shape.transformation)
    cPos2 = numpy.array([pos[0], pos[1], pos[2], 1.0])
    cPos2 = numpy.dot(cPos2, m)
    cPos2 = numpy.dot(cPos2, lwMat)
    return numpy.array([cPos2[0,0], cPos2[0,1], cPos2[0,2]])
ボーンのワールド座標での中心位置を計算
def calcBoneWorldCenter(shape):
    cPos = numpy.array([0.0, 0.0, 0.0, 1.0])
    lwMat = numpy.matrix(shape.local_to_world_matrix)
    m = numpy.matrix(shape.bone_joint.matrix)
    joint_offset = shape.bone_joint.offset
    joint_rotate = quaternion_matrix4x4(shape.bone_joint.rotation)
    cPos2 = numpy.dot(cPos, joint_rotate)
    cPos2 = numpy.dot(cPos2, m)
    cPos2 = numpy.dot(cPos2, translate_matrix4x4(joint_offset))
    cPos2 = numpy.dot(cPos2, lwMat)
    return numpy.array([cPos2[0,0], cPos2[0,1], cPos2[0,2]])
この計算は、以下も同じ結果になります。
def calcBoneWorldCenter(shape):
    cPos = numpy.array([0.0, 0.0, 0.0, 1.0])
    lwMat = numpy.matrix(shape.local_to_world_matrix)
    m = numpy.matrix(shape.transformation)
    cPos2 = numpy.dot(cPos, m)
    cPos2 = numpy.dot(cPos2, lwMat)
    return numpy.array([cPos2[0,0], cPos2[0,1], cPos2[0,2]])
使用方法
上記の関数を使用して、選択形状がボールジョイントまたはボーンの場合、
ワールド座標での中心位置をメッセージウィンドウに表示します。
scene = xshade.scene()
shape = scene.active_shape()
cPos = [0.0, 0.0, 0.0]
if shape.is_ball_joint:     # ボールジョイントの場合.
    cPos = calcBallJointWorldCenter(shape)
if shape.is_bone_joint:     # ボーンの場合.
    cPos = calcBoneWorldCenter(shape)
print "center : " + str(cPos[0]) + ",  " + str(cPos[1]) + ", " + str(cPos[2])