コード例 #1
0
    def import_keyframe_controller(self,
                                   n_kfc,
                                   b_obj,
                                   bone_name=None,
                                   n_bone_bind_scale=None,
                                   n_bone_bind_rot_inv=None,
                                   n_bone_bind_trans=None):

        NifLog.debug('Importing keyframe controller for' + b_obj.name)

        b_action = b_obj.animation_data.action

        if bone_name:
            b_obj = b_obj.pose.bones[bone_name]

        translations = []
        scales = []
        rotations = []
        eulers = []
        n_kfd = None

        # transform controllers (dartgun.nif)
        if isinstance(n_kfc, NifFormat.NiTransformController):
            if n_kfc.interpolator:
                n_kfd = n_kfc.interpolator.data
        # B-spline curve import
        elif isinstance(n_kfc, NifFormat.NiBSplineInterpolator):
            # used by WLP2 (tiger.kf), but only for non-LocRotScale data
            # eg. bone stretching - see controlledblock.get_variable_1()
            # do not support this for now, no good representation in Blender
            if isinstance(n_kfc, NifFormat.NiBSplineCompFloatInterpolator):
                # pyffi lacks support for this, but the following gets float keys
                # keys = list(kfc._getCompKeys(kfc.offset, 1, kfc.bias, kfc.multiplier))
                return
            times = list(n_kfc.get_times())
            # just do these temp steps to avoid generating empty fcurves down the line
            trans_temp = [
                mathutils.Vector(tup) for tup in n_kfc.get_translations()
            ]
            if trans_temp:
                translations = zip(times, trans_temp)
            rot_temp = [
                mathutils.Quaternion(tup) for tup in n_kfc.get_rotations()
            ]
            if rot_temp:
                rotations = zip(times, rot_temp)
            scale_temp = list(n_kfc.get_scales())
            if scale_temp:
                scales = zip(times, scale_temp)
            # Bsplines are Bezier curves
            interp_rot = interp_loc = interp_scale = "BEZIER"
        else:
            # ZT2 & Fallout
            n_kfd = n_kfc.data
        if isinstance(n_kfd, NifFormat.NiKeyframeData):
            interp_rot = self.get_b_interp_from_n_interp(n_kfd.rotation_type)
            interp_loc = self.get_b_interp_from_n_interp(
                n_kfd.translations.interpolation)
            interp_scale = self.get_b_interp_from_n_interp(
                n_kfd.scales.interpolation)
            if n_kfd.rotation_type == 4:
                b_obj.rotation_mode = "XYZ"
                # uses xyz rotation
                if n_kfd.xyz_rotations[0].keys:
                    # euler keys need not be sampled at the same time in KFs
                    # but we need complete key sets to do the space conversion
                    # so perform linear interpolation to import all keys properly

                    # get all the keys' times
                    times_x = [key.time for key in n_kfd.xyz_rotations[0].keys]
                    times_y = [key.time for key in n_kfd.xyz_rotations[1].keys]
                    times_z = [key.time for key in n_kfd.xyz_rotations[2].keys]
                    # the unique time stamps we have to sample all curves at
                    times_all = sorted(set(times_x + times_y + times_z))
                    # the actual resampling
                    x_r = interpolate(
                        times_all, times_x,
                        [key.value for key in n_kfd.xyz_rotations[0].keys])
                    y_r = interpolate(
                        times_all, times_y,
                        [key.value for key in n_kfd.xyz_rotations[1].keys])
                    z_r = interpolate(
                        times_all, times_z,
                        [key.value for key in n_kfd.xyz_rotations[2].keys])
                eulers = zip(times_all, zip(x_r, y_r, z_r))
            else:
                b_obj.rotation_mode = "QUATERNION"
                rotations = [(key.time, key.value)
                             for key in n_kfd.quaternion_keys]

            if n_kfd.scales.keys:
                scales = [(key.time, key.value) for key in n_kfd.scales.keys]

            if n_kfd.translations.keys:
                translations = [(key.time, key.value)
                                for key in n_kfd.translations.keys]

        # ZT2 - get extrapolation for every kfc
        if isinstance(n_kfc, NifFormat.NiKeyframeController):
            flags = n_kfc.flags
        # fallout, Loki - we set extrapolation according to the root NiControllerSequence.cycle_type
        else:
            flags = None

        if eulers:
            NifLog.debug('Rotation keys..(euler)')
            fcurves = self.create_fcurves(b_action, "rotation_euler", range(3),
                                          flags, bone_name)
            for t, val in eulers:
                key = mathutils.Euler(val)
                if bone_name:
                    key = math.import_keymat(
                        n_bone_bind_rot_inv,
                        key.to_matrix().to_4x4()).to_euler()
                self.add_key(fcurves, t, key, interp_rot)
        elif rotations:
            NifLog.debug('Rotation keys...(quaternions)')
            fcurves = self.create_fcurves(b_action, "rotation_quaternion",
                                          range(4), flags, bone_name)
            for t, val in rotations:
                key = mathutils.Quaternion([val.w, val.x, val.y, val.z])
                if bone_name:
                    key = math.import_keymat(
                        n_bone_bind_rot_inv,
                        key.to_matrix().to_4x4()).to_quaternion()
                self.add_key(fcurves, t, key, interp_rot)
        if translations:
            NifLog.debug('Translation keys...')
            fcurves = self.create_fcurves(b_action, "location", range(3),
                                          flags, bone_name)
            for t, val in translations:
                key = mathutils.Vector([val.x, val.y, val.z])
                if bone_name:
                    key = math.import_keymat(
                        n_bone_bind_rot_inv,
                        mathutils.Matrix.Translation(
                            key - n_bone_bind_trans)).to_translation()
                self.add_key(fcurves, t, key, interp_loc)
        if scales:
            NifLog.debug('Scale keys...')
            fcurves = self.create_fcurves(b_action, "scale", range(3), flags,
                                          bone_name)
            for t, val in scales:
                key = (val, val, val)
                self.add_key(fcurves, t, key, interp_scale)
コード例 #2
0
def convert_euler(bullet_euler):
    """
    input blender rad angles and convert to bullet rad coordinates
    """
    return list(mathutils.Euler(bullet_euler, "ZYX"))
コード例 #3
0
ファイル: urdf.py プロジェクト: Netzahualcoyotl/phobos
def calc_pose_formats(position, rotation, pivot=(0, 0, 0)):
    """Create a dictionary containing various representations of the pose
    represented by 'position' and 'rotation':
        - translation == position
        - rotation_quaternion == rotation
        - rotation_euler: euler angles
        - matrix: position and rotation in 4x4 matrix form

    :param position: The position to include in the dictionary.
    :type position: list
    :param rotation: The rotation to include into the dictionary. It can either be an euler angle or a quaternion.
    :type rotation: list
    :param pivot: The pivot point.
    :type pivot: list
    :return: dict
    """
    px, py, pz = position
    if len(rotation) == 3:
        rot = mathutils.Euler(rotation).to_quaternion()
        # TODO delete me?
        #print(rotation)
    else:
        rot = mathutils.Quaternion(rotation)

    # TODO delete me?
    #if angle_offset is not 0.0:
    #    axis_vec = mathutils.Vector(axis)

    #    offset_matrix = mathutils.Matrix.Rotation(angle_offset, 4, axis_vec) #get_axis_rotation_matrix(axis, angle_offset)
    #    rot_matrix = rot.to_matrix().to_4x4()
    #    applied_matrix = rot_matrix * offset_matrix
    #    rot = applied_matrix.to_quaternion()

    rw, rx, ry, rz = rot
    pose_dict = {}

    neg_pivot_translation = mathutils.Matrix.Translation(
        (-pivot[0], -pivot[1], -pivot[2]))
    pivot_translation = mathutils.Matrix.Translation(pivot)
    rotation_matrix = mathutils.Quaternion(rot).to_matrix().to_4x4()
    translation = mathutils.Matrix.Translation(position)
    # TODO delete me?
    #print()
    #print("translation:", translation)
    #print("neg_pivot_translation:", neg_pivot_translation)
    #print("rotation_matrix:", rotation_matrix)
    #print("pivot_translation", pivot_translation)
    #print()
    #transformation_matrix = translation * neg_pivot_translation * rotation_matrix * pivot_translation
    transformation_matrix = translation * rotation_matrix * neg_pivot_translation

    rm = transformation_matrix
    #TODO: this is not good
    matrix = [[rm[0][0], rm[0][1], rm[0][2], rm[0][3]],
              [rm[1][0], rm[1][1], rm[1][2], rm[1][3]],
              [rm[2][0], rm[2][1], rm[2][2], rm[2][3]],
              [rm[3][0], rm[3][1], rm[3][2], rm[3][3]]]
    pose_dict['matrix'] = matrix
    loc, rot, sca = transformation_matrix.decompose()
    pose_dict['translation'] = [loc.x, loc.y, loc.z]
    pose_dict['rotation_quaternion'] = [rot.w, rot.x, rot.y, rot.z]
    euler = rot.to_euler()
    pose_dict['rotation_euler'] = [euler.x, euler.y, euler.z]

    # TODO delete me?
    #translation = [px, py, pz]
    #quaternion = mathutils.Quaternion([rw, rx, ry, rz])
    #euler = quaternion.to_euler()
    ##print(euler)
    #pose_dict['translation'] = translation
    ##pose_dict['rotation_quaternion'] = [rw, rx, ry, rz]
    #pose_dict['rotation_euler'] = [euler.x, euler.y, euler.z]
    #rm = quaternion.to_matrix()
    #matrix = [[rm[0][0], rm[0][1], rm[0][2], px],
    #          [rm[1][0], rm[1][1], rm[1][2], py],
    #          [rm[2][0], rm[2][1], rm[2][2], pz],
    #          [0.0,      0.0,      0.0,      1.0]]
    #
    # pose_dict['matrix'] = matrix

    #print()
    #print('pose_dict:', pose_dict)
    #print()

    return pose_dict
コード例 #4
0
    def constructMovement(self, J, helicity, amt, rig, a, b, y, o):

        # Linkages
        aa = [[0 for i in range(4)] for j in range(4)] # Link α(i) - α(j)
        ab = [[0 for i in range(4)] for j in range(4)] # Link α(i) - β(j)
        ya = [[0 for i in range(4)] for j in range(4)] # Link γ(i) - α(j)
        ao = [[0 for i in range(4)] for j in range(4)] # Link α(i) - δ(j)
        ob = [[0 for i in range(self.J)] for j in range(self.J)] # Link δ(i) - β(j)
        yy = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - γ(j)
        by = [[0 for i in range(self.J)] for j in range(self.J)] # Link β(i) - γ(j)
        yo = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - δ(j)

        rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
        rig.show_in_front = True
        amt.show_names = True
        amt.display_type = 'STICK'
#        amt.display_type = 'BBONE'

        # Link object to scene

        bpy.data.collections['movement'].objects.link(rig)
        bpy.context.view_layer.objects.active = rig
        bpy.context.view_layer.update()

        # Edit
        bpy.ops.object.editmode_toggle()

        # Construction Linkage
        aa[2][1] = amt.edit_bones.new('a2a1')
        aa[2][1].head = a[2]
        aa[2][1].tail = a[1]
        
        ab[1][1] = amt.edit_bones.new('a1b1')
        ab[1][1].head = a[1]
        ab[1][1].tail = b[1]
        ab[1][1].parent = aa[2][1]
 
        by[1][1] = amt.edit_bones.new('b1y1')
        by[1][1].head = b[1]
        by[1][1].tail = y[1]
        by[1][1].parent = ab[1][1]
        by[1][1].use_inherit_rotation = False

        ya[1][2] = amt.edit_bones.new('y1a2')
        ya[1][2].head = y[1]
        ya[1][2].tail = a[2]
        ya[1][2].parent = by[1][1]

        ao[2][1] = amt.edit_bones.new('a2o1')
        ao[2][1].head = a[2]
        ao[2][1].tail = o[1]
        ao[2][1].parent = ya[1][2]

        ob[1][2] = amt.edit_bones.new('o1b2')
        ob[1][2].head = o[1]
        ob[1][2].tail = b[2]
        ob[1][2].parent = ao[2][1]
        
        yy[1][2] = amt.edit_bones.new('y1y2')
        yy[1][2].head = y[1]
        yy[1][2].tail = y[2]
        yy[1][2].parent = by[1][1]

        for j in range(2, J - 1):

            by[j][j] = amt.edit_bones.new('b'+ str(j) + 'y'+ str(j))
            by[j][j].head = b[j]
            by[j][j].tail = y[j]
            by[j][j].parent = ob[j-1][j]

            yo[j][j] = amt.edit_bones.new('y'+ str(j) + 'o'+ str(j))
            yo[j][j].head = y[j]
            yo[j][j].tail = o[j]
            yo[j][j].parent = yy[j-1][j]

            yy[j][j+1] = amt.edit_bones.new('y'+ str(j) + 'y'+ str(j+1))
            yy[j][j+1].head = y[j]
            yy[j][j+1].tail = y[j+1]
            yy[j][j+1].parent = by[j][j]

            if j < (J-2):
                ob[j][j+1] = amt.edit_bones.new('o'+ str(j) + 'b'+ str(j+1))
                ob[j][j+1].head = o[j]
                ob[j][j+1].tail = b[j+1]
                ob[j][j+1].parent = yo[j][j]

        # all bones select

        # Bone constraints. Armature must be in pose mode.
        bpy.ops.object.mode_set(mode='POSE')

        bpy.ops.pose.select_all(action="SELECT")

        # Edit
        bpy.ops.object.editmode_toggle()

        if helicity == 'right':
            bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Z')
        else:
            bpy.ops.armature.calculate_roll(type='GLOBAL_NEG_Z')
 
        # IK constraint
        cns = rig.pose.bones['y1a2'].constraints.new('IK')
        cns.name = 'Ik'
        cns.target = rig
        cns.subtarget = 'a2a1'
        cns.chain_count = 2
        cns.use_stretch = False

        for j in range(2, J - 1):
            cns = rig.pose.bones['b'+str(j) +'y'+str(j)].constraints.new('IK')
            cns.name = 'Ik'
            cns.target = rig
            cns.subtarget = 'y'+str(j)+'o'+str(j)
            cns.iterations = 500
            cns.chain_count = 2
            cns.use_stretch = False

        bpy.ops.object.mode_set(mode='OBJECT')
コード例 #5
0
    def configMovement(self, P, A, J, a, b, y, o):

        a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
        print ("a1 =", a[1])

        a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
        print ("a2 =", a[2])

        b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
        print ("b1 =", b[1])

        o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
        print ("o1 =", o[1])

        B = A * 2 * sqrt (2)
        C = B + (B * sqrt (2))
        D = C * sqrt (2)
        E = C + D
        
        y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
        print ("y1 =", y[1])

        b[2] = mathutils.Euler(((A*3/0.431828)*A, (A/0.431828)*A, 0.0), 'XYZ')
        print ("b2 =", b[2])

        b[3] = mathutils.Euler(((-A/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
        print ("b3 =", b[3])
        
        y[2] = mathutils.Euler(((A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
        print ("y2 =", y[2])

        y[3] = mathutils.Euler(((A/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
        print ("y3 =", y[3])

        o[2] = mathutils.Euler(((-A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
        print ("o2 =", o[2])
        
        o[3] = mathutils.Euler(((A/0.431828)*A, (2.53357/0.431828)*A, 0.0), 'XYZ')
        print ("o3 =", o[3])
        
        y[4] = mathutils.Euler(((A*3/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
        print ("y4 =", y[4])
コード例 #6
0
    def execute(self, context):
        scene = context.scene

        stageProps=EDFLibrary.CalcStageBladeAngles(R=scene.reaction,\
                        phi=scene.flowCoefficient,\
                        psi=scene.stageLoading,\
                        radius=scene.meanLineRadius,
                        rpm = scene.rpm)
        print("")
        print("")
        print("Drawing 2D Rotor/Stator blades")
        print("")
        print("")

        chord = 1
        deltaBeta = (stageProps.beta2 - stageProps.beta1)
        camber = chord / 2 / math.sin(deltaBeta) - chord / 2 / math.tan(
            deltaBeta)
        print("beta " +
              str((stageProps.beta1 + stageProps.beta2) / 2 * 180 / math.pi))
        print("rotorcamber " + str(camber * 100))
        print("deltaBeta " + str(deltaBeta * 180 / math.pi))
        TurboMachLib.NACA4(name='rotor2D',\
                        camber_root=camber*100,\
                        camber_tip=camber*100,\
                        camber_position=35,\
                        thickness=6,\
                        bladeHeight=1,\
                        twistAngle=0,\
                        rootChord=1,\
                        tipChord=1,\
                        centerOfTwist=[0,0],\
                        nspan=1,\
                        npts=24)

        DLUtils.RotateObject(
            'rotor2D',
            mathutils.Euler([0, 0,
                             -(stageProps.beta2 + stageProps.beta1) / 2]))
        deltaAlpha = (stageProps.alpha2 - stageProps.alpha1)
        camber = chord / 2 / math.sin(deltaAlpha) - chord / 2 / math.tan(
            deltaAlpha)
        print("alpha " +
              str((stageProps.alpha1 + stageProps.alpha2) / 2 * 180 / math.pi))
        print("statorcamber " + str(camber * 100))
        print("deltaAlpha " + str(deltaAlpha * 180 / math.pi))
        TurboMachLib.NACA4(name='stator2D',\
                        camber_root=camber*100,\
                        camber_tip=camber*100,\
                        camber_position=35,\
                        thickness=6,\
                        bladeHeight=1,\
                        twistAngle=0,\
                        rootChord=1,\
                        tipChord=1,\
                        centerOfTwist=[0,0],\
                        nspan=1,\
                        npts=15)

        DLUtils.MoveObject('stator2D', mathutils.Vector([1, 0, 0]))
        DLUtils.RotateObject(
            'stator2D',
            mathutils.Euler(
                [0, 0, (stageProps.alpha2 + stageProps.alpha1) / 2]))

        #stageProps.GenerateReport("test.txt")

        return {'FINISHED'}
コード例 #7
0
def road_generate(ops, road_width, invert):
    bpy.ops.object.mode_set(mode='EDIT')
    me = bpy.context.edit_object.data
    bm = bmesh.from_edit_mesh(me)

    edges = [e for e in bm.edges if e.select and not e.hide]

    lines = get_lines(edges)
    if len(lines) != 1:
        ops.report({"WARNING"}, "1つの線になるように辺を選択して下さい")
        return False

    vs = get_sorted_verts(lines[0])
    if invert:
        vs.reverse()

    vs_l = []
    vs_r = []

    rot_l = mathutils.Euler((0.0, 0.0, math.radians(90.0)), 'XYZ')
    rot_r = mathutils.Euler((0.0, 0.0, math.radians(-90.0)), 'XYZ')

    rot_c = None
    for n, v in enumerate(vs):
        #v.select = False
        vb = None
        vf = None
        if n != 0:
            vb = vs[n - 1]
        if n != len(vs) - 1:
            vf = vs[n + 1]

        co_bl = None
        co_br = None
        co_fl = None
        co_fr = None
        if vb != None:
            rot_b = (v.co - vb.co)
            rot_b.z = 0.0
            rot_b.normalize()
            co_bl = mathutils.Vector(rot_b)
            co_bl.rotate(rot_l)
            co_bl *= road_width / 2
            co_br = mathutils.Vector(rot_b)
            co_br.rotate(rot_r)
            co_br *= road_width / 2
        if vf != None:
            rot_f = (vf.co - v.co)
            rot_f.z = 0.0
            rot_f.normalize()
            co_fl = mathutils.Vector(rot_f)
            co_fl.rotate(rot_l)
            co_fl *= road_width / 2
            co_fr = mathutils.Vector(rot_f)
            co_fr.rotate(rot_r)
            co_fr *= road_width / 2

        if n == 0:
            vs_l = vs_l + [v.co + co_fl]
            vs_r = vs_r + [v.co + co_fr]
        elif n == len(vs) - 1:
            vs_l = vs_l + [v.co + co_bl]
            vs_r = vs_r + [v.co + co_br]
        else:
            vc = get_cross_point(vb.co + co_bl, v.co + co_bl, vf.co + co_fl,
                                 v.co + co_fl, False)
            vc.z = v.co.z
            vs_l = vs_l + [vc]
            vc = get_cross_point(vb.co + co_br, v.co + co_br, vf.co + co_fr,
                                 v.co + co_fr, False)
            vc.z = v.co.z
            vs_r = vs_r + [vc]

    vb = None
    vbl = None
    vbr = None

    for v, vl, vr in zip(vs, vs_l, vs_r):
        vfl = bm.verts.new(vl)
        vfr = bm.verts.new(vr)

        if vb != None:
            bm.faces.new([vfl, vbl, vb, v]).select = True
            bm.faces.new([v, vb, vbr, vfr]).select = True

        vb = v
        vbl = vfl
        vbr = vfr

    bmesh.update_edit_mesh(me)
    bm.calc_tessface()
    bm.normal_update()
    return True
コード例 #8
0
def _import_main(fpath, context, creader):
    object_name = os.path.basename(fpath.lower())

    bpy_arm_obj = None
    renamemap = {}
    meshes_data = None

    unread_chunks = []

    for (cid, data) in creader:
        if cid == Chunks.Object.VERSION:
            reader = PackedReader(data)
            ver = reader.getf('H')[0]
            if ver != 0x10:
                raise AppError('unsupported OBJECT format version',
                               log.props(version=ver))
        elif cid == Chunks.Object.MESHES:
            meshes_data = data
        elif (cid == Chunks.Object.SURFACES) or (cid == Chunks.Object.SURFACES1) or \
            (cid == Chunks.Object.SURFACES2):
            reader = PackedReader(data)
            surfaces_count = reader.int()
            if cid == Chunks.Object.SURFACES:
                try:
                    xrlc_reader = PackedReader(
                        creader.next(Chunks.Object.SURFACES_XRLC))
                    xrlc_shaders = [
                        xrlc_reader.gets() for _ in range(surfaces_count)
                    ]
                except:
                    xrlc_shaders = ['default' for _ in range(surfaces_count)]
            for surface_index in range(surfaces_count):
                if cid == Chunks.Object.SURFACES:
                    name = reader.gets()
                    eshader = reader.gets()
                    flags = reader.getf('B')[0]
                    reader.skip(4 + 4)  # fvf and TCs count
                    texture = reader.gets()
                    vmap = reader.gets()
                    if texture != vmap or not (texture and vmap):
                        old_object_format = False
                        renamemap[vmap.lower()] = vmap
                    else:  # old format (Objects\Rainbow\lest.object)
                        old_object_format = True
                        vmap = 'Texture'
                    gamemtl = 'default'
                    cshader = xrlc_shaders[surface_index]
                else:
                    name = reader.gets()
                    eshader = reader.gets()
                    cshader = reader.gets()
                    gamemtl = reader.gets(
                    ) if cid == Chunks.Object.SURFACES2 else 'default'
                    texture = reader.gets()
                    vmap = reader.gets()
                    if texture != vmap or not (texture and vmap):
                        old_object_format = False
                        renamemap[vmap.lower()] = vmap
                    else:  # old format (Objects\corps\corp_BYAKA.object)
                        old_object_format = True
                        vmap = 'Texture'
                    renamemap[vmap.lower()] = vmap
                    flags = reader.int()
                    reader.skip(4 + 4)  # fvf and ?
                bpy_material = None
                tx_filepart = texture.replace('\\', os.path.sep).lower()
                for material in bpy.data.materials:
                    if not material.name.startswith(name):
                        continue
                    if material.xray.flags != flags:
                        continue
                    if material.xray.eshader != eshader:
                        continue
                    if material.xray.cshader != cshader:
                        continue
                    if material.xray.gamemtl != gamemtl:
                        continue

                    if (not texture) and (not vmap):
                        all_empty_slots = all(
                            not slot for slot in material.texture_slots)
                        if all_empty_slots:
                            bpy_material = material
                            break

                    ts_found = False
                    for slot in material.texture_slots:
                        if not slot:
                            continue
                        if slot.uv_layer != vmap:
                            continue
                        if not _is_compatible_texture(slot.texture,
                                                      tx_filepart):
                            continue
                        ts_found = True
                        break
                    if not ts_found:
                        continue
                    bpy_material = material
                    break
                if bpy_material is None:
                    bpy_material = bpy.data.materials.new(name)
                    bpy_material.xray.version = context.version
                    bpy_material.xray.flags = flags
                    bpy_material.xray.eshader = eshader
                    bpy_material.xray.cshader = cshader
                    bpy_material.xray.gamemtl = gamemtl
                    bpy_material.use_shadeless = True
                    bpy_material.use_transparency = True
                    bpy_material.alpha = 0
                    if texture:
                        bpy_texture = bpy.data.textures.get(texture)
                        if (bpy_texture is None) \
                            or not _is_compatible_texture(bpy_texture, tx_filepart):
                            bpy_texture = bpy.data.textures.new(texture,
                                                                type='IMAGE')
                            bpy_texture.image = context.image(texture)
                            bpy_texture.use_preview_alpha = True
                        bpy_texture_slot = bpy_material.texture_slots.add()
                        bpy_texture_slot.texture = bpy_texture
                        bpy_texture_slot.texture_coords = 'UV'
                        bpy_texture_slot.uv_layer = vmap
                        bpy_texture_slot.use_map_color_diffuse = True
                        bpy_texture_slot.use_map_alpha = True
                context.loaded_materials[name] = bpy_material
        elif (cid == Chunks.Object.BONES) or (cid == Chunks.Object.BONES1):
            if cid == Chunks.Object.BONES:
                reader = PackedReader(data)
                bones_count = reader.int()
                if not bones_count:
                    continue  # Do not create an armature if zero bones
            if bpy and (bpy_arm_obj is None):
                bpy_armature = bpy.data.armatures.new(object_name)
                bpy_armature.use_auto_ik = True
                bpy_armature.draw_type = 'STICK'
                bpy_arm_obj = bpy.data.objects.new(object_name, bpy_armature)
                bpy_arm_obj.show_x_ray = True
                bpy.context.scene.objects.link(bpy_arm_obj)
                bpy.context.scene.objects.active = bpy_arm_obj
            if cid == Chunks.Object.BONES:
                for _ in range(bones_count):
                    name, parent, vmap = reader.gets(), reader.gets(
                    ), reader.gets()
                    offset, rotate, length = read_v3f(reader), read_v3f(
                        reader), reader.getf('f')[0]
                    rotate = rotate[2], rotate[1], rotate[0]
                    bpy_bone = _create_bone(context, bpy_arm_obj, name, parent,
                                            vmap, offset, rotate, length,
                                            renamemap)
                    xray = bpy_bone.xray
                    xray.mass.gamemtl = 'default_object'
                    xray.mass.value = 10
                    xray.ikjoint.lim_x_spr, xray.ikjoint.lim_x_dmp = 1, 1
                    xray.ikjoint.lim_y_spr, xray.ikjoint.lim_y_dmp = 1, 1
                    xray.ikjoint.lim_z_spr, xray.ikjoint.lim_z_dmp = 1, 1
                    xray.ikjoint.spring = 1
                    xray.ikjoint.damping = 1
            else:
                for (_, bdat) in ChunkedReader(data):
                    _import_bone(context, ChunkedReader(bdat), bpy_arm_obj,
                                 renamemap)
            bpy.ops.object.mode_set(mode='EDIT')
            try:
                if context.operator.shaped_bones:
                    bones = bpy_armature.edit_bones
                    lenghts = [0] * len(bones)
                    for i, bone in enumerate(bones):
                        min_rad_sq = math.inf
                        for j, bone1 in enumerate(bones):
                            if j == i:
                                continue
                            rad_sq = (bone1.head - bone.head).length_squared
                            if rad_sq < min_rad_sq:
                                min_rad_sq = rad_sq
                        lenghts[i] = math.sqrt(min_rad_sq)
                    for bone, length in zip(bones, lenghts):
                        bone.length = min(max(length * 0.4, 0.01), 0.1)
            finally:
                bpy.ops.object.mode_set(mode='OBJECT')
            for bone in bpy_arm_obj.pose.bones:
                bone.rotation_mode = 'ZXY'
        elif (cid
              == Chunks.Object.PARTITIONS0) or (cid
                                                == Chunks.Object.PARTITIONS1):
            bpy.context.scene.objects.active = bpy_arm_obj
            bpy.ops.object.mode_set(mode='POSE')
            try:
                reader = PackedReader(data)
                for _partition_idx in range(reader.int()):
                    bpy.ops.pose.group_add()
                    bone_group = bpy_arm_obj.pose.bone_groups.active
                    bone_group.name = reader.gets()
                    for _bone_idx in range(reader.int()):
                        name = reader.gets(
                        ) if cid == Chunks.Object.PARTITIONS1 else reader.int(
                        )
                        bpy_arm_obj.pose.bones[name].bone_group = bone_group
            finally:
                bpy.ops.object.mode_set(mode='OBJECT')
        elif cid == Chunks.Object.MOTIONS:
            if not context.import_motions:
                continue
            reader = PackedReader(data)
            import_motions(reader, bpy_arm_obj)
        elif cid == Chunks.Object.LIB_VERSION:
            pass  # skip obsolete chunk
        else:
            unread_chunks.append((cid, data))

    mesh_objects = []
    for (_, mdat) in ChunkedReader(meshes_data):
        mesh = _import_mesh(context, ChunkedReader(mdat), renamemap)

        if bpy_arm_obj:
            bpy_armmod = mesh.modifiers.new(name='Armature', type='ARMATURE')
            bpy_armmod.object = bpy_arm_obj
            mesh.parent = bpy_arm_obj

        mesh_objects.append(mesh)
        bpy.context.scene.objects.link(mesh)

    bpy_obj = bpy_arm_obj
    if bpy_obj is None:
        if len(mesh_objects) == 1:
            bpy_obj = mesh_objects[0]
            bpy_obj.name = object_name
        else:
            bpy_obj = bpy.data.objects.new(object_name, None)
            for mesh in mesh_objects:
                mesh.parent = bpy_obj
            bpy.context.scene.objects.link(bpy_obj)

    bpy_obj.xray.version = context.version
    bpy_obj.xray.isroot = True
    if fpath.lower().startswith(
            context.objects_folder.lower()) and context.objects_folder:
        object_folder_length = len(context.objects_folder)
        bpy_obj.xray.export_path = os.path.dirname(
            fpath.lower())[object_folder_length:]

    for (cid, data) in unread_chunks:
        if cid == Chunks.Object.TRANSFORM:
            reader = PackedReader(data)
            pos = read_v3f(reader)
            rot = read_v3f(reader)
            bpy_obj.matrix_basis *= mathutils.Matrix.Translation(pos) \
                * mathutils.Euler(rot, 'YXZ').to_matrix().to_4x4()
        elif cid == Chunks.Object.FLAGS:
            length_data = len(data)
            if length_data == 4:
                bpy_obj.xray.flags = PackedReader(data).int()
            elif length_data == 1:  # old object format
                bpy_obj.xray.flags = PackedReader(data).getf('B')[0]
        elif cid == Chunks.Object.USERDATA:
            bpy_obj.xray.userdata = \
                PackedReader(data).gets(onerror=lambda e: log.warn('bad userdata', error=e))
        elif cid == Chunks.Object.LOD_REF:
            bpy_obj.xray.lodref = PackedReader(data).gets()
        elif cid == Chunks.Object.REVISION:
            reader = PackedReader(data)
            bpy_obj.xray.revision.owner = reader.gets()
            bpy_obj.xray.revision.ctime = reader.int()
            bpy_obj.xray.revision.moder = reader.gets()
            bpy_obj.xray.revision.mtime = reader.int()
        elif cid == Chunks.Object.MOTION_REFS:
            mrefs = bpy_obj.xray.motionrefs_collection
            for mref in PackedReader(data).gets().split(','):
                mrefs.add().name = mref
        elif cid == Chunks.Object.SMOTIONS3:
            reader = PackedReader(data)
            mrefs = bpy_obj.xray.motionrefs_collection
            for _ in range(reader.int()):
                mrefs.add().name = reader.gets()
        else:
            log.debug('unknown chunk', cid=cid)
コード例 #9
0
    def run(self):
        self._init_bvh_tree()

        cam_ob = bpy.context.scene.camera
        cam = cam_ob.data

        # Set resolution and aspect ratio, as they have an influence on the near plane
        bpy.context.scene.render.resolution_x = self.config.get_int(
            "resolution_x", 512)
        bpy.context.scene.render.resolution_y = self.config.get_int(
            "resolution_y", 512)
        bpy.context.scene.render.pixel_aspect_x = self.config.get_float(
            "pixel_aspect_x", 1)

        room_id = 0
        for room_obj in bpy.context.scene.objects:
            # Find room objects
            if "type" in room_obj and room_obj[
                    "type"] == "Room" and "bbox" in room_obj:

                floor_obj = self._find_floor(room_obj)
                if floor_obj is None:
                    continue

                number_of_cams = self._calc_number_of_cams_in_room(room_obj)
                print("Generating " + str(number_of_cams) + " cams for room " +
                      room_obj.name + " (" + str(room_obj["roomTypes"]) + ")")

                # Now try to generate the requested number of cams
                successful_tries = 0
                tries = 0
                while successful_tries < number_of_cams and tries < self.max_tries_per_room:

                    tries += 1
                    position = self._sample_position(room_obj)

                    if not self._position_is_above_floor(position, floor_obj):
                        continue

                    orientation = self._sample_orientation()

                    # Compute the world matrix of a cam with the given pose
                    world_matrix = mathutils.Matrix.Translation(
                        mathutils.Vector(position)) @ mathutils.Euler(
                            orientation, 'XYZ').to_matrix().to_4x4()

                    if not self._perform_obstacle_in_view_check(
                            cam, position, world_matrix):
                        continue

                    if self._scene_coverage_score(
                            cam, position,
                            world_matrix) < self.min_interest_score:
                        continue

                    # Set the camera pose at the next frame
                    self.cam_pose_collection.add_item({
                        "location":
                        list(position),
                        "rotation":
                        list(orientation),
                        "room_id":
                        room_id
                    })

                    successful_tries += 1

                print(str(tries) + " tries were necessary")
                room_id += 1
コード例 #10
0
    def configMovement(self, P, A, J, a, b, y, o):

        a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
        print("a1 =", a[1])

        a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
        print("a2 =", a[2])

        b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
        print("b1 =", b[1])

        o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
        print("o1 =", o[1])

        B = A * 2 * sqrt(2)
        C = B + (B * sqrt(2))
        D = C * sqrt(2)
        E = C + D

        y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
        print("y1 =", y[1])

        b[2] = mathutils.Euler(
            ((3.37305 / 0.578724) * A, (-2.2156 / 0.578724) * A, 0.0), 'XYZ')
        print("b2 =", b[2])

        b[3] = mathutils.Euler(
            ((3.37305 / 0.578724) * A, (-6.16738 / 0.578724) * A, 0.0), 'XYZ')
        print("b3 =", b[3])

        b[4] = mathutils.Euler(
            ((1.05816 / 0.578724) * A, (-4.5305 / 0.578724) * A, 0.0), 'XYZ')
        print("b4 =", b[4])

        y[2] = mathutils.Euler(
            ((2.2156 / 0.578724) * A, (-3.37305 / 0.578724) * A, 0.0), 'XYZ')
        print("y2 =", y[2])

        y[3] = mathutils.Euler(
            ((5.00993 / 0.578724) * A, (-6.16738 / 0.578724) * A, 0.0), 'XYZ')
        print("y3 =", y[3])

        o[2] = b[2]
        print("o2 =", o[2])

        o[3] = mathutils.Euler(
            ((5.00993 / 0.578724) * A, (-4.5305 / 0.578724) * A, 0.0), 'XYZ')
        print("o3 =", o[3])

        y[4] = y[2]
        print("y4 =", y[4])

        o[4] = b[4]
        print("o4 =", o[4])

        b[5] = mathutils.Euler(
            ((-1.73617 / 0.578724) * A, (-1.73617 / 0.578724) * A, 0.0), 'XYZ')
        print("b5 =", b[5])

        y[5] = y[1]
        print("y5 =", y[5])

        o[5] = b[5]

        y[6] = mathutils.Euler(
            ((-3.37305 / 0.578724) * A, (2.2156 / 0.578724) * A, 0.0), 'XYZ')
        print("y6 =", y[6])
コード例 #11
0
ファイル: geometries.py プロジェクト: yarrrtem/phobos
def createGeometry(viscol, geomsrc, linkobj=None):
    """Creates Blender object for visual or collision objects.
    
    If the creation fails, nothing is returned.
    
    These entries in the dictionary are mandatory:
    
    |   **geometry**:
    |       **type**: type of geometry (mesh, box, cylinder, sphere)
    
    Depending on the geometry type other values are required: `size`, `radius`, `length`
    
    These entries are optional:
    
    |   **geometry**:
    |       **scale**: scale for the new geometry
    |   **material**: material name to assign to the visual
    |   **pose**: specifies the placement of the new object relative to the optional linkobj
    |       **translation**: position vector for the new object
    |       **rotation_euler**: rotation for the new object
    
    Furthermore any generic properties, prepended by a ``$`` will be added as custom properties to
    the visual/collision object. E.g. ``$test/etc`` would be put to visual/test/etc for a visual
    object. However, these properties are extracted only in the first layer of hierarchy.

    Args:
      viscol(dict): visual/collision model dictionary representation
      geomsrc(str): phobostype of the new object
      linkobj(bpy.types.Object, optional): link object to attach the visual/collision object to
    (Default value = None)

    Returns:
      bpy.types.Object or None: the new geometry object or nothing

    """
    if 'geometry' not in viscol or viscol['geometry'] is {}:
        log("Could not create {}. Geometry information not defined!".format(geomsrc), 'ERROR')
        return None

    bpy.ops.object.select_all(action='DESELECT')
    geom = viscol['geometry']

    # create the Blender object
    if geom['type'] == 'mesh':
        bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes[geomsrc])
        meshname = "".join(os.path.basename(geom["filename"]).split(".")[:-1])
        if not os.path.isfile(geom['filename']):
            log(
                "This path "
                + geom['filename']
                + " is no file. Object "
                + viscol['name']
                + " will have empty mesh!",
                'ERROR',
            )
            bpy.ops.object.add(type='MESH')
            newgeom = bpy.context.active_object
            nUtils.safelyName(newgeom, viscol['name'], phobostype=geomsrc)
        else:
            if meshname in bpy.data.meshes:
                log('Assigning copy of existing mesh ' + meshname + ' to ' + viscol['name'], 'INFO')
                bpy.ops.object.add(type='MESH')
                newgeom = bpy.context.object
                newgeom.data = bpy.data.meshes[meshname]
            else:
                log("Importing mesh for {0} element: '{1}".format(geomsrc, viscol['name']), 'INFO')
                filetype = geom['filename'].split('.')[-1].lower()
                newgeom = meshes.importMesh(geom['filename'], filetype)
                # bpy.data.meshes[newgeom].name = meshname
                if not newgeom:
                    log('Failed to import mesh file ' + geom['filename'], 'ERROR')
                    return
    else:
        if geom['type'] == 'box':
            dimensions = geom['size']
        elif geom['type'] == 'cylinder':
            dimensions = (geom['radius'], geom['length'])
        elif geom['type'] == 'sphere':
            dimensions = geom['radius']
        # TODO add support for heightmap, image, plane and polyline geometries (see sdf!)
        else:
            log(
                "Unknown geometry type of "
                + geomsrc
                + viscol['name']
                + '. Placing empty coordinate system.',
                "ERROR",
            )
            bpy.ops.object.empty_add(type='PLAIN_AXES', radius=0.2)
            obj = bpy.context.object
            obj.phobostype = geomsrc
            nUtils.safelyName(bpy.context.active_object, viscol['name'], phobostype=geomsrc)
            return None
        log("Creating primtive for {0}: {1}".format(geomsrc, viscol['name']), 'INFO')
        newgeom = bUtils.createPrimitive(
            viscol['name'], geom['type'], dimensions, phobostype=geomsrc
        )
        newgeom.select = True
        bpy.ops.object.transform_apply(scale=True)

    # from here it's the same for both meshes and primitives
    newgeom['geometry/type'] = geom['type']
    if geomsrc == 'visual':
        if 'material' in viscol:
            assignMaterial(newgeom, viscol['material'])
        else:
            log('No material for visual {}.'.format(viscol['name']), 'WARNING')

    # write generic custom properties
    for prop in viscol:
        if prop.startswith('$'):
            for tag in viscol[prop]:
                newgeom[prop[1:] + '/' + tag] = viscol[prop][tag]

    nUtils.safelyName(newgeom, viscol['name'])
    newgeom[geomsrc + '/name'] = viscol['name']
    newgeom.phobostype = geomsrc

    # place geometric object relative to its parent link
    if linkobj:
        if 'pose' in viscol:
            log("Setting transformation of element: " + viscol['name'], 'DEBUG')
            location = mathutils.Matrix.Translation(viscol['pose']['translation'])
            rotation = (
                mathutils.Euler(tuple(viscol['pose']['rotation_euler']), 'XYZ').to_matrix().to_4x4()
            )
        else:
            log("No pose in element: " + viscol['name'], 'DEBUG')
            location = mathutils.Matrix.Identity(4)
            rotation = mathutils.Matrix.Identity(4)
        eUtils.parentObjectsTo(newgeom, linkobj)
        newgeom.matrix_local = location * rotation

    # scale imported object
    if 'scale' in geom:
        newgeom.scale = geom['scale']

    # make object smooth
    eUtils.smoothen_surface(newgeom)

    return newgeom
コード例 #12
0
ファイル: __init__.py プロジェクト: rcg4u/blender2cal3d
	def execute(self, context):
		from . import export_mesh
		from . import export_armature
		from . import export_action
		from .export_armature import create_cal3d_skeleton
		from .export_mesh import create_cal3d_materials
		from .export_mesh import create_cal3d_mesh
		from .export_action import create_cal3d_animation

		cal3d_dirname = os.path.dirname(self.filepath)

		cal3d_skeleton = None
		cal3d_materials = []
		cal3d_meshes = []
		cal3d_animations = []
		armature_obj = None

		# base_translation, base_rotation, and base_scale are user adjustments to the export
		base_translation = mathutils.Vector([0.0, 0.0, 0.0])
		base_rotation = mathutils.Euler([self.base_rotation[0],
		                                 self.base_rotation[1],
		                                 self.base_rotation[2]], 'XYZ').to_matrix()
		base_scale = self.base_scale
		fps = self.fps
		
		#visible_objects = [ob for ob in context.scene.objects if ob.is_visible(context.scene)]
		visible_objects = context.selected_objects
		
		# Export armatures
		try:
			for obj in visible_objects:
				if obj.type == "ARMATURE":
					if cal3d_skeleton:
						raise RuntimeError("Only one armature is supported per scene")
					armature_obj = obj
					cal3d_skeleton = create_cal3d_skeleton(obj, obj.data,
					                                       base_rotation.copy(),
					                                       base_translation.copy(),
					                                       base_scale, 900)
		except Exception as e:
			print("###### ERROR DURING ARMATURE EXPORT ######")
			traceback.print_exc()
			return {"FINISHED"}

		# Export meshes and materials
		try:
			cal3d_materials = create_cal3d_materials(cal3d_dirname, self.imagepath_prefix, 900)

			for obj in visible_objects:
				if obj.type == "MESH" and obj.is_visible(context.scene):
					cal3d_meshes.append(create_cal3d_mesh(context.scene, obj, 
														  cal3d_skeleton,
														  cal3d_materials,
														  base_rotation,
														  base_translation,
														  base_scale, 900,
														  self.use_groups, False, armature_obj))
		except RuntimeError as e:
			print("###### ERROR DURING MESH EXPORT ######")
			print(e)
			return {"FINISHED"}


		# Export animations
		try:
			if cal3d_skeleton:
				for action in bpy.data.actions:
					cal3d_animation = create_cal3d_animation(cal3d_skeleton,
					                                         action, fps, 900)
					if cal3d_animation:
						cal3d_animations.append(cal3d_animation)
						
		except RuntimeError as e:
			print("###### ERROR DURING ACTION EXPORT ######")
			print(e)
			return {"FINISHED"}



		if cal3d_skeleton:
			if self.skeleton_binary_bool == 'binary':
				skeleton_filename = self.skeleton_prefix + cal3d_skeleton.name + ".csf"
				skeleton_filepath = os.path.join(cal3d_dirname, skeleton_filename)
				cal3d_skeleton_file = open(skeleton_filepath, "wb")
				cal3d_skeleton.to_cal3d_binary(cal3d_skeleton_file)
			else:
				skeleton_filename = self.skeleton_prefix + cal3d_skeleton.name + ".xsf"
				skeleton_filepath = os.path.join(cal3d_dirname, skeleton_filename)
				cal3d_skeleton_file = open(skeleton_filepath, "wt")
				cal3d_skeleton_file.write(cal3d_skeleton.to_cal3d_xml())
			cal3d_skeleton_file.close()
			print("Wrote skeleton '%s'" % (skeleton_filename))

		i = 0
		for cal3d_material in cal3d_materials:
			if self.material_binary_bool == 'binary':
				material_filename = self.material_prefix + cal3d_material.name + ".crf"
				material_filepath = os.path.join(cal3d_dirname, material_filename)
				cal3d_material_file = open(material_filepath, "wb")
				cal3d_material.to_cal3d_binary(cal3d_material_file)
			else:
				material_filename = self.material_prefix + cal3d_material.name + ".xrf"
				material_filepath = os.path.join(cal3d_dirname, material_filename)
				cal3d_material_file = open(material_filepath, "wt")
				cal3d_material_file.write(cal3d_material.to_cal3d_xml())
			cal3d_material_file.close()
			print("Wrote material '%s' with index %s" % (material_filename, i))
			i += 1


		for cal3d_mesh in cal3d_meshes:
			if self.mesh_binary_bool == 'binary':
				mesh_filename = self.mesh_prefix + cal3d_mesh.name + ".cmf"
				mesh_filepath = os.path.join(cal3d_dirname, mesh_filename)
				cal3d_mesh_file = open(mesh_filepath, "wb")
				cal3d_mesh.to_cal3d_binary(cal3d_mesh_file)
			else:
				mesh_filename = self.mesh_prefix + cal3d_mesh.name + ".xmf"
				mesh_filepath = os.path.join(cal3d_dirname, mesh_filename)
				cal3d_mesh_file = open(mesh_filepath, "wt")
				cal3d_mesh_file.write(cal3d_mesh.to_cal3d_xml())
			cal3d_mesh_file.close()
			print("Wrote mesh '%s' with materials %s" % (mesh_filename, [x.material_id for x in cal3d_mesh.submeshes]))
			
		for cal3d_animation in cal3d_animations:
			if self.animation_binary_bool == 'binary':
				animation_filename = self.anim_prefix + cal3d_animation.name + ".caf"
				animation_filepath = os.path.join(cal3d_dirname, animation_filename)
				cal3d_animation_file = open(animation_filepath, "wb")
				cal3d_animation.to_cal3d_binary(cal3d_animation_file)
			else:
				animation_filename = self.anim_prefix + cal3d_animation.name + ".xaf"
				animation_filepath = os.path.join(cal3d_dirname, animation_filename)
				cal3d_animation_file = open(animation_filepath, "wt")
				cal3d_animation_file.write(cal3d_animation.to_cal3d_xml())
			cal3d_animation_file.close()
			print("Wrote animation '%s'" % (animation_filename))


		if self.export_cfg:
			cal3d_cfg_file = open(self.filepath, "wt")

			# lolwut?
			#cal3d_cfg_file.write("path={0}\n".format("data\\models\\" + os.path.basename(self.filepath[:-4])+ "\\"))
			#cal3d_cfg_file.write("scale=0.01f\n")
			
			if cal3d_skeleton:
				if self.skeleton_binary_bool == 'binary':
					skeleton_filename = self.skeleton_prefix + cal3d_skeleton.name + ".csf"
				else:
					skeleton_filename = self.skeleton_prefix + cal3d_skeleton.name + ".xsf"
				cal3d_cfg_file.write("skeleton={0}\n".format(skeleton_filename))

			for cal3d_animation in cal3d_animations:
				if self.animation_binary_bool == 'binary':
					animation_filename = self.anim_prefix + cal3d_animation.name + ".caf"
				else:
					animation_filename = self.anim_prefix + cal3d_animation.name + ".xaf"
				cal3d_cfg_file.write("animation={0}\n".format(animation_filename))

			for cal3d_material in cal3d_materials:
				if self.material_binary_bool == 'binary':
					material_filename = self.material_prefix + cal3d_material.name + ".crf"
				else:
					material_filename = self.material_prefix + cal3d_material.name + ".xrf"
				cal3d_cfg_file.write("material={0}\n".format(material_filename))

			for cal3d_mesh in cal3d_meshes:
				if self.mesh_binary_bool == 'binary':
					mesh_filename = self.mesh_prefix + cal3d_mesh.name + ".cmf"
				else:
					mesh_filename = self.mesh_prefix + cal3d_mesh.name + ".xmf"
				cal3d_cfg_file.write("mesh={0}\n".format(mesh_filename))

			cal3d_cfg_file.close()

		return {"FINISHED"}
    def configMovement(self, P, A, J, a, b, y, o):

        a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
        print("a1 =", a[1])

        a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
        print("a2 =", a[2])

        b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
        print("b1 =", b[1])

        o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
        print("o1 =", o[1])

        B = A * 2 * sqrt(2)
        C = B + (B * sqrt(2))
        D = C * sqrt(2)
        E = C + D

        y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
        print("y1 =", y[1])

        b[2] = mathutils.Euler(((9.4 / 0.6) * A, (-8.2 / 0.6) * A, 0.0), 'XYZ')
        print("b2 =", b[2])

        b[3] = mathutils.Euler(
            ((7.399085 / 0.6) * A, (-19.717056 / 0.6) * A, 0.0), 'XYZ')
        print("b3 =", b[3])

        y[2] = mathutils.Euler(((8.2 / 0.6) * A, (-9.4 / 0.6) * A, 0.0), 'XYZ')
        print("y2 =", y[2])

        y[3] = mathutils.Euler(
            ((9.08969 / 0.6) * A, (-19.569149 / 0.6) * A, 0.0), 'XYZ')
        print("y3 =", y[3])

        y[4] = mathutils.Euler(
            ((9.2376 / 0.6) * A, (-21.259787 / 0.6) * A, 0.0), 'XYZ')
        print("y4 =", y[4])

        o[2] = mathutils.Euler(
            ((6.509395 / 0.6) * A, (-9.547907 / 0.6) * A, 0.0), 'XYZ')
        print("o2 =", o[2])

        o[3] = mathutils.Euler(
            ((10.38971 / 0.6) * A, (-20.659994 / 0.6) * A, 0.0), 'XYZ')
        print("o3 =", o[3])
コード例 #14
0
    def run(self):
        """ Performs physics simulation in the scene. """
        # locations of all soon to be active objects before we shift their origin points
        locations_before_origin_shift = {}
        for obj in get_all_mesh_objects():
            if obj["physics"]:
                locations_before_origin_shift.update(
                    {obj.name: obj.location.copy()})
        # enable rigid body and shift origin point for active objects
        locations_after_origin_shift = self._add_rigidbody()
        # compute origin point shift for all active objects
        origin_shift = {}
        for obj in locations_after_origin_shift:
            shift = locations_before_origin_shift[
                obj] - locations_after_origin_shift[obj]
            origin_shift.update({obj: shift})

        bpy.context.scene.rigidbody_world.steps_per_second = self.steps_per_sec
        bpy.context.scene.rigidbody_world.solver_iterations = self.solver_iters

        obj_poses_before_sim = self._get_pose()
        # perform simulation
        obj_poses_after_sim = self._do_simulation()
        # reset origin point of all active objects to the total shift location of the 3D cursor
        for obj in get_all_mesh_objects():
            if obj.rigid_body.type == "ACTIVE":
                bpy.context.view_layer.objects.active = obj
                obj.select_set(True)
                # compute relative object rotation before and after simulation
                R_obj_before_sim = mathutils.Euler(
                    obj_poses_before_sim[obj.name]['rotation']).to_matrix()
                R_obj_after = mathutils.Euler(
                    obj_poses_after_sim[obj.name]['rotation']).to_matrix()
                R_obj_rel = R_obj_before_sim @ R_obj_after.transposed()
                # compute origin shift in object coordinates
                origin_shift[
                    obj.name] = R_obj_rel.transposed() @ origin_shift[obj.name]
                # set 3d cursor location to the total shift of the object
                bpy.context.scene.cursor.location = origin_shift[
                    obj.name] + obj_poses_after_sim[obj.name]['location']
                bpy.ops.object.origin_set(type='ORIGIN_CURSOR',
                                          center='MEDIAN')
                obj.select_set(False)

        # reset 3D cursor location
        bpy.context.scene.cursor.location = mathutils.Vector([0, 0, 0])

        # get current poses
        curr_pose = self._get_pose()
        # displace for the origin shift
        final_poses = {}
        for obj in curr_pose:
            final_poses.update({
                obj: {
                    'location': curr_pose[obj]['location'] + origin_shift[obj],
                    'rotation': curr_pose[obj]['rotation']
                }
            })
        self._set_pose(final_poses)

        self._remove_rigidbody()
コード例 #15
0
def Set_Rotation_Curves(action, mode_from, mode_to, remove, selection,
                        object_curves):
    # copy the action so we can remove curves and re-add them...
    action_copy = action.copy()
    # these two bool conditions would be annoying to keep calling on...
    is_from_euler = True if mode_from in [
        'XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'
    ] else False
    is_to_euler = True if mode_to in [
        'XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'
    ] else False
    # get the strings we need for the to and from data paths...
    rot_path_to = "rotation_quaternion" if mode_to == 'QUATERNION' else "rotation_axis_angle" if mode_to == 'AXIS_ANGLE' else "rotation_euler"
    rot_path_from = "rotation_quaternion" if mode_from == 'QUATERNION' else "rotation_axis_angle" if mode_from == 'AXIS_ANGLE' else "rotation_euler"
    # get the original rotation fcurves...
    rot_curves = Get_Rotation_Curves(action, rot_path_from, selection,
                                     object_curves)
    # then we want to operate on the copy...
    rot_curves_copy = Get_Rotation_Curves(action_copy, rot_path_from,
                                          selection, object_curves)
    rot_curves_from = rot_curves_copy[rot_path_from]
    # iterate over data path and channel index dictionary...
    for d_path, indices in rot_curves_from.items():
        # if the data_path is the one we wish to change from...
        if d_path.endswith(rot_path_from):
            # get the base path without rotation string...
            b_path = d_path[:-19] if mode_from in ['QUATERNION', 'AXIS_ANGLE'
                                                   ] else d_path[:-14]
            # if we are coming from eulers to quat/axis angle...
            if (is_from_euler and not is_to_euler):
                # and there is already a w curve...
                if (b_path + rot_path_to in rot_curves[rot_path_to] and 0
                        in rot_curves[rot_path_to][b_path + rot_path_to]):
                    # remove it...
                    action.fcurves.remove(
                        rot_curves[rot_path_to][b_path +
                                                rot_path_to][new_index])
                # add a w curve...
                w_curve = action.fcurves.new(
                    data_path=b_path + rot_path_to,
                    index=0,
                    action_group=b_path.partition('"')[2].split('"')[0])
            # iterate over the index and channel dictionary...
            for index, fcurve in indices.items():
                if not (index == 0 and (is_to_euler and not is_from_euler)):
                    # new index is subtracted by 1 if we are switching to euler from quat/axis angle and + 1 if we are switching to quat/axis angle from euler...
                    new_index = index + (
                        -1 if (is_to_euler and not is_from_euler) else 1 if
                        (is_from_euler and not is_to_euler) else 0)
                    # if the new curve already exists...
                    if b_path + rot_path_to in rot_curves[
                            rot_path_to] and new_index in rot_curves[
                                rot_path_to][b_path + rot_path_to]:
                        # remove it...
                        action.fcurves.remove(
                            rot_curves[rot_path_to][b_path +
                                                    rot_path_to][new_index])
                    # add the new curve by adding the the base data path to the desired data path...
                    if fcurve.group:
                        new_curve = action.fcurves.new(
                            data_path=b_path + rot_path_to,
                            index=new_index,
                            action_group=fcurve.group.name)
                    else:
                        new_curve = action.fcurves.new(data_path=b_path +
                                                       rot_path_to,
                                                       index=new_index)
                    new_curve.auto_smoothing = fcurve.auto_smoothing
                    new_curve.extrapolation = fcurve.extrapolation
                    # for each keyframe in the fcurve...
                    for key in fcurve.keyframe_points:
                        # get the rotation as evaluated floats from the curves of the same data path...
                        w = rot_curves_from[d_path][0].evaluate(key.co[0])
                        x = rot_curves_from[d_path][1].evaluate(
                            key.co[0]
                        ) if not is_from_euler else rot_curves_from[d_path][
                            0].evaluate(key.co[0])
                        y = rot_curves_from[d_path][2].evaluate(
                            key.co[0]
                        ) if not is_from_euler else rot_curves_from[d_path][
                            1].evaluate(key.co[0])
                        z = rot_curves_from[d_path][3].evaluate(
                            key.co[0]
                        ) if not is_from_euler else rot_curves_from[d_path][
                            2].evaluate(key.co[0])
                        # create a quaternion from the evaluated floats...
                        quat = (
                            mathutils.Quaternion(
                                (w, x, y, z)) if mode_from == 'QUATERNION' else
                            # axis angle wants to be a quaternion created a little different...
                            mathutils.Quaternion(
                                (x, y, z), w) if mode_from == 'AXIS_ANGLE' else
                            # euler wants to be converted to quaternion...
                            mathutils.Euler(
                                (x, y, z), mode_from).to_quaternion())
                        # set that rotation to what we want it to be...
                        new_rot = (
                            quat if mode_to == 'QUATERNION' else
                            # rotation needs to be unpacked for axis angle...
                            [
                                quat.to_axis_angle()[1],
                                quat.to_axis_angle()[0][0],
                                quat.to_axis_angle()[0][1],
                                quat.to_axis_angle()[0][2]
                            ] if mode_to == 'AXIS_ANGLE' else
                            # rotation needs converting for euler...
                            quat.to_euler(mode_to))
                        # add a new key in the same place...
                        new_key = new_curve.keyframe_points.insert(
                            key.co[0],
                            new_rot[new_index],
                            keyframe_type='KEYFRAME')
                        # set that keyframes curve coordinates and settings...
                        new_key.co[0] = key.co[0]
                        new_key.co[1] = new_rot[new_index]
                        new_key.handle_left_type = key.handle_left_type
                        new_key.handle_right_type = key.handle_right_type
                        # custom curve handles will be close approximations until i can figured out a better way to calculate them...
                        new_key.handle_left[0] = key.handle_left[0]
                        new_key.handle_left[1] = new_key.co[1] * (
                            key.handle_left[1] /
                            (key.co[1] + (1 if key.co[1] == 0 else 0)))
                        new_key.handle_right[0] = key.handle_right[0]
                        new_key.handle_right[1] = new_key.co[1] * (
                            key.handle_right[1] /
                            (key.co[1] + (1 if key.co[1] == 0 else 0)))
                        # and the rest of the keyframe settings...
                        new_key.interpolation = key.interpolation
                        new_key.period = key.period
                        new_key.easing = key.easing
                        new_key.amplitude = key.amplitude
                        new_key.back = key.back
                        if key.type in [
                                'KEYFRAME', 'BREAKDOWN', 'MOVING_HOLD',
                                'EXTREME', 'JITTER'
                        ]:
                            new_key.type = key.type
                        # if we came from eulers...
                        if (is_from_euler and not is_to_euler):
                            if w_curve != None:
                                # we need to key w everytime any channel is keyed... (unable to support interpolation and custom handles on a curve that doesn't exist)
                                w_key = w_curve.keyframe_points.insert(
                                    key.co[0],
                                    new_rot[0],
                                    keyframe_type='KEYFRAME')
                                w_key.co[1] = new_rot[0]
                                w_key.handle_left[1] = new_rot[0]
                                w_key.handle_right[1] = new_rot[0]
            # if we want to remove the old fcurves...
            if remove and not (is_from_euler and is_to_euler):
                for fcurve in [
                        fc for fc in action.fcurves if fc.data_path == d_path
                ]:
                    action.fcurves.remove(fcurve)
    # get rid of the copy we operated on...
    bpy.data.actions.remove(action_copy)
コード例 #16
0
    def configMovement(self, P, A, J, a, b, y, o):

        a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
        print("a1 =", a[1])

        a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
        print("a2 =", a[2])

        b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
        print("b1 =", b[1])

        o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
        print("o1 =", o[1])

        B = A * 2 * sqrt(2)
        C = B + (B * sqrt(2))
        D = C * sqrt(2)
        E = C + D

        y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
        print("y1 =", y[1])

        b[2] = mathutils.Euler(((4.08 / 0.7) * A, (-2.68 / 0.7) * A, 0.0),
                               'XYZ')
        print("b2 =", b[2])

        b[3] = mathutils.Euler(
            ((2.520382 / 0.7) * A, (-7.734981 / 0.7) * A, 0.0), 'XYZ')
        print("b3 =", b[3])

        b[4] = mathutils.Euler(
            ((4.650852 / 0.7) * A, (-10.086805 / 0.7) * A, 0.0), 'XYZ')
        print("b4 =", b[4])

        y[2] = mathutils.Euler(((2.68 / 0.7) * A, (-4.08 / 0.7) * A, 0.0),
                               'XYZ')
        print("y2 =", y[2])

        y[3] = mathutils.Euler(
            ((4.314873 / 0.7) * A, (-8.571764 / 0.7) * A, 0.0), 'XYZ')
        print("y3 =", y[3])

        y[4] = mathutils.Euler(
            ((4.065916 / 0.7) * A, (-9.98368 / 0.7) * A, 0.0), 'XYZ')
        print("y4 =", y[4])

        y[5] = mathutils.Euler(
            ((3.816914 / 0.7) * A, (-11.395846 / 0.7) * A, 0.0), 'XYZ')
        print("y5 =", y[5])

        o[2] = mathutils.Euler(
            ((4.5405 / 0.7) * A, (-3.402836 / 0.7) * A, 0.0), 'XYZ')
        print("o2 =", o[2])

        o[3] = mathutils.Euler(
            ((4.899491 / 0.7) * A, (-8.674883 / 0.7) * A, 0.0), 'XYZ')
        print("o3 =", o[3])

        o[4] = b[4]
        print("o4 =", o[4])
コード例 #17
0
def pmx_euler2quat(eular: XMLRotate) -> Math.Vector:
    radian = (radians(eular.x), radians(eular.y), radians(eular.z))
    rotate_euler = Math.Euler(radian, "ZXY")
    rotate_quat = rotate_euler.to_quaternion()
    return Math.Vector(
        (rotate_quat.x, rotate_quat.y, rotate_quat.z, rotate_quat.w))
コード例 #18
0
def render_scene(args,
                 num_objects=5,
                 output_index=0,
                 output_split='none',
                 output_image='render.png',
                 output_scene='render_json',
                 output_blendfile=None,
                 img_template='image%d.png'):

    bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile)

    # Load materials
    utils.load_materials(args.material_dir)

    # node_path = '/home/bozidar/uni/prac/repos/clevr-dataset-gen/image_generation/data/NodeGroupMulti4.blend'
    node_path = '/home/bozidar/uni/prac/repos/clevr-dataset-gen/image_generation/data/NodeGroup.blend'
    with bpy.data.libraries.load(node_path) as (data_from, data_to):
        data_to.objects = data_from.objects
        data_to.materials = data_from.materials
        data_to.node_groups = data_from.node_groups
    node_mat = data_to.materials[0]
    node_group_elems = data_to.node_groups[0].nodes[
        "ColorRamp"].color_ramp.elements
    # for i in segm_colors:
    #   print(list(i.color))

    # Set render arguments so we can get pixel coordinates later.
    # We use functionality specific to the CYCLES renderer so BLENDER_RENDER
    # cannot be used.
    render_args = bpy.context.scene.render
    render_args.engine = "CYCLES"
    render_args.filepath = output_image
    render_args.resolution_x = args.width
    render_args.resolution_y = args.height
    render_args.resolution_percentage = 100
    render_args.tile_x = args.render_tile_size
    render_args.tile_y = args.render_tile_size
    if args.use_gpu == 1:
        # Blender changed the API for enabling CUDA at some point
        if bpy.app.version < (2, 78, 0):
            bpy.context.user_preferences.system.compute_device_type = 'CUDA'
            bpy.context.user_preferences.system.compute_device = 'CUDA_0'
        else:
            cycles_prefs = bpy.context.user_preferences.addons[
                'cycles'].preferences
            cycles_prefs.compute_device_type = 'CUDA'

    # Some CYCLES-specific stuff
    bpy.data.worlds['World'].cycles.sample_as_light = True
    bpy.context.scene.cycles.blur_glossy = 2.0
    bpy.context.scene.cycles.samples = args.render_num_samples
    bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces
    bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces
    if args.use_gpu == 1:
        bpy.context.scene.cycles.device = 'GPU'

    # This will give ground-truth information about the scene and its objects
    scene_struct = {
        'split': output_split,
        'image_index': output_index,
        'image_filename': os.path.basename(output_image),
        'objects': [],
        'directions': {},
    }

    # Put a plane on the ground so we can compute cardinal directions
    if bpy.app.version < (2, 80, 0):
        bpy.ops.mesh.primitive_plane_add(radius=5)
    else:
        bpy.ops.mesh.primitive_plane_add(size=5)
    plane = bpy.context.object

    def rand(L):
        return 2.0 * L * (random.random() - 0.5)

    # Add random jitter to camera position
    if args.camera_jitter > 0:
        for i in range(3):
            bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter)

    # Figure out the left, up, and behind directions along the plane and record
    # them in the scene structure
    camera = bpy.data.objects['Camera']
    plane_normal = plane.data.vertices[0].normal
    if bpy.app.version < (2, 80, 0):
        cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1))
        cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0))
        cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0))
    else:
        cam_behind = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1))
        cam_left = camera.matrix_world.to_quaternion() @ Vector((-1, 0, 0))
        cam_up = camera.matrix_world.to_quaternion() @ Vector((0, 1, 0))
    plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized()
    plane_left = (cam_left - cam_left.project(plane_normal)).normalized()
    plane_up = cam_up.project(plane_normal).normalized()

    # Delete the plane; we only used it for normals anyway. The base scene file
    # contains the actual ground plane.
    utils.delete_object(plane)

    # Save all six axis-aligned directions in the scene struct
    scene_struct['directions']['behind'] = tuple(plane_behind)
    scene_struct['directions']['front'] = tuple(-plane_behind)
    scene_struct['directions']['left'] = tuple(plane_left)
    scene_struct['directions']['right'] = tuple(-plane_left)
    scene_struct['directions']['above'] = tuple(plane_up)
    scene_struct['directions']['below'] = tuple(-plane_up)

    # Add random jitter to lamp positions
    if args.key_light_jitter > 0:
        for i in range(3):
            bpy.data.objects['Lamp_Key'].location[i] += rand(
                args.key_light_jitter)
    if args.back_light_jitter > 0:
        for i in range(3):
            bpy.data.objects['Lamp_Back'].location[i] += rand(
                args.back_light_jitter)
    if args.fill_light_jitter > 0:
        for i in range(3):
            bpy.data.objects['Lamp_Fill'].location[i] += rand(
                args.fill_light_jitter)

    # Now make some random objects
    objects, blender_objects = add_random_objects(scene_struct, num_objects,
                                                  args, camera)

    # Segmentation materials and colors
    n = len(objects)
    node_mat.node_tree.nodes['Group'].inputs[1].default_value = n
    segm_mat = []
    segm_color = []
    for i in range(n + 1):
        node_mat.node_tree.nodes['Group'].inputs[0].default_value = i
        segm_mat.append(node_mat.copy())
        segm_color.append(list(node_group_elems[i].color))
    print(segm_mat)
    print(segm_color)

    angles = [-50, 90]
    steps = 5
    for i, a in enumerate(np.linspace(*angles, steps)):
        # position = bpy.data.objects['Lamp_Key'].location
        # r = R.from_euler(axis, a, degrees=True).as_matrix()
        r = mathutils.Euler((0.0, math.radians(a), 0.0), 'XYZ')
        # r = mathutils.Euler((math.radians(30), math.radians(a), 0.0), 'XYZ')
        # bpy.data.objects['Lamp_Back'].location.rotate(r)
        # bpy.data.objects['Area'].location.rotate(r)
        bpy.data.objects['Area'].rotation_euler = r

        scene_struct['image_index'] = output_index * steps + i
        render_args.filepath = img_template % (output_index * steps + i)

        # bpy.data.objects['Sphere_0'].select = True
        # obj = bpy.context.selected_objects
        # for obj in bpy.context.selected_objects:
        # obj.select = False
        # bpy.context.scene.objects.active = None
        # bpy.context.scene.objects.active = bpy.data.objects['Ground']

        print('---------------------------')
        print(objects)
        print('---------------------------')
        print(bpy.data.objects.items())
        print('---------------------------')

        # exit()

        # Render the scene and dump the scene data structure
        scene_struct['objects'] = objects
        scene_struct['relationships'] = compute_all_relationships(scene_struct)
        while True:
            try:
                bpy.ops.render.render(write_still=True)
                break
            except Exception as e:
                print(e)

        with open(output_scene, 'w') as f:
            json.dump(scene_struct, f, indent=2)

        if output_blendfile is not None:
            print('===============================>', output_blendfile)
            bpy.ops.wm.save_as_mainfile(filepath=output_blendfile)

        # segm rendering
        s = render_args.filepath
        ind = s.rindex('.')
        render_args.filepath = s[:ind] + '_segm' + s[ind:]

        prev_mat = []

        bpy.data.objects['Ground'].data.materials.clear()
        bpy.data.objects['Ground'].data.materials.append(segm_mat[0])
        for i in range(n):
            prev_mat.append(bpy.data.objects[i - n].data.materials[0])
            scene_name = bpy.data.objects[i - n].name
            index = -1
            for obj in objects:
                if obj['scene_name'] == scene_name:
                    index = obj['index']
                    obj['segm_color'] = segm_color[obj['index'] + 1]

            bpy.data.objects[i - n].data.materials.clear()
            bpy.data.objects[i - n].data.materials.append(segm_mat[index + 1])

        while True:
            try:
                bpy.ops.render.render(write_still=True)
                break
            except Exception as e:
                print(e)

        bpy.data.objects['Ground'].data.materials.clear()
        for i in range(n):
            bpy.data.objects[i - n].data.materials.clear()
            bpy.data.objects[i - n].data.materials.append(prev_mat[i])
コード例 #19
0
def lanes_generate(ops, left_lanes, right_lanes, road_width, offset, invert):
    bpy.ops.object.mode_set(mode='EDIT')
    me = bpy.context.edit_object.data
    bm = bmesh.from_edit_mesh(me)

    edges = [e for e in bm.edges if e.select and not e.hide]

    lines = get_lines(edges)
    if len(lines) != 1:
        ops.report({"WARNING"}, "1つの線になるように辺を選択して下さい")
        return False

    vs = get_sorted_verts(lines[0])
    if invert:
        vs.reverse()

    vs_n = []

    rot_l = mathutils.Euler((0.0, 0.0, math.radians(90.0)), 'XYZ')
    rot_r = mathutils.Euler((0.0, 0.0, math.radians(-90.0)), 'XYZ')

    rot_c = None
    for n, v in enumerate(vs):
        v.select = False
        vb = None
        vf = None
        if n != 0:
            vb = vs[n - 1]
        if n != len(vs) - 1:
            vf = vs[n + 1]

        co_bn = None
        co_fn = None
        if vb != None:
            rot_b = (v.co - vb.co)
            rot_b.z = 0.0
            rot_b.normalize()
            co_bn = mathutils.Vector(rot_b)
            co_bn.rotate(rot_l)
            co_bn *= road_width / 2
        if vf != None:
            rot_f = (vf.co - v.co)
            rot_f.z = 0.0
            rot_f.normalize()
            co_fn = mathutils.Vector(rot_f)
            co_fn.rotate(rot_l)
            co_fn *= road_width / 2

        if n == 0:
            vs_n = vs_n + [v.co + co_fn]
        elif n == len(vs) - 1:
            vs_n = vs_n + [v.co + co_bn]
        else:
            vc = get_cross_point(vb.co + co_bn, v.co + co_bn, vf.co + co_fn,
                                 v.co + co_fn, False)
            vc.z = v.co.z
            vs_n = vs_n + [vc]

    vb = None

    for v in zip(vs_n):
        nv = bm.verts.new(v)

        if vb != None:
            bm.edges.new([vb, nv]).select = True

        vb = nv

    bmesh.update_edit_mesh(me)
    return True
コード例 #20
0
for f in range(0, s_end + 1):
    px = camdata["cameraFrames"][f]["position"]["x"]
    py = camdata["cameraFrames"][f]["position"]["y"]
    pz = camdata["cameraFrames"][f]["position"]["z"]

    rx = float(camdata["cameraFrames"][f]["rotation"]["x"])
    ry = camdata["cameraFrames"][f]["rotation"]["y"]
    rz = camdata["cameraFrames"][f]["rotation"]["z"]

    # position set in relation to first frame - scale to 1/100
    cam.location.x = (px - psx) / 100
    cam.location.y = (py - psy) / 100
    cam.location.z = (pz - psz) / 100

    eul = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')

    eul.rotate_axis('X', math.radians(-rx))
    eul.rotate_axis('Y', math.radians(ry))
    eul.rotate_axis('Z', math.radians(-rz + 180))

    cam.rotation_euler = eul

    cam.keyframe_insert(data_path="location", index=-1, frame=f + 1)
    cam.keyframe_insert(data_path="rotation_euler", index=-1, frame=f + 1)

cam.data.type = 'PERSP'
cam.data.lens_unit = 'FOV'

# camera "lens" based on json
for f in range(0, s_end + 1):
コード例 #21
0
 def __xyzw_from_euler(xyzw):
     q = mathutils.Euler(xyzw[:3], xyzw[3]).to_quaternion()
     return [q.x, q.y, q.z, q.w]
コード例 #22
0
def load(operator, context, files=[], filepath="", set_fps=False):
    starttime = time.clock()
    dirname, filename = os.path.split(filepath)
    data = load_bani(filepath)

    # data 0 has various scales and counts
    anim_length = data.header.data_0.animation_length
    num_frames = data.header.data_0.num_frames

    global_corr_euler = mathutils.Euler(
        [math.radians(k) for k in (0, -90, -90)])
    global_corr_mat = global_corr_euler.to_matrix().to_4x4()

    fps = int(round(num_frames / anim_length))
    bpy.context.scene.frame_start = 0
    bpy.context.scene.frame_end = num_frames - 1
    print("Banis fps", fps)
    ob = get_armature()

    bones_table = [(bone["index"], bone.name) for bone in ob.pose.bones]
    bone_names = [tup[1] for tup in sorted(bones_table)]

    # ns = ("def_rearLegUpr_joint.L", "def_rearLegUprHalfTwist_joint.L", "def_rearLegUprAllTwist_joint.L",
    # 	  "def_rearLegLwr_joint.L", "def_rearLegLwrHalfTwist_joint.L", "def_rearLegLwrAllTwist_joint.L")
    # # ns = ("def_c_neck_joint", "def_c_head_joint", "def_wing_joint.L", "def_wing02_joint.L", "def_wing_joint.R", "def_wing02_joint.R")
    # # ns = ("def_rearHorselink_joint.L", "def_rearFoot_joint.L", "def_toeRearRing1_joint.L", "def_toeRearRing2_joint.L", "def_toeRearRing3_joint.L",
    # # 	  "def_rearHorselink_joint.R", "def_rearFoot_joint.R", "def_toeRearRing1_joint.R", "def_toeRearRing2_joint.R", "def_toeRearRing3_joint.R")
    #
    # # a rotation is not relative to the parent, but relative to the rest pose
    #
    # for n in ns:
    # 	i = bone_names.index(n)
    # 	euler = data.eulers[0, i]
    # 	# loc = data.locs[:, i]
    # 	loc = data.locs[0, i]
    # 	print(n, "euler", euler)
    # 	print(n, "locat", loc)
    # return
    # bone_names = ovl_bones(ob.data)
    # goliath imports fine with the correct name order
    # bone_names = ['def_c_root_joint', 'def_c_hips_joint', 'def_c_spine1_joint', 'def_c_spine2_joint', 'def_c_chestBreath_joint', 'def_c_spine3_joint', 'def_c_chest_joint', 'def_c_neck1_joint', 'def_c_head_joint', 'def_c_jaw_joint', 'def_l_clavicle_joint', 'def_l_frontLegUpr_joint', 'def_l_frontLegLwr_joint', 'def_l_frontFoot_joint', 'def_l_toeFrontIndex1_joint', 'def_l_toeFrontIndex2_joint', 'def_l_toeFrontPinky1_joint', 'def_l_toeFrontPinky2_joint', 'def_l_toeFrontPinky3_joint', 'def_l_toeFrontRing1_joint', 'def_l_toeFrontRing2_joint', 'def_l_toeFrontRing3_joint', 'def_l_frontLegLwrAllTwist_joint', 'def_l_frontLegLwrHalfTwist_joint', 'def_l_frontLegUprAllTwist_joint', 'def_r_clavicle_joint', 'def_r_frontLegUpr_joint', 'def_r_frontLegLwr_joint', 'def_r_frontFoot_joint', 'def_r_toeFrontIndex1_joint', 'def_r_toeFrontIndex2_joint', 'def_r_toeFrontPinky1_joint', 'def_r_toeFrontPinky2_joint', 'def_r_toeFrontPinky3_joint', 'def_r_toeFrontRing1_joint', 'def_r_toeFrontRing2_joint', 'def_r_toeFrontRing3_joint', 'def_r_frontLegLwrAllTwist_joint', 'def_r_frontLegLwrHalfTwist_joint', 'def_r_frontLegUprAllTwist_joint', 'def_l_rearLegUpr_joint', 'def_l_rearLegLwr_joint', 'def_l_rearHorselink_joint', 'def_l_rearFoot_joint', 'def_l_toeRearMid1_joint', 'def_l_toeRearMid2_joint', 'def_l_toeRearMid3_joint', 'def_l_toeRearPinky1_joint', 'def_l_toeRearPinky2_joint', 'def_l_toeRearPinky3_joint', 'def_l_toeRearRing1_joint', 'def_l_toeRearRing2_joint', 'def_l_toeRearRing3_joint', 'def_l_toeRearThumb1_joint', 'def_l_toeRearThumb2_joint', 'def_l_toeRearThumb3_joint', 'def_l_rearLegLwrAllTwist_joint', 'def_l_rearLegLwrHalfTwist_joint', 'def_l_rearLegUprAllTwist_joint', 'def_r_rearLegUpr_joint', 'def_r_rearLegLwr_joint', 'def_r_rearHorselink_joint', 'def_r_rearFoot_joint', 'def_r_toeRearMid1_joint', 'def_r_toeRearMid2_joint', 'def_r_toeRearMid3_joint', 'def_r_toeRearPinky1_joint', 'def_r_toeRearPinky2_joint', 'def_r_toeRearPinky3_joint', 'def_r_toeRearRing1_joint', 'def_r_toeRearRing2_joint', 'def_r_toeRearRing3_joint', 'def_r_toeRearThumb1_joint', 'def_r_toeRearThumb2_joint', 'def_r_toeRearThumb3_joint', 'def_r_rearLegLwrAllTwist_joint', 'def_r_rearLegLwrHalfTwist_joint', 'def_r_rearLegUprAllTwist_joint', 'def_c_throat_joint', 'def_l_eyelidUpr_joint', 'def_r_eyelidUpr_joint', 'def_l_toeFrontIndex3_joint', 'def_l_toeFrontThumb1_joint', 'def_l_toeFrontThumb2_joint', 'def_l_toeFrontThumb3_joint', 'def_l_frontLegUprHalfTwist_joint', 'def_r_toeFrontIndex3_joint', 'def_r_toeFrontThumb1_joint', 'def_r_toeFrontThumb2_joint', 'def_r_toeFrontThumb3_joint', 'def_r_frontLegUprHalfTwist_joint', 'def_l_chestBreath_joint', 'def_r_chestBreath_joint', 'def_l_toeRearIndex1_joint', 'def_l_toeRearIndex2_joint', 'def_l_toeRearIndex3_joint', 'def_l_rearLegUprHalfTwist_joint', 'def_r_toeRearIndex1_joint', 'def_r_toeRearIndex2_joint', 'def_r_toeRearIndex3_joint', 'def_r_rearLegUprHalfTwist_joint', 'rig_l_frontToe_joint', 'rig_r_frontToe_joint', 'rig_l_rearToe_joint', 'rig_r_rearToe_joint', 'srb']
    # print(bone_names)
    # print(len(bone_names), len(data.bones_frames_eulers), len(data.bones_frames_locs))
    # assert( len(bone_names) == len(data.bones_frames_eulers) == len(data.bones_frames_locs) )
    action = create_anim(ob, filename)
    # go over list of euler keys

    for i, bone_name in enumerate(bone_names):
        # print(i, bone_name)

        # bone_keys = data.eulers_dict[bone_name]
        # bone_name = bone_name.decode()
        # get pose pbone
        pbone = ob.pose.bones[bone_name]
        pbone.rotation_mode = "XYZ"
        # get object mode bone
        obone = ob.data.bones[bone_name]
        armature_space_matrix = obone.matrix_local
        for frame_i in range(data.header.data_0.num_frames):
            bpy.context.scene.frame_set(frame_i)
            euler = data.eulers[frame_i, i]
            loc = data.locs[frame_i, i]
            # create fcurves
            data_type = "rotation_euler"
            # fcu = [action.fcurves.new(data_path = 'pose.bones["'+bone_name+'"].'+data_type, index = i, action_group = bone_name) for i in (0,1,2)]

            # for fcurve, k in zip(fcu, key):
            # fcurve.keyframe_points.insert(frame_i, math.radians(k))#.interpolation = "Linear"
            euler = mathutils.Euler([math.radians(k) for k in euler])
            # experiments
            # trans = (global_corr_mat @ mathutils.Vector(loc)) + armature_space_matrix.translation

            # mdl2 vectors: (-x,-z,y)
            # loc = mathutils.Vector((-loc[0], -loc[2], loc[1]))
            loc = mathutils.Vector(loc)
            # trans = (mathutils.Vector(loc)) + armature_space_matrix.translation

            # the eulers are applied globally to the bone, equivalent to the user doing R+X, R+Y, R+Z for each axis.
            # this expresses the rotation that should be done in blender coordinates about the center of the bone
            space_corrected_rot = global_corr_mat @ euler.to_matrix().to_4x4()

            # rot_mat is the final armature space matrix of the posed bone
            rot_mat = space_corrected_rot @ armature_space_matrix

            # rot_mat.translation = (space_corrected_rot @ loc) + armature_space_matrix.translation
            # loc_key = (space_corrected_rot @ mathutils.Vector(loc))
            loc_key = (euler.to_matrix().to_4x4() @ loc)
            # loc_key = ( loc @ space_corrected_rot)
            # loc_key = mathutils.Vector((-loc_key[0], -loc_key[2], loc_key[1]))
            # rot_mat.translation = loc_key + armature_space_matrix.translation
            # the ideal translation as calculated by blender
            rot_mat.translation = pbone.matrix.translation
            # print(rot_mat)
            pbone.matrix = rot_mat

            pbone.keyframe_insert(data_path="rotation_euler",
                                  frame=frame_i,
                                  group=bone_name)
            pbone.keyframe_insert(data_path="location",
                                  frame=frame_i,
                                  group=bone_name)
    return {'FINISHED'}
コード例 #23
0
    def constructLink(self, A, J, helicity, rig, move, part):

        # Move and rotate the tip bone in pose mode
        bpy.context.view_layer.objects.active = rig 

        Y = 1.1838*A

        for n in rig.pose.bones:
            if n.name != "o" + str(J-2) + "b" + str(J-1):
                # we can get the object from the pose bone
                obj = n.id_data
                matrix_final = obj.matrix_world @ n.matrix

                # Create armature and object
                lnk = bpy.data.armatures.new(n.name[:len(n.name)]+'.data.' + helicity)
                lnk_rig = bpy.data.objects.new(n.name[:len(n.name)]+'.link.' + helicity, lnk)
                lnk_rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')

                # rig.show_in_front = True
                lnk.show_names = True
                lnk.display_type = 'STICK'

                bpy.data.collections['link'].objects.link(lnk_rig)
                bpy.context.view_layer.objects.active = lnk_rig
                bpy.context.view_layer.update()

                # Create bones

                # mode='EDIT'
                bpy.ops.object.editmode_toggle()
    
                link = lnk.edit_bones.new(n.name[:len(n.name)])
                link.head = (0.0, 0.0, 0.0)
                link.tail = (0.0, Y, 0.0)

                link_head = lnk.edit_bones.new('head')
                link_head.head = (0.0, 0.0, 0.1)
                link_head.tail = (0.0, 0.0, 0.0)
                link_head.parent = link
                link_head.use_inherit_scale = False

                link_tail = lnk.edit_bones.new('tail')
                link_tail.head = (0.0, Y, 0.0)
                link_tail.tail = (0.0, Y, -0.1)
                link_tail.parent = link
                link_tail.use_inherit_scale = False

                bpy.ops.object.mode_set(mode='OBJECT')

                ob = bpy.data.objects[n.name[:len(n.name)]+'.mesh.' + move + '.' + part +'.' + helicity]
                ob.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
    
                # Give mesh object an armature modifier, using vertex groups but
                # not envelopes
                mod = ob.modifiers.new('MyRigModif', 'ARMATURE')
                mod.object = lnk_rig
                mod.use_bone_envelopes = False
                mod.use_vertex_groups = True

                # Bone constraints. Armature must be in pose mode.
                bpy.ops.object.mode_set(mode='POSE')
 
                # Copy rotation constraints Base -> Tip
                pBase = lnk_rig.pose.bones[n.name[:len(n.name)]]
                cns = pBase.constraints.new('COPY_LOCATION')
                cns.name = 'Copy_Location'
                cns.target = rig
                cns.subtarget = n.name[:len(n.name)]
                cns.owner_space = 'WORLD'
                cns.target_space = 'WORLD'

                # Copy rotation constraints Base -> Tip
                pBase = lnk_rig.pose.bones[n.name[:len(n.name)]]
                cns = pBase.constraints.new('COPY_ROTATION')
                cns.name = 'Copy_Rotation'
                cns.target = rig
                cns.subtarget = n.name[:len(n.name)]
                cns.owner_space = 'WORLD'
                cns.target_space = 'WORLD'

                # StretchTo constraint Mid -> Tip with influence 0.5
                cns1 = pBase.constraints.new('STRETCH_TO')
                cns1.name = 'Stretch'
                cns1.target = rig
                cns1.subtarget = n.name[:len(n.name)]
                cns1.head_tail = 1
                cns1.rest_length = Y
                cns1.influence = 1
                cns1.keep_axis = 'PLANE_Z'
                cns1.volume = 'NO_VOLUME'

                bpy.ops.object.mode_set(mode='OBJECT')
    def configMovement(self, P, A, J, a, b, y, o):

        a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
        print("a1 =", a[1])

        a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
        print("a2 =", a[2])

        b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
        print("b1 =", b[1])

        o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
        print("o1 =", o[1])

        B = A * 2 * sqrt(2)
        C = B + (B * sqrt(2))
        D = C * sqrt(2)
        E = C + D

        y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
        print("y1 =", y[1])

        b[2] = mathutils.Euler(((9.4 / 0.6) * A, (-8.2 / 0.6) * A, 0.0), 'XYZ')
        print("b2 =", b[2])

        b[3] = mathutils.Euler(
            ((9.202797 / 0.6) * A, (-19.69939 / 0.6) * A, 0.0), 'XYZ')
        print("b3 =", b[3])

        y[2] = mathutils.Euler(((8.2 / 0.6) * A, (-9.4 / 0.6) * A, 0.0), 'XYZ')
        print("y2 =", y[2])

        y[3] = mathutils.Euler(
            ((10.842033 / 0.6) * A, (-19.260159 / 0.6) * A, 0.0), 'XYZ')
        print("y3 =", y[3])

        y[4] = mathutils.Euler(
            ((11.281277 / 0.6) * A, (-20.899431 / 0.6) * A, 0.0), 'XYZ')
        print("y4 =", y[4])

        o[2] = mathutils.Euler(
            ((6.560764 / 0.6) * A, (-9.83923 / 0.6) * A, 0.0), 'XYZ')
        print("o2 =", o[2])

        o[3] = mathutils.Euler(
            ((12.311729 / 0.6) * A, (-20.108688 / 0.6) * A, 0.0), 'XYZ')
        print("o3 =", o[3])
コード例 #25
0
def createGeometry(viscol, geomsrc, linkobj=None):
    """Creates Blender object for visual or collision objects.
    Returns reference to new object or None if creation failed.

    Args:
      viscol(dict): visual/collision dictionary element
      geomsrc(str): new object's phobostype
      linkobj(bpy.types.Object): link object

    Returns:
      bpy.types.Object or None

    """
    if 'geometry' not in viscol or viscol['geometry'] is {}:
        return None
    bpy.ops.object.select_all(action='DESELECT')
    geom = viscol['geometry']
    # create the Blender object
    if geom['type'] == 'mesh':
        bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes[geomsrc])
        meshname = "".join(os.path.basename(geom["filename"]).split(".")[:-1])
        if not os.path.isfile(geom['filename']):
            log(geom['filename'] + " is no file. Object " + viscol['name'] + " will have empty mesh!", "ERROR")
            #bpy.data.meshes.new(meshname)
            bpy.ops.object.add(type='MESH')
            newgeom = bpy.context.active_object
            nUtils.safelyName(newgeom, viscol['name'], phobostype=geomsrc)
        else:
            if meshname in bpy.data.meshes:
                log('Assigning copy of existing mesh ' + meshname + ' to ' + viscol['name'], 'INFO')
                bpy.ops.object.add(type='MESH')
                newgeom = bpy.context.object
                newgeom.data = bpy.data.meshes[meshname]
            else:
                log("Importing mesh for {0} element: '{1}".format(geomsrc, viscol['name']), 'INFO')
                filetype = geom['filename'].split('.')[-1].lower()
                newgeom = meshes.importMesh(geom['filename'], filetype)
                newgeom.data.name = meshname
                if not newgeom:
                    log('Failed to import mesh file ' + geom['filename'], 'ERROR')
                    return
            # scale imported object
            if 'scale' in geom:
                newgeom.scale = geom['scale']
    else:
        if geom['type'] == 'box':
            dimensions = geom['size']
        elif geom['type'] == 'cylinder':
            dimensions = (geom['radius'], geom['length'])
        elif geom['type'] == 'sphere':
            dimensions = geom['radius']
        else:
            log("Unknown geometry type of " + geomsrc + viscol['name']
                + '. Placing empty coordinate system.', "ERROR")
            bpy.ops.object.empty_add(type='PLAIN_AXES', radius=0.2)
            obj = bpy.context.object
            obj.phobostype = geomsrc
            nUtils.safelyName(bpy.context.active_object, viscol['name'], phobostype=geomsrc)
            return None
        log('Creating primtive for {0}: {1}'.format(geomsrc, viscol['name']), 'INFO')
        newgeom = bUtils.createPrimitive(viscol['name'], geom['type'], dimensions, phobostype=geomsrc)
        newgeom.select = True
        bpy.ops.object.transform_apply(scale=True)

    # from here it's the same for both meshes and primitives
    newgeom['geometry/type'] = geom['type']
    if geomsrc == 'visual':
        try:
            assignMaterial(newgeom, viscol['material'])
        except KeyError:
            log('No material for visual ' + viscol['name'], 'DEBUG')
    for prop in viscol:
        if prop.startswith('$'):
            for tag in viscol[prop]:
                newgeom[prop[1:]+'/'+tag] = viscol[prop][tag]
    nUtils.safelyName(newgeom, viscol['name'])
    newgeom[geomsrc+"/name"] = viscol['name']
    newgeom.phobostype = geomsrc

    # place geometric object relative to its parent link
    if linkobj:
        if 'pose' in viscol:
            log('Setting transformation of element: ' + viscol['name'], 'DEBUG')
            location = mathutils.Matrix.Translation(viscol['pose']['translation'])
            rotation = mathutils.Euler(tuple(viscol['pose']['rotation_euler']), 'XYZ').to_matrix().to_4x4()
        else:
            log('No pose in element: ' + viscol['name'], 'DEBUG')
            location = mathutils.Matrix.Identity(4)
            rotation = mathutils.Matrix.Identity(4)
        sUtils.selectObjects([newgeom, linkobj], True, 1)
        bpy.ops.object.parent_set(type='BONE_RELATIVE')
        newgeom.matrix_local = location * rotation
        if 'scale' in viscol['geometry']:
            newgeom.scale = mathutils.Vector(viscol['geometry']['scale'])
    return newgeom
コード例 #26
0
 def evaluate(self, f):
     return mathutils.Euler(self.fcurves_evaluator.evaluate(f)).to_quaternion()
コード例 #27
0
def convert_inverse_euler(blender_euler):
    """
    input rad euler angles and convert to blender rad coordinates
    """
    return list(mathutils.Euler(blender_euler, "ZYX"))
コード例 #28
0
def write_actions(actions):
    global current_scene
    open_class("UpdateCallbacks")
    open_class("osgAnimation::BasicAnimationManager")
    write_indented("num_animations %d" % (len(actions)))
    for action in actions:
        open_class("osgAnimation::Animation")
        write_indented("name \"%s\"" % (action.name))

        # restructure fcurves into channels (a channel combines x, y, and z for translation for example)
        channels = {}
        for fcurve in action.fcurves:
            if fcurve.data_path not in channels:
                channels[fcurve.data_path] = {}

            for keyframe in fcurve.keyframe_points:
                if keyframe.co[0] not in channels[fcurve.data_path]:
                    channels[fcurve.data_path][keyframe.co[0]] = {}
                channels[fcurve.data_path][keyframe.co[0]][
                    fcurve.array_index] = keyframe.co[1]

        # fix any "holes" ie in blender we can animate on the x channel only - in this case we should either drop the animation or evaluate the curve at the hole
        for path in iter(channels):
            channel = channels[path]
            bone_name = get_bone_from_path(path)
            bone_property = get_property_from_path(path)
            channel_skipped = False

            if bone_name != None and bone_property != None:
                num_properties = 0
                if bone_property.lower() == 'scale':
                    num_properties = 3
                elif bone_property.lower() == 'location':
                    num_properties = 3
                elif bone_property.lower() == 'rotation_euler':
                    pose_bone = get_pose_bone_by_name(bone_name)
                    if pose_bone != None and 'Z' in pose_bone.rotation_mode:
                        num_properties = 3
                elif bone_property.lower() == 'rotation_quaternion':
                    pose_bone = get_pose_bone_by_name(bone_name)
                    if pose_bone != None and pose_bone.rotation_mode == 'QUATERNION':
                        num_properties = 4
                if num_properties > 0:
                    for keyframe in channels[path].keys():
                        for i in range(0, num_properties):
                            if not i in channels[path][keyframe]:
                                fcurve = get_action_fcurve(action, path, i)
                                if fcurve != None:
                                    channels[path][keyframe][
                                        i] = fcurve.evaluate(keyframe)
                                else:
                                    # no fcurve exists for this property
                                    # we will have to skip the entire action
                                    channels.remove(path)
                                    channel_skipped = True
                        if channel_skipped:
                            break
                    if channel_skipped:
                        break

        write_indented("num_channels %d" % (len(channels)))

        for path in iter(channels):
            channel = channels[path]
            bone_name = get_bone_from_path(path)
            bone_property = get_property_from_path(path)

            if bone_name != None and bone_property != None:
                if bone_property.lower() == 'scale':
                    open_class("Vec3LinearChannel")
                    write_indented("name \"scale\"")
                    write_indented("target \"%s\"" % (bone_name))
                    open_class("Keyframes %d" % (len(channel)))

                    for timestamp in sorted(channel.keys()):
                        #write_indented("key %f %f %f %f" % (timestamp/current_scene.render.fps, channel[timestamp][1], channel[timestamp][0], channel[timestamp][2]))
                        write_indented(
                            "key %f %f %f %f" %
                            (timestamp / current_scene.render.fps,
                             channel[timestamp][0], channel[timestamp][2],
                             channel[timestamp][1]))

                    close_class()
                    close_class()
                elif bone_property.lower() == 'location':
                    open_class("Vec3LinearChannel")
                    write_indented("name \"translate\"")
                    write_indented("target \"%s\"" % (bone_name))
                    open_class("Keyframes %d" % (len(channel)))
                    for timestamp in sorted(channel.keys()):
                        # note the axis translation
                        #write_indented("key %f %f %f %f" % (timestamp/current_scene.render.fps, channel[timestamp][1], -channel[timestamp][0], channel[timestamp][2]))
                        #write_indented("key %f %f %f %f" % (timestamp/current_scene.render.fps, channel[timestamp][1], channel[timestamp][0], channel[timestamp][2]))
                        #write_indented("key %f %f %f %f" % (timestamp/current_scene.render.fps, channel[timestamp][0], channel[timestamp][1], channel[timestamp][2]))
                        write_indented(
                            "key %f %f %f %f" %
                            (timestamp / current_scene.render.fps,
                             channel[timestamp][0], channel[timestamp][2],
                             -channel[timestamp][1]))

                    close_class()
                    close_class()
                elif bone_property.lower() == 'rotation_euler':
                    # first - tweak the axis
                    # then convert to quaternion
                    pose_bone = get_pose_bone_by_name(bone_name)
                    if pose_bone != None and 'Z' in pose_bone.rotation_mode:
                        open_class("QuatSphericalLinearChannel")
                        write_indented("name \"quaternion\"")
                        write_indented("target \"%s\"" % (bone_name))
                        open_class("Keyframes %d" % (len(channel)))
                        for timestamp in sorted(channel.keys()):
                            euler = mathutils.Euler()
                            euler.order = pose_bone.rotation_mode
                            euler.x = channel[timestamp][0]
                            euler.y = channel[timestamp][1]
                            euler.z = channel[timestamp][2]

                            # reorder euler
                            #   t = euler.x
                            #  euler.x = euler.y
                            # euler.y = -t

                            quat = euler.to_quaternion()

                            # quat.rotate(mathutils.Matrix.Rotation(math.radians(180), 4, 'Z'))
                            # quat.
                            write_indented(
                                "key %f %f %f %f %f" %
                                (timestamp / current_scene.render.fps, quat.x,
                                 quat.y, quat.z, quat.w))

                        close_class()
                        close_class()
                elif bone_property.lower() == 'rotation_quaternion':
                    pose_bone = get_pose_bone_by_name(bone_name)
                    if pose_bone != None and pose_bone.rotation_mode == 'QUATERNION':
                        open_class("QuatSphericalLinearChannel")
                        write_indented("name \"quaternion\"")
                        write_indented("target \"%s\"" % (bone_name))
                        open_class("Keyframes %d" % (len(channel)))
                        for timestamp in sorted(channel.keys()):
                            quat = mathutils.Quaternion()
                            quat.w = channel[timestamp][0]
                            quat.x = channel[timestamp][1]
                            quat.y = channel[timestamp][2]
                            quat.z = channel[timestamp][3]

                            # convert to euler fix the axis and then back to quat
                            #euler = quat.to_euler('XYZ')
                            #t = euler.x
                            #euler.x = euler.y
                            #euler.y = -t
                            #quat = euler.to_quaternion()

                            # quat.rotate(mathutils.Matrix.Rotation(math.radians(-90), 4, 'Y'))

                            write_indented(
                                "key %f %f %f %f %f" %
                                (timestamp / current_scene.render.fps, quat.x,
                                 quat.y, quat.z, quat.w))

                        close_class()
                        close_class()
                # end if bone_name and bone_property
            # end for path in channels
        close_class()

    close_class()
    close_class()
コード例 #29
0
    def configMovement(self, P, A, J, a, b, y, o):

        mat_a = [0 for i in range(4)]  # Joint α matrix
        mat_b = [0 for i in range(self.J)]  # Joint β matrix
        mat_y = [0 for i in range(self.J)]  # Joint γ matrix
        mat_o = [0 for i in range(self.J)]  # Joint δ matrix

        a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
        print("a1 =", a[1])

        a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
        print("a2 =", a[2])

        b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
        print("b1 =", b[1])

        o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
        print("o1 =", o[1])

        B = A * 2 * sqrt(2)
        C = B + (B * sqrt(2))
        D = C * sqrt(2)
        E = C + D

        a[0] = mathutils.Euler((-A - E + (D * 0.5), -A - (D * 0.5), 0.0),
                               'XYZ')
        print("a0 =", a[0])
        mat_a[0] = Matrix.Translation(a[0])

        a[3] = mathutils.Euler((0 - a[0].x, 0 - a[0].y, 0 - a[0].z), 'XYZ')
        print("a3 =", a[3])
        mat_a[3] = Matrix.Translation(a[3])

        y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
        print("y1 =", y[1])
        mat_y[1] = Matrix.Translation(y[1])

        ### pattern A

        b[2] = mathutils.Euler((a[0].x + E + (A * 2), a[0].y + (A * 2), 0.0),
                               'XYZ')
        print("b2 =", b[2])
        mat_b[2] = Matrix.Translation(b[2])

        b[3] = mathutils.Euler((a[0].x + E - (D * 0.5), a[0].y - (A * 2), 0.0),
                               'XYZ')
        print("b3 =", b[3])
        mat_b[3] = Matrix.Translation(b[3])

        y[2] = mathutils.Euler((a[0].x + E, a[0].y, 0.0), 'XYZ')
        print("y2 =", y[2])
        mat_y[2] = Matrix.Translation(y[2])

        y[3] = mathutils.Euler(
            (a[0].x + E - (D * 0.5), a[0].y - (D * 0.5), 0.0), 'XYZ')
        print("y3 =", y[3])
        mat_y[3] = Matrix.Translation(y[3])

        o[2] = mathutils.Euler((a[0].x + E + (A * 2), a[0].y - (A * 2), 0.0),
                               'XYZ')
        print("o2 =", o[2])
        mat_o[2] = Matrix.Translation(o[2])

        o[3] = mathutils.Euler((a[0].x + E - (D * 0.5) - (A * 2), a[0].y -
                                (D * 0.5) - (A * 2), 0.0), 'XYZ')
        print("o3 =", o[3])
        mat_o[3] = Matrix.Translation(o[3])

        ### pattern A end

        org_rot_mat = Matrix.Rotation(math.radians(0), 4, 'Z')

        # define the rotation
        rot_mat = Matrix.Rotation(math.radians(-45), 4, 'Z')

        for j in range(2, J - 2):

            mat_y[j +
                  2] = mat_a[0] @ org_rot_mat @ rot_mat @ mat_a[3] @ mat_y[j]

            #            obj.matrix_world = mat_y[j + 2]
            # extract components back out of the matrix
            loc, rot, sca = mat_y[j + 2].decompose()
            y[j + 2] = mathutils.Euler(loc, 'XYZ')
            print("y" + str(j + 2) + " = ", y[j + 2], rot, sca)

            mat_b[j +
                  2] = mat_a[0] @ org_rot_mat @ rot_mat @ mat_a[3] @ mat_b[j]

            #            obj.matrix_world = mat_b[j + 2]
            # extract components back out of the matrix
            loc, rot, sca = mat_b[j + 2].decompose()
            b[j + 2] = mathutils.Euler(loc, 'XYZ')
            print("b" + str(j + 2) + " = ", b[j + 2], rot, sca)

            mat_o[j +
                  2] = mat_a[0] @ org_rot_mat @ rot_mat @ mat_a[3] @ mat_o[j]

            #            obj.matrix_world = mat_o[j + 2]
            # extract components back out of the matrix
            loc, rot, sca = mat_o[j + 2].decompose()
            o[j + 2] = mathutils.Euler(loc, 'XYZ')
            print("o" + str(j + 2) + " = ", o[j + 2], rot, sca)
コード例 #30
0
    def export_keyframes(self,
                         b_action,
                         space,
                         parent_block,
                         bind_matrix=None,
                         extra_mat_inv=None):

        if self.properties.animation == 'GEOM_NIF' and self.nif_export.version < 0x0A020000:
            # keyframe controllers are not present in geometry only files
            # for more recent versions, the controller and interpolators are
            # present, only the data is not present (see further on)
            return

        # only localspace keyframes need to be exported
        assert (space == 'localspace')

        # make sure the parent is of the right type
        assert (isinstance(parent_block, NifFormat.NiNode))

        # add a keyframecontroller block, and refer to this block in the
        # parent's time controller
        if self.nif_export.version < 0x0A020000:
            kfc = self.nif_export.objecthelper.create_block(
                "NiKeyframeController", b_action)
        else:
            kfc = self.nif_export.objecthelper.create_block(
                "NiTransformController", b_action)
            kfi = self.nif_export.objecthelper.create_block(
                "NiTransformInterpolator", b_action)
            # link interpolator from the controller
            kfc.interpolator = kfi
            # set interpolator default data
            scale, quat, trans = \
                parent_block.get_transform().get_scale_quat_translation()
            kfi.translation.x = trans.x
            kfi.translation.y = trans.y
            kfi.translation.z = trans.z
            kfi.rotation.x = quat.x
            kfi.rotation.y = quat.y
            kfi.rotation.z = quat.z
            kfi.rotation.w = quat.w
            kfi.scale = scale

        parent_block.add_controller(kfc)

        # determine cycle mode for this controller
        # this is stored in the blender action fcurves
        # while we're at it, we also determine the
        # start and stop frames
        extend = None
        if b_action:
            start_frame = +1000000
            stop_frame = -1000000
            for curve in b_action:
                # get cycle mode
                if extend is None:
                    extend = curve.extend
                elif extend != curve.extend:
                    self.nif_export.warning(
                        "Inconsistent extend type in %s, will use %s." %
                        (b_action, extend))
                # get start and stop frames
                start_frame = min(
                    start_frame,
                    min(btriple.pt[0] for btriple in curve.bezierPoints))
                stop_frame = max(
                    stop_frame,
                    max(btriple.pt[0] for btriple in curve.bezierPoints))
        else:
            # dummy b_action
            # default extend, start, and end
            extend = bpy.types.FCurve.ExtendTypes.CYCLIC
            start_frame = self.context.scene.frame_start
            stop_frame = self.context.scene.frame_end

        # fill in the non-trivial values
        kfc.flags = 8  # active
        kfc.flags |= self.get_flags_from_extend(extend)
        kfc.frequency = 1.0
        kfc.phase = 0.0
        kfc.start_time = (start_frame - 1) * self.context.scene.render.fps
        kfc.stop_time = (stop_frame - 1) * self.context.scene.render.fps

        if self.properties.animation == 'GEOM_NIF':
            # keyframe data is not present in geometry files
            return

        # -> get keyframe information

        # some calculations
        if bind_matrix:
            bind_scale, bind_rot, bind_trans = nif_utils.decompose_srt(
                bind_matrix)
            bind_quat = bind_rot.toQuat()
        else:
            bind_scale = 1.0
            bind_rot = mathutils.Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
            bind_quat = mathutils.Quaternion(1, 0, 0, 0)
            bind_trans = mathutils.Vector()
        if extra_mat_inv:
            extra_scale_inv, extra_rot_inv, extra_trans_inv = \
                nif_utils.decompose_srt(extra_mat_inv)
            extra_quat_inv = extra_rot_inv.toQuat()
        else:
            extra_scale_inv = 1.0
            extra_rot_inv = mathutils.Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
            extra_quat_inv = mathutils.Quaternion(1, 0, 0, 0)
            extra_trans_inv = mathutils.Vector()

        # sometimes we need to export an empty keyframe... this will take care of that
        if b_action is None:
            scale_curve = {}
            rot_curve = {}
            trans_curve = {}
        # the usual case comes now...
        else:
            # merge the animation curves into a rotation vector and translation vector curve
            scale_curve = {}
            rot_curve = {}
            trans_curve = {}
            # the following code makes these assumptions
            # Note: PO = Pose, OB = Object, MA = Material ***********************************************************************************
            assert (Ipo.PO_SCALEX == Ipo.OB_SCALEX)
            assert (Ipo.PO_LOCX == Ipo.OB_LOCX)
            # check validity of curves
            for curvecollection in ((Ipo.PO_SCALEX, Ipo.PO_SCALEY,
                                     Ipo.PO_SCALEZ), (Ipo.PO_LOCX, Ipo.PO_LOCY,
                                                      Ipo.PO_LOCZ),
                                    (Ipo.PO_QUATX, Ipo.PO_QUATY, Ipo.PO_QUATZ,
                                     Ipo.PO_QUATW), (Ipo.OB_ROTX, Ipo.OB_ROTY,
                                                     Ipo.OB_ROTZ)):
                # skip invalid curves
                try:
                    b_action[curvecollection[0]]
                except KeyError:
                    continue
                # check that if any curve is defined in the collection
                # then all curves are defined in the collection
                if (any(b_action[curve] for curve in curvecollection)
                        and not all(b_action[curve]
                                    for curve in curvecollection)):
                    keytype = {
                        Ipo.PO_SCALEX: "SCALE",
                        Ipo.PO_LOCX: "LOC",
                        Ipo.PO_QUATX: "ROT",
                        Ipo.OB_ROTX: "ROT"
                    }
                    raise nif_utils.NifError(
                        "missing curves in %s; insert %s key at frame 1 and try again"
                        % (b_action, keytype[curvecollection[0]]))
            # go over all curves
            b_action_curves = list(b_action.curveConsts.values())
            for curve in b_action_curves:
                # skip empty curves
                if b_action[curve] is None:
                    continue
                # non-empty curve: go over all frames of the curve
                for btriple in b_action[curve].bezierPoints:
                    frame = btriple.pt[0]
                    if (frame < self.context.scene.frame_start) or (
                            frame > self.context.scene.frame_end):
                        continue
                    # PO_SCALEX == OB_SCALEX, so this does both pose and object
                    # scale
                    if curve in (Ipo.PO_SCALEX, Ipo.PO_SCALEY, Ipo.PO_SCALEZ):
                        # support only uniform scaling... take the mean
                        scale_curve[frame] = (
                            b_action[Ipo.PO_SCALEX][frame] +
                            b_action[Ipo.PO_SCALEY][frame] +
                            b_action[Ipo.PO_SCALEZ][frame]) / 3.0
                        # SC' * SB' / SX
                        scale_curve[frame] = \
                            scale_curve[frame] * bind_scale * extra_scale_inv
                    # object rotation
                    elif curve in (Ipo.OB_ROTX, Ipo.OB_ROTY, Ipo.OB_ROTZ):
                        rot_curve[frame] = mathutils.Euler([
                            10 * ipo[Ipo.OB_ROTX][frame],
                            10 * ipo[Ipo.OB_ROTY][frame],
                            10 * ipo[Ipo.OB_ROTZ][frame]
                        ])
                        # use quat if we have bind matrix and/or extra matrix
                        # XXX maybe we should just stick with eulers??
                        if bind_matrix or extra_mat_inv:
                            rot_curve[frame] = rot_curve[frame].toQuat()
                            # beware, mathutils.Quaternion.cross takes arguments in a counter-intuitive order:
                            # q1.to_matrix() * q2.to_matrix() == mathutils.Quaternion.cross(q2, q1).to_matrix()
                            rot_curve[frame] = mathutils.Quaternion.cross(
                                mathutils.Quaternion.cross(
                                    bind_quat, rot_curve[frame]),
                                extra_quat_inv)  # inverse(RX) * RC' * RB'
                    # pose rotation
                    elif curve in (Ipo.PO_QUATX, Ipo.PO_QUATY, Ipo.PO_QUATZ,
                                   Ipo.PO_QUATW):
                        rot_curve[frame] = mathutils.Quaternion()
                        rot_curve[frame].x = b_action[Ipo.PO_QUATX][frame]
                        rot_curve[frame].y = b_action[Ipo.PO_QUATY][frame]
                        rot_curve[frame].z = b_action[Ipo.PO_QUATZ][frame]
                        rot_curve[frame].w = b_action[Ipo.PO_QUATW][frame]
                        # beware, mathutils.Quaternion.cross takes arguments in a counter-intuitive order:
                        # q1.to_matrix() * q2.to_matrix() == mathutils.Quaternion.cross(q2, q1).to_matrix()
                        rot_curve[frame] = mathutils.Quaternion.cross(
                            mathutils.Quaternion.cross(bind_quat,
                                                       rot_curve[frame]),
                            extra_quat_inv)  # inverse(RX) * RC' * RB'
                    # PO_LOCX == OB_LOCX, so this does both pose and object
                    # location
                    elif curve in (Ipo.PO_LOCX, Ipo.PO_LOCY, Ipo.PO_LOCZ):
                        trans_curve[frame] = mathutils.Vector([
                            b_action[Ipo.PO_LOCX][frame],
                            b_action[Ipo.PO_LOCY][frame],
                            b_action[Ipo.PO_LOCZ][frame]
                        ])
                        # T = - TX * inverse(RX) * RC' * RB' * SC' * SB' / SX + TC' * SB' * RB' + TB'
                        trans_curve[frame] *= bind_scale
                        trans_curve[frame] *= bind_rot
                        trans_curve[frame] += bind_trans
                        # we need RC' and SC'
                        if Ipo.OB_ROTX in b_action_curves and b_action[
                                Ipo.OB_ROTX]:
                            rot_c = mathutils.Euler([
                                10 * b_action[Ipo.OB_ROTX][frame],
                                10 * b_action[Ipo.OB_ROTY][frame],
                                10 * b_action[Ipo.OB_ROTZ][frame]
                            ]).to_matrix()
                        elif Ipo.PO_QUATX in b_action_curves and b_action[
                                Ipo.PO_QUATX]:
                            rot_c = mathutils.Quaternion()
                            rot_c.x = b_action[Ipo.PO_QUATX][frame]
                            rot_c.y = b_action[Ipo.PO_QUATY][frame]
                            rot_c.z = b_action[Ipo.PO_QUATZ][frame]
                            rot_c.w = b_action[Ipo.PO_QUATW][frame]
                            rot_c = rot_c.to_matrix()
                        else:
                            rot_c = mathutils.Matrix([[1, 0, 0], [0, 1, 0],
                                                      [0, 0, 1]])
                        # note, PO_SCALEX == OB_SCALEX, so this does both
                        if b_action[Ipo.PO_SCALEX]:
                            # support only uniform scaling... take the mean
                            scale_c = (b_action[Ipo.PO_SCALEX][frame] +
                                       b_action[Ipo.PO_SCALEY][frame] +
                                       b_action[Ipo.PO_SCALEZ][frame]) / 3.0
                        else:
                            scale_c = 1.0
                        trans_curve[frame] += \
                            extra_trans_inv * rot_c * bind_rot * \
                            scale_c * bind_scale

        # -> now comes the real export
        if (max(len(rot_curve), len(trans_curve), len(scale_curve)) <= 1
                and self.nif_export.version >= 0x0A020000):
            # only add data if number of keys is > 1
            # (see importer comments with import_kf_root: a single frame
            # keyframe denotes an interpolator without further data)
            # insufficient keys, so set the data and we're done!
            if trans_curve:
                trans = list(trans_curve.values())[0]
                kfi.translation.x = trans[0]
                kfi.translation.y = trans[1]
                kfi.translation.z = trans[2]
            if rot_curve:
                rot = list(rot_curve.values())[0]
                # XXX blender weirdness... Euler() is a function!!
                if isinstance(rot, mathutils.Euler().__class__):
                    rot = rot.toQuat()
                kfi.rotation.x = rot.x
                kfi.rotation.y = rot.y
                kfi.rotation.z = rot.z
                kfi.rotation.w = rot.w
            # ignore scale for now...
            kfi.scale = 1.0
            # done!
            return

        # add the keyframe data
        if self.nif_export.version < 0x0A020000:
            kfd = self.nif_export.objecthelper.create_block(
                "NiKeyframeData", b_action)
            kfc.data = kfd
        else:
            # number of frames is > 1, so add transform data
            kfd = self.nif_export.objecthelper.create_block(
                "NiTransformData", b_action)
            kfi.data = kfd

        frames = list(rot_curve.keys())
        frames.sort()
        # XXX blender weirdness... Euler() is a function!!
        if (frames and isinstance(
                list(rot_curve.values())[0],
                mathutils.Euler().__class__)):
            # eulers
            kfd.rotation_type = NifFormat.KeyType.XYZ_ROTATION
            kfd.num_rotation_keys = 1  # *NOT* len(frames) this crashes the engine!
            kfd.xyz_rotations[0].num_keys = len(frames)
            kfd.xyz_rotations[1].num_keys = len(frames)
            kfd.xyz_rotations[2].num_keys = len(frames)
            # TODO: quadratic interpolation?
            kfd.xyz_rotations[0].interpolation = NifFormat.KeyType.LINEAR
            kfd.xyz_rotations[1].interpolation = NifFormat.KeyType.LINEAR
            kfd.xyz_rotations[2].interpolation = NifFormat.KeyType.LINEAR
            kfd.xyz_rotations[0].keys.update_size()
            kfd.xyz_rotations[1].keys.update_size()
            kfd.xyz_rotations[2].keys.update_size()
            for i, frame in enumerate(frames):
                # TODO: speed up by not recalculating stuff
                rot_frame_x = kfd.xyz_rotations[0].keys[i]
                rot_frame_y = kfd.xyz_rotations[1].keys[i]
                rot_frame_z = kfd.xyz_rotations[2].keys[i]
                rot_frame_x.time = (frame - 1) * self.context.scene.render.fps
                rot_frame_y.time = (frame - 1) * self.context.scene.render.fps
                rot_frame_z.time = (frame - 1) * self.context.scene.render.fps
                rot_frame_x.value = rot_curve[
                    frame].x * 3.14159265358979323846 / 180.0
                rot_frame_y.value = rot_curve[
                    frame].y * 3.14159265358979323846 / 180.0
                rot_frame_z.value = rot_curve[
                    frame].z * 3.14159265358979323846 / 180.0
        else:
            # quaternions
            # TODO: quadratic interpolation?
            kfd.rotation_type = NifFormat.KeyType.LINEAR
            kfd.num_rotation_keys = len(frames)
            kfd.quaternion_keys.update_size()
            for i, frame in enumerate(frames):
                rot_frame = kfd.quaternion_keys[i]
                rot_frame.time = (frame - 1) * self.context.scene.render.fps
                rot_frame.value.w = rot_curve[frame].w
                rot_frame.value.x = rot_curve[frame].x
                rot_frame.value.y = rot_curve[frame].y
                rot_frame.value.z = rot_curve[frame].z

        frames = list(trans_curve.keys())
        frames.sort()
        kfd.translations.interpolation = NifFormat.KeyType.LINEAR
        kfd.translations.num_keys = len(frames)
        kfd.translations.keys.update_size()
        for i, frame in enumerate(frames):
            trans_frame = kfd.translations.keys[i]
            trans_frame.time = (frame - 1) * self.context.scene.render.fps
            trans_frame.value.x = trans_curve[frame][0]
            trans_frame.value.y = trans_curve[frame][1]
            trans_frame.value.z = trans_curve[frame][2]

        frames = list(scale_curve.keys())
        frames.sort()
        kfd.scales.interpolation = NifFormat.KeyType.LINEAR
        kfd.scales.num_keys = len(frames)
        kfd.scales.keys.update_size()
        for i, frame in enumerate(frames):
            scale_frame = kfd.scales.keys[i]
            scale_frame.time = (frame - 1) * self.context.scene.render.fps
            scale_frame.value = scale_curve[frame]