def load_ani(filename, context):
    name, ext = os.path.splitext(os.path.basename(filename))
    file = open(filename, 'rb')
    ani = MabinogiAnimation()
    try:
        magic, version, ani.frameCount, _, ani.baseTime, _, ani.boneCount = struct.unpack(
            "<4sihhhii", file.read(22))
    except:
        print("Error parsing file header!")
        file.close()
        return
    if magic != b'pa!\x00':
        print("Not a supported file type!")
        file.close()
        return
    file.seek(9 * 4, os.SEEK_CUR)
    for b in range(ani.boneCount):
        ani.bone += [
            MabinogiAniData(),
        ]
        _, ani.bone[b].mDataCount, _, ani.bone[b].mTime, ani.bone[
            b].mSize = struct.unpack("<ihhii", file.read(16))
        file.seek(2 * 4, os.SEEK_CUR)
        ani.bone[b].frames = list()
        print("bone %d" % b)
        for f in range(ani.bone[b].mDataCount):
            ani.bone[b].frames += [
                MabinogiFrame(),
            ]
            ani.bone[b].frames[f].mTime = struct.unpack("<i", file.read(4))[0]
            ani.bone[b].frames[f].move = struct.unpack("<4f", file.read(16))
            ani.bone[b].frames[f].roto = list(
                struct.unpack("<4f", file.read(16)))
            ani.bone[b].frames[f].roto = [-ani.bone[b].frames[f].roto[3]
                                          ] + ani.bone[b].frames[f].roto[:3]
            if f == 0:
                print(ani.bone[b].frames[f].mTime)
                print("%.2f %.2f %.2f %.2f" % ani.bone[b].frames[f].move)
                print("%.2f %.2f %.2f %.2f" %
                      tuple(ani.bone[b].frames[f].roto))

    #find if the selected object is a an armature
    armature = None
    sel_ob = None
    if len(context.selected_objects) > 0:
        sel_ob = context.selected_objects[0]
        if type(sel_ob.data) == bpy.types.Armature: armature = sel_ob.data
        else:
            print("No armature selected")
            return
    if len(armature.bones) != ani.boneCount:
        print("Bone count doesn't match")
    sel_ob.animation_data_create()
    action = bpy.data.actions.new(name=name)
    sel_ob.animation_data.action = action
    pb = sel_ob.pose.bones
    eb = sel_ob.data.bones
    pose_bones = dict()
    edit_bones = dict()
    for i in range(len(pb)):
        bone_id = int(pb[i].name[:pb[i].name.index('__')])
        pose_bones[bone_id] = pb[i]
        edit_bones[bone_id] = eb[i]
    bone_space = mathutils.Matrix(
        ((0, 1, 0, 0), (0, 0, 1, 0), (1, 0, 0, 0), (0, 0, 0, 1)))
    for b in range(ani.boneCount):
        for f in range(ani.bone[b].mDataCount):
            context.scene.frame_set(ani.bone[b].frames[f].mTime / 50)
            pos = ani.bone[b].frames[f].move[:3]
            quat = mathutils.Quaternion(ani.bone[b].frames[f].roto)
            mat = mathutils.Matrix.Translation(pos) * quat.to_matrix().to_4x4()
            link = edit_bones[b].matrix_local * bone_space.inverted()
            if edit_bones[b].parent is not None:
                parent_link = edit_bones[
                    b].parent.matrix_local * bone_space.inverted()
                link = parent_link.inverted() * link
            mat *= bone_space
            link *= bone_space
            pose_bones[b].matrix_basis = link.inverted() * mat
            pose_bones[b].keyframe_insert("rotation_quaternion")
            pose_bones[b].keyframe_insert("location")
Esempio n. 2
0
def animate_convert_rotation_axis_angle(axis_angle):
    q = mathutils.Quaternion((axis_angle[1], axis_angle[2], axis_angle[3]),
                             axis_angle[0])

    return [q.x, q.y, q.z, q.w]
Esempio n. 3
0
    def ModalMove(self, context):
        scene = context.scene
        pFS = scene.FSimProps
        pFSM = scene.FSimMainProps
        startFrame = pFSM.fsim_start_frame
        endFrame = pFSM.fsim_end_frame

        nFrame = scene.frame_current
        print("nFrame: ", nFrame)

        #Get the effort and direction change to head toward the target
        RqdEffort, RqdDirection, RqdDirectionV = self.Target(
            self.sTargetRig, self.sTargetProxy, pFS)
        if nFrame == startFrame:
            self.sOldRqdEffort = RqdEffort
            context.scene.frame_set(nFrame + 1)
            self.sOld_back_fin = self.sBack_fin_middle.matrix.decompose()[0]
            return 1
        TargetEffort = pFS.pEffortGain * (pFS.pEffortIntegral * RqdEffort +
                                          (RqdEffort - self.sOldRqdEffort))
        self.sOldRqdEffort = RqdEffort
        pFS.sEffort = pFS.pEffortGain * RqdEffort * pFS.pEffortRamp + pFS.sEffort * (
            1.0 - pFS.pEffortRamp)
        pFS.sEffort = min(pFS.sEffort, 1.0)
        #print("Required, Effort:", RqdEffort, pFS.sEffort)

        #Pec fin simulation
        self.PecSimulation(nFrame, pFS, startFrame)

        #Convert effort into tail frequency and amplitude (Fades to a low value if in hover mode)
        pFS.pFreq = self.rMaxFreq * (
            (1 - self.sHoverMode) *
            (1.0 / (pFS.sEffort + 0.01)) + self.sHoverMode * 2.0)
        pFS.pTailAngle = self.rMaxTailAngle * (
            (1 - self.sHoverMode) * pFS.sEffort +
            self.sHoverMode * pFS.pHoverTailFrc)
        #print("rMax, Frc: %.2f, %.2f" % (self.rMaxTailAngle, pFS.pHoverTailFrc))

        #Convert direction into Tail Offset angle (Work out swim turn angle and Hover turn angle and mix)
        xSwimTailAngleOffset = RqdDirection * pFS.pMaxSteeringAngle
        xHoverTailAngleOffset = pFS.pMaxSteeringAngle * self.sHoverTurn / 30.0
        xHoverTailAngleOffset = 0.0
        # xHoverFactor = max(0,(1.0 - self.sHoverMode * 4.0))
        pFS.sTailAngleOffset = pFS.sTailAngleOffset * (
            1 - pFS.pEffortRamp
        ) + pFS.pEffortRamp * max(
            0, (1.0 - self.sHoverMode * 2.0)
        ) * xSwimTailAngleOffset + pFS.pEffortRamp * self.sHoverMode * xHoverTailAngleOffset
        # pFS.sTailAngleOffset = pFS.sTailAngleOffset * (1 - pFS.pEffortRamp) + pFS.pEffortRamp * xSwimTailAngleOffset
        # print("xHoverOffset, TailOffset: ", xHoverTailAngleOffset, pFS.sTailAngleOffset)
        # print("HoverMode, xSwimTailAngleOffset: ", self.sHoverMode, xSwimTailAngleOffset)

        #Hover 'Twitch' calculations (Make the fish do some random twisting during hover mode)
        if self.sHoverMode < 0.5:
            #Not hovering so reset
            self.sTwitchTarget = 0.0
            self.sTwitchFrame = 0.0
        else:
            #Hovering, so check if the twitch frame has been reached
            if nFrame >= self.sTwitchFrame:
                #set new twitch frame
                self.sTwitchFrame = nFrame + pFS.pHoverTwitchTime * (random() -
                                                                     0.5)
                #Only twitch while not resting
                if self.sTwitchFrame < self.sRestartFrame and self.sTwitchFrame > self.sRestFrame:
                    self.sTwitchFrame = self.sRestartFrame + 5
                #set a new twitch target angle
                self.sTwitchTarget = pFS.pHoverTwitch * 2.0 * (random() - 0.5)
        self.sTwitchAngle = self.sTwitchAngle * 0.9 + 0.1 * self.sTwitchTarget
        #print("Twitch Angle: ", self.sTwitchAngle)

        #Spine Movement
        self.sState = self.sState + 360.0 / pFS.pFreq
        xTailAngle = math.sin(math.radians(self.sState)) * math.radians(
            pFS.pTailAngle) + math.radians(
                pFS.sTailAngleOffset) + math.radians(self.sTwitchAngle)
        #print("Components: %.2f, %.2f, %.2f" % (math.sin(math.radians(self.sState))*math.radians(pFS.pTailAngle),math.radians(pFS.sTailAngleOffset),math.radians(self.sTwitchAngle)))
        #print("TailAngle", math.degrees(xTailAngle))
        self.sSpine_master.rotation_quaternion = mathutils.Quaternion(
            (0.0, 0.0, 1.0), xTailAngle)
        self.sSpine_master.keyframe_insert(data_path='rotation_quaternion',
                                           frame=(nFrame))
        ChestRot = mathutils.Quaternion(
            (0.0, 0.0, 1.0), -xTailAngle *
            pFS.pChestRatio)  # - math.radians(pFS.sTailAngleOffset))
        self.sChest.rotation_quaternion = ChestRot * mathutils.Quaternion(
            (1.0, 0.0, 0.0), -math.fabs(math.radians(pFS.sTailAngleOffset)) *
            pFS.pChestRaise * (1.0 - self.sHoverMode))
        #print("Torso:", pFS.sTailAngleOffset)
        self.sTorso.rotation_quaternion = mathutils.Quaternion(
            (0.0, 1.0, 0.0), -math.radians(pFS.sTailAngleOffset) *
            pFS.pLeanIntoTurn * (1.0 - self.sHoverMode))
        self.sChest.keyframe_insert(data_path='rotation_quaternion',
                                    frame=(nFrame))
        self.sTorso.keyframe_insert(data_path='rotation_quaternion',
                                    frame=(nFrame))
        #context.scene.update()

        # #Tail Movment
        if (nFrame == startFrame):
            back_fin_dif = 0
        else:
            back_fin_dif = (self.sBack_fin_middle.matrix.decompose()[0].x -
                            self.sOld_back_fin.x)
        self.sOld_back_fin = self.sBack_fin_middle.matrix.decompose()[0]

        #Tailfin bending based on phase offset
        pMaxTailScale = pFS.pMaxTailFinAngle * (
            1.0 / pFS.pTailFinStiffness) * 0.2 / 30.0

        self.sBack_fin1_scale = 1.0 + math.sin(
            math.radians(self.sState + pFS.pTailFinPhase)) * pMaxTailScale * (
                pFS.pTailAngle / self.rMaxTailAngle)
        # print("Bend Factor: ", (pFS.pTailAngle / self.rMaxTailAngle))

        self.sBack_fin1.scale[1] = self.sBack_fin1_scale
        self.sBack_fin2.scale[1] = 1 - (
            1 - self.sBack_fin1_scale) * pFS.pTailFinStubRatio
        self.sBack_fin1.keyframe_insert(data_path='scale', frame=(nFrame))
        self.sBack_fin2.keyframe_insert(data_path='scale', frame=(nFrame))

        SideFinRot = math.sin(
            math.radians(self.sState +
                         pFS.pSideFinPhase)) * pFS.pMaxSideFinAngle

        self.sSideFinL.rotation_quaternion = mathutils.Quaternion(
            (1, 0, 0), math.radians(-SideFinRot))
        self.sSideFinR.rotation_quaternion = mathutils.Quaternion(
            (1, 0, 0), math.radians(SideFinRot))

        self.sSideFinL.keyframe_insert(data_path='rotation_quaternion',
                                       frame=(nFrame))
        self.sSideFinR.keyframe_insert(data_path='rotation_quaternion',
                                       frame=(nFrame))

        #Do Object movment with Forward force and Angular force
        TailFinAngle = (self.sBack_fin1_scale - 1.0) * 30.0 / 0.4
        TailFinAngleForce = math.sin(math.radians(TailFinAngle))
        # ForwardForce = -back_fin_dif * TailFinAngleForce * pFS.pPower
        ForwardForce = math.fabs(math.cos(math.radians(
            self.sState))) * math.radians(
                pFS.pTailAngle) * 15.0 * pFS.pPower / pFS.pMaxFreq
        # print("Force", ForwardForce, math.fabs(math.cos(math.radians(self.sState))), math.radians(pFS.pTailAngle))

        #Angular force due to 'swish'
        AngularForce = back_fin_dif / pFS.pAngularDrag

        #Angular force due to rudder effect
        AngularForce += xTailAngle * pFS.sVelocity[1] / pFS.pAngularDrag

        #Fake Angular force to make turning more effective
        AngularForce += -(pFS.sTailAngleOffset /
                          pFS.pMaxSteeringAngle) * pFS.pTurnAssist

        #Angular force for vertical movement
        self.sAngularForceV = self.sAngularForceV * (
            1 - pFS.pEffortRamp) + RqdDirectionV * pFS.pMaxVerticalAngle

        #print("TailFinAngle, AngularForce", xTailAngle, AngularForce)
        if self.sHoverMode < 0.1:
            self.ObjectMovment(self.sTargetRig, ForwardForce, AngularForce,
                               self.sAngularForceV, nFrame, self.sTargetProxy,
                               pFS)
        else:
            self.ObjectMovmentHover(self.sTargetRig, nFrame, self.sTargetProxy,
                                    pFS)

        #Go to next frame, or finish
        wm = context.window_manager
        # print("Frame: ", nFrame)
        if nFrame == endFrame:
            return 0
        else:
            wm.progress_update((len(self.sArmatures) - self.nArmature) * 99.0 /
                               len(self.sArmatures))
            context.scene.frame_set(nFrame + 1)
            return 1
Esempio n. 4
0
def lp_left(bm, lp, wid, vm, wm):
    # pass
    size = len(lp)
    up = wm.inverted() * vm.inverted() * Vector((0, 0, 1))
    lp_off = []
    faces = []
    for i in range(size - 1):
        if i == 0:
            pt = bm.verts[lp[i]].co
            pre = bm.verts[lp[-2]].co
            nxt = bm.verts[lp[1]].co
            pre_ind = lp[size - 2]
            nxt_ind = lp[1]
        else:
            bm.verts.ensure_lookup_table()
            pt = bm.verts[lp[i]].co
            pre = bm.verts[lp[i - 1]].co
            nxt = bm.verts[lp[i + 1]].co
            pre_ind = lp[i - 1]
            nxt_ind = lp[i + 1]

        vec1 = pt - pre
        vec2 = pt - nxt

        mid = vec1.normalized() + vec2.normalized()
        if mid.length < 10e-4:

            up2 = Vector((0, 0, 1))
            mid = up2.cross(vec1)

        else:
            xx = mid.cross(vec1).dot(up)

            if xx > 0:
                mid.negate()

        mid.normalize()
        if pre_ind == nxt_ind:
            mid = (pt - pre).normalized()
            q_a = mathutils.Quaternion((0.0, 0.0, 1.0), math.radians(90.0))
            q_b = mathutils.Quaternion((0.0, 0.0, 1.0), math.radians(-180.0))
            mid.rotate(q_a)
            pt1 = pt + mid * wid
            mid.rotate(q_b)
            pt2 = pt + mid * wid
            new_vert_1 = bm.verts.new(pt1)
            new_vert_2 = bm.verts.new(pt2)
            lp_off.append([new_vert_1, new_vert_2])
        else:
            ang = mid.angle(pre - pt)

            vec_len = wid / (math.sin(ang))
            # print(wid)
            pt = pt + mid * vec_len
            new_vert = bm.verts.new(pt)
            lp_off.append(new_vert)
    lp_off.append(lp_off[0])
    bm.verts.index_update()
    for i in range(len(lp_off) - 1):
        bm.verts.ensure_lookup_table()
        p1 = bm.verts[lp[i]]
        p2 = bm.verts[lp[i + 1]]
        p3 = lp_off[i + 1]
        p4 = lp_off[i]

        if isinstance(p3, list):

            faces.append((p1, p2, p3[0], p4))
            # faces.append((p3[0],p2,p3[1]))
        elif isinstance(p4, list):

            faces.append((p1, p2, p3, p4[1]))
        else:
            faces.append((p1, p2, p3, p4))

    return faces
import mathutils
import math

# a new rotation 90 degrees about the Y axis
quat_a = mathutils.Quaternion((0.7071068, 0.0, 0.7071068, 0.0))

# passing values to Quaternion's directly can be confusing so axis, angle
# is supported for initializing too
quat_b = mathutils.Quaternion((0.0, 1.0, 0.0), math.radians(90.0))

print("Check quaternions match", quat_a == quat_b)

# like matrices, quaternions can be multiplied to accumulate rotational values
quat_a = mathutils.Quaternion((0.0, 1.0, 0.0), math.radians(90.0))
quat_b = mathutils.Quaternion((0.0, 0.0, 1.0), math.radians(45.0))
quat_out = quat_a * quat_b

# print the quat, euler degrees for mear mortals and (axis, angle)
print("Final Rotation:")
print(quat_out)
print("%.2f, %.2f, %.2f" % tuple(math.degrees(a) for a in quat_out.to_euler()))
print("(%.2f, %.2f, %.2f), %.2f" % (quat_out.axis[:] +
                                    (math.degrees(quat_out.angle), )))

# multiple rotations can be interpolated using the exponential map
quat_c = mathutils.Quaternion((1.0, 0.0, 0.0), math.radians(15.0))
exp_avg = (quat_a.to_exponential_map() + quat_b.to_exponential_map() +
           quat_c.to_exponential_map()) / 3.0
quat_avg = mathutils.Quaternion(exp_avg)
print("Average rotation:")
print(quat_avg)
Esempio n. 6
0
    def import_armature(self, niArmature):
        """Scans an armature hierarchy, and returns a whole armature.
		This is done outside the normal node tree scan to allow for positioning
		of the bones before skins are attached."""
        armature_name = self.import_name(niArmature)

        b_armatureData = Blender.Armature.Armature()
        b_armatureData.name = armature_name
        b_armatureData.drawAxes = True
        b_armatureData.envelopes = False
        b_armatureData.vertexGroups = True
        b_armatureData.draw_type = 'STICK'
        b_armature = self.context.scene.objects.new(b_armatureData,
                                                    armature_name)

        # make armature editable and create bones
        b_armatureData.makeEditable()
        niChildBones = [
            child for child in niArmature.children if self.is_bone(child)
        ]
        for niBone in niChildBones:
            self.import_bone(niBone, b_armature, b_armatureData, niArmature)
        b_armatureData.update()

        # TODO: Move to Animation.py

        # The armature has been created in editmode,
        # now we are ready to set the bone keyframes.
        if self.nif_common.properties.animation:
            # create an action
            action = Blender.Armature.NLA.NewAction()
            action.setActive(b_armature)
            # go through all armature pose bones
            # see http://www.elysiun.com/forum/viewtopic.php?t=58693
            self.nif_common.info('Importing Animations')
            for bone_name, b_posebone in b_armature.getPose().bones.items():
                # denote progress
                self.nif_common.debug('Importing animation for bone %s' %
                                      bone_name)
                niBone = self.nif_common.blocks[bone_name]

                # get bind matrix (NIF format stores full transformations in keyframes,
                # but Blender wants relative transformations, hence we need to know
                # the bind position for conversion). Since
                # [ SRchannel 0 ]	[ SRbind 0 ]   [ SRchannel * SRbind		 0 ]   [ SRtotal 0 ]
                # [ Tchannel  1 ] *  [ Tbind  1 ] = [ Tchannel  * SRbind + Tbind 1 ] = [ Ttotal  1 ]
                # with
                # 'total' the transformations as stored in the NIF keyframes,
                # 'bind' the Blender bind pose, and
                # 'channel' the Blender IPO channel,
                # it follows that
                # Schannel = Stotal / Sbind
                # Rchannel = Rtotal * inverse(Rbind)
                # Tchannel = (Ttotal - Tbind) * inverse(Rbind) / Sbind
                bone_bm = self.nif_common.import_matrix(niBone)  # base pose
                niBone_bind_scale, niBone_bind_rot, niBone_bind_trans = self.decompose_srt(
                    bone_bm)
                niBone_bind_rot_inv = mathutils.Matrix(niBone_bind_rot)
                niBone_bind_rot_inv.invert()
                niBone_bind_quat_inv = niBone_bind_rot_inv.toQuat()
                # we also need the conversion of the original matrix to the
                # new bone matrix, say X,
                # B' = X * B
                # (with B' the Blender matrix and B the NIF matrix) because we
                # need that
                # C' * B' = X * C * B
                # and therefore
                # C' = X * C * B * inverse(B') = X * C * inverse(X),
                # where X = B' * inverse(B)
                #
                # In detail:
                # [ SRX 0 ]   [ SRC 0 ]			[ SRX 0 ]
                # [ TX  1 ] * [ TC  1 ] * inverse( [ TX  1 ] ) =
                # [ SRX * SRC	   0 ]   [ inverse(SRX)		 0 ]
                # [ TX * SRC + TC   1 ] * [ -TX * inverse(SRX)   1 ] =
                # [ SRX * SRC * inverse(SRX)			  0 ]
                # [ (TX * SRC + TC - TX) * inverse(SRX)   1 ]
                # Hence
                # SC' = SX * SC / SX = SC
                # RC' = RX * RC * inverse(RX)
                # TC' = (TX * SC * RC + TC - TX) * inverse(RX) / SX
                extra_matrix_scale, extra_matrix_rot, extra_matrix_trans = self.decompose_srt(
                    self.bones_extra_matrix[niBone])
                extra_matrix_quat = extra_matrix_rot.toQuat()
                extra_matrix_rot_inv = mathutils.Matrix(extra_matrix_rot)
                extra_matrix_rot_inv.invert()
                extra_matrix_quat_inv = extra_matrix_rot_inv.toQuat()
                # now import everything
                # ##############################

                # get controller, interpolator, and data
                # note: the NiKeyframeController check also includes
                #	   NiTransformController (see hierarchy!)
                kfc = self.find_controller(niBone,
                                           NifFormat.NiKeyframeController)
                # old style: data directly on controller
                kfd = kfc.data if kfc else None
                # new style: data via interpolator
                kfi = kfc.interpolator if kfc else None
                # next is a quick hack to make the new transform
                # interpolator work as if it is an old style keyframe data
                # block parented directly on the controller
                if isinstance(kfi, NifFormat.NiTransformInterpolator):
                    kfd = kfi.data
                    # for now, in this case, ignore interpolator
                    kfi = None

                # B-spline curve import
                if isinstance(kfi, NifFormat.NiBSplineInterpolator):
                    times = list(kfi.get_times())
                    translations = list(kfi.get_translations())
                    scales = list(kfi.get_scales())
                    rotations = list(kfi.get_rotations())

                    # if we have translation keys, we make a dictionary of
                    # rot_keys and scale_keys, this makes the script work MUCH
                    # faster in most cases
                    if translations:
                        scale_keys_dict = {}
                        rot_keys_dict = {}

                    # scales: ignore for now, implement later
                    #		 should come here
                    scales = None

                    # rotations
                    if rotations:
                        self.nif_common.debug(
                            'Rotation keys...(bspline quaternions)')
                        for time, quat in zip(times, rotations):
                            frame = 1 + int(time * self.nif_common.fps + 0.5)
                            quat = mathutils.Quaternion(
                                [quat[0], quat[1], quat[2], quat[3]])
                            # beware, CrossQuats takes arguments in a
                            # counter-intuitive order:
                            # q1.toMatrix() * q2.toMatrix() == CrossQuats(q2, q1).toMatrix()
                            quatVal = CrossQuats(
                                niBone_bind_quat_inv,
                                quat)  # Rchannel = Rtotal * inverse(Rbind)
                            rot = CrossQuats(
                                CrossQuats(extra_matrix_quat_inv, quatVal),
                                extra_matrix_quat)  # C' = X * C * inverse(X)
                            b_posebone.quat = rot
                            b_posebone.insertKey(b_armature, frame,
                                                 [Blender.Object.Pose.ROT])
                            # fill optimizer dictionary
                            if translations:
                                rot_keys_dict[frame] = mathutils.Quaternion(
                                    rot)

                    # translations
                    if translations:
                        self.nif_common.debug('Translation keys...(bspline)')
                        for time, translation in zip(times, translations):
                            # time 0.0 is frame 1
                            frame = 1 + int(time * self.nif_common.fps + 0.5)
                            trans = mathutils.Vector(*translation)
                            locVal = (
                                trans - niBone_bind_trans
                            ) * niBone_bind_rot_inv * (
                                1.0 / niBone_bind_scale
                            )  # Tchannel = (Ttotal - Tbind) * inverse(Rbind) / Sbind
                            # the rotation matrix is needed at this frame (that's
                            # why the other keys are inserted first)
                            if rot_keys_dict:
                                try:
                                    rot = rot_keys_dict[frame].toMatrix()
                                except KeyError:
                                    # fall back on slow method
                                    ipo = action.getChannelIpo(bone_name)
                                    quat = mathutils.Quaternion()
                                    quat.x = ipo.getCurve('QuatX').evaluate(
                                        frame)
                                    quat.y = ipo.getCurve('QuatY').evaluate(
                                        frame)
                                    quat.z = ipo.getCurve('QuatZ').evaluate(
                                        frame)
                                    quat.w = ipo.getCurve('QuatW').evaluate(
                                        frame)
                                    rot = quat.toMatrix()
                            else:
                                rot = mathutils.Matrix([[1.0, 0.0, 0.0],
                                                        [0.0, 1.0, 0.0],
                                                        [0.0, 0.0, 1.0]])
                            # we also need the scale at this frame
                            if scale_keys_dict:
                                try:
                                    sizeVal = scale_keys_dict[frame]
                                except KeyError:
                                    ipo = action.getChannelIpo(bone_name)
                                    if ipo.getCurve('SizeX'):
                                        sizeVal = ipo.getCurve(
                                            'SizeX').evaluate(
                                                frame)  # assume uniform scale
                                    else:
                                        sizeVal = 1.0
                            else:
                                sizeVal = 1.0
                            size = mathutils.Matrix([[sizeVal, 0.0, 0.0],
                                                     [0.0, sizeVal, 0.0],
                                                     [0.0, 0.0, sizeVal]])
                            # now we can do the final calculation
                            loc = (
                                extra_matrix_trans * size * rot + locVal -
                                extra_matrix_trans) * extra_matrix_rot_inv * (
                                    1.0 / extra_matrix_scale
                                )  # C' = X * C * inverse(X)
                            b_posebone.loc = loc
                            b_posebone.insertKey(b_armature, frame,
                                                 [Blender.Object.Pose.LOC])

                    # delete temporary dictionaries
                    if translations:
                        del scale_keys_dict
                        del rot_keys_dict

                # NiKeyframeData and NiTransformData import
                elif isinstance(kfd, NifFormat.NiKeyframeData):

                    translations = kfd.translations
                    scales = kfd.scales
                    # if we have translation keys, we make a dictionary of
                    # rot_keys and scale_keys, this makes the script work MUCH
                    # faster in most cases
                    if translations:
                        scale_keys_dict = {}
                        rot_keys_dict = {}
                    # add the keys

                    # Scaling
                    if scales.keys:
                        self.nif_common.debug('Scale keys...')
                    for scaleKey in scales.keys:
                        # time 0.0 is frame 1
                        frame = 1 + int(scaleKey.time * self.nif_common.fps +
                                        0.5)
                        sizeVal = scaleKey.value
                        size = sizeVal / niBone_bind_scale  # Schannel = Stotal / Sbind
                        b_posebone.size = mathutils.Vector(size, size, size)
                        b_posebone.insertKey(b_armature, frame,
                                             [Blender.Object.Pose.SIZE
                                              ])  # this is very slow... :(
                        # fill optimizer dictionary
                        if translations:
                            scale_keys_dict[frame] = size

                    # detect the type of rotation keys
                    rotation_type = kfd.rotation_type

                    # Euler Rotations
                    if rotation_type == 4:
                        # uses xyz rotation
                        if kfd.xyz_rotations[0].keys:
                            self.nif_common.debug('Rotation keys...(euler)')
                        for xkey, ykey, zkey in zip(kfd.xyz_rotations[0].keys,
                                                    kfd.xyz_rotations[1].keys,
                                                    kfd.xyz_rotations[2].keys):
                            # time 0.0 is frame 1
                            # XXX it is assumed that all the keys have the
                            # XXX same times!!!
                            if (abs(xkey.time - ykey.time) >
                                    self.nif_common.properties.epsilon
                                    or abs(xkey.time - zkey.time) >
                                    self.nif_common.properties.epsilon):
                                self.nif_common.warning(
                                    "xyz key times do not correspond, "
                                    "animation may not be correctly imported")
                            frame = 1 + int(xkey.time * self.nif_common.fps +
                                            0.5)
                            euler = mathutils.Euler([
                                xkey.value * 180.0 / math.pi,
                                ykey.value * 180.0 / math.pi,
                                zkey.value * 180.0 / math.pi
                            ])
                            quat = euler.toQuat()

                            # beware, CrossQuats takes arguments in a counter-intuitive order:
                            # q1.toMatrix() * q2.toMatrix() == CrossQuats(q2, q1).toMatrix()

                            quatVal = CrossQuats(
                                niBone_bind_quat_inv,
                                quat)  # Rchannel = Rtotal * inverse(Rbind)
                            rot = CrossQuats(
                                CrossQuats(extra_matrix_quat_inv, quatVal),
                                extra_matrix_quat)  # C' = X * C * inverse(X)
                            b_posebone.quat = rot
                            b_posebone.insertKey(b_armature, frame,
                                                 [Blender.Object.Pose.ROT
                                                  ])  # this is very slow... :(
                            # fill optimizer dictionary
                            if translations:
                                rot_keys_dict[frame] = mathutils.Quaternion(
                                    rot)

                    # Quaternion Rotations
                    else:
                        # TODO take rotation type into account for interpolation
                        if kfd.quaternion_keys:
                            self.nif_common.debug(
                                'Rotation keys...(quaternions)')
                        quaternion_keys = kfd.quaternion_keys
                        for key in quaternion_keys:
                            frame = 1 + int(key.time * self.nif_common.fps +
                                            0.5)
                            keyVal = key.value
                            quat = mathutils.Quaternion(
                                [keyVal.w, keyVal.x, keyVal.y, keyVal.z])
                            # beware, CrossQuats takes arguments in a
                            # counter-intuitive order:
                            # q1.toMatrix() * q2.toMatrix() == CrossQuats(q2, q1).toMatrix()
                            quatVal = CrossQuats(
                                niBone_bind_quat_inv,
                                quat)  # Rchannel = Rtotal * inverse(Rbind)
                            rot = CrossQuats(
                                CrossQuats(extra_matrix_quat_inv, quatVal),
                                extra_matrix_quat)  # C' = X * C * inverse(X)
                            b_posebone.quat = rot
                            b_posebone.insertKey(b_armature, frame,
                                                 [Blender.Object.Pose.ROT])
                            # fill optimizer dictionary
                            if translations:
                                rot_keys_dict[frame] = mathutils.Quaternion(
                                    rot)
                        #else:
                        #	print("Rotation keys...(unknown)" +
                        #		  "WARNING: rotation animation data of type" +
                        #		  " %i found, but this type is not yet supported; data has been skipped""" % rotation_type)

                    # Translations
                    if translations.keys:
                        self.nif_common.debug('Translation keys...')
                    for key in translations.keys:
                        # time 0.0 is frame 1
                        frame = 1 + int(key.time * self.nif_common.fps + 0.5)
                        keyVal = key.value
                        trans = mathutils.Vector(keyVal.x, keyVal.y, keyVal.z)
                        locVal = (
                            trans - niBone_bind_trans
                        ) * niBone_bind_rot_inv * (
                            1.0 / niBone_bind_scale
                        )  # Tchannel = (Ttotal - Tbind) * inverse(Rbind) / Sbind
                        # the rotation matrix is needed at this frame (that's
                        # why the other keys are inserted first)
                        if rot_keys_dict:
                            try:
                                rot = rot_keys_dict[frame].toMatrix()
                            except KeyError:
                                # fall back on slow method
                                ipo = action.getChannelIpo(bone_name)
                                quat = mathutils.Quaternion()
                                quat.x = ipo.getCurve('QuatX').evaluate(frame)
                                quat.y = ipo.getCurve('QuatY').evaluate(frame)
                                quat.z = ipo.getCurve('QuatZ').evaluate(frame)
                                quat.w = ipo.getCurve('QuatW').evaluate(frame)
                                rot = quat.toMatrix()
                        else:
                            rot = mathutils.Matrix([[1.0, 0.0, 0.0],
                                                    [0.0, 1.0, 0.0],
                                                    [0.0, 0.0, 1.0]])
                        # we also need the scale at this frame
                        if scale_keys_dict:
                            try:
                                sizeVal = scale_keys_dict[frame]
                            except KeyError:
                                ipo = action.getChannelIpo(bone_name)
                                if ipo.getCurve('SizeX'):
                                    sizeVal = ipo.getCurve('SizeX').evaluate(
                                        frame)  # assume uniform scale
                                else:
                                    sizeVal = 1.0
                        else:
                            sizeVal = 1.0
                        size = mathutils.Matrix([[sizeVal, 0.0, 0.0],
                                                 [0.0, sizeVal, 0.0],
                                                 [0.0, 0.0, sizeVal]])
                        # now we can do the final calculation
                        loc = (extra_matrix_trans * size * rot + locVal -
                               extra_matrix_trans) * extra_matrix_rot_inv * (
                                   1.0 / extra_matrix_scale
                               )  # C' = X * C * inverse(X)
                        b_posebone.loc = loc
                        b_posebone.insertKey(b_armature, frame,
                                             [Blender.Object.Pose.LOC])
                    if translations:
                        del scale_keys_dict
                        del rot_keys_dict
                # set extend mode for all ipo curves
                if kfc:
                    try:
                        ipo = action.getChannelIpo(bone_name)
                    except ValueError:
                        # no channel for bone_name
                        pass
                    else:
                        for b_curve in ipo:
                            b_curve.extend = self.nif_common.get_extend_from_flags(
                                kfc.flags)

        # constraints (priority)
        # must be done outside edit mode hence after calling
        for bone_name, b_posebone in b_armature.getPose().bones.items():
            # find bone nif block
            niBone = self.nif_common.blocks[bone_name]
            # store bone priority, if applicable
            if niBone.name in self.nif_common.bone_priorities:
                constr = b_posebone.constraints.append(
                    bpy.types.Constraint.NULL)
                constr.name = "priority:%i" % self.nif_common.bone_priorities[
                    niBone.name]

        return b_armature
Esempio n. 7
0
def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
    from bpy_extras.image_utils import load_image

    #print previous_chunk.bytes_read, 'BYTES READ'
    contextObName = None
    contextLamp = [None, None]  # object, Data
    contextMaterial = None
    contextMatrix_rot = None  # Blender.mathutils.Matrix(); contextMatrix.identity()
    #contextMatrix_tx = None # Blender.mathutils.Matrix(); contextMatrix.identity()
    contextMesh_vertls = None  # flat array: (verts * 3)
    contextMesh_facels = None
    contextMeshMaterials = []  # (matname, [face_idxs])
    contextMeshUV = None  # flat array (verts * 2)

    TEXTURE_DICT = {}
    MATDICT = {}
# 	TEXMODE = Mesh.FaceModes['TEX']

    # Localspace variable names, faster.
    STRUCT_SIZE_FLOAT = struct.calcsize('f')
    STRUCT_SIZE_2FLOAT = struct.calcsize('2f')
    STRUCT_SIZE_3FLOAT = struct.calcsize('3f')
    STRUCT_SIZE_4FLOAT = struct.calcsize('4f')
    STRUCT_SIZE_UNSIGNED_SHORT = struct.calcsize('H')
    STRUCT_SIZE_4UNSIGNED_SHORT = struct.calcsize('4H')
    STRUCT_SIZE_4x3MAT = struct.calcsize('ffffffffffff')
    # STRUCT_SIZE_4x3MAT = calcsize('ffffffffffff')
    # print STRUCT_SIZE_4x3MAT, ' STRUCT_SIZE_4x3MAT'
    # only init once
    object_list = []  # for hierarchy
    object_parent = []  # index of parent in hierarchy, 0xFFFF = no parent
    pivot_list = []  # pivots with hierarchy handling

    def putContextMesh(myContextMesh_vertls, myContextMesh_facels, myContextMeshMaterials):
        bmesh = bpy.data.meshes.new(contextObName)

        if myContextMesh_facels is None:
            myContextMesh_facels = []

        if myContextMesh_vertls:

            bmesh.vertices.add(len(myContextMesh_vertls) // 3)
            bmesh.vertices.foreach_set("co", myContextMesh_vertls)

            nbr_faces = len(myContextMesh_facels)
            bmesh.polygons.add(nbr_faces)
            bmesh.loops.add(nbr_faces * 3)
            eekadoodle_faces = []
            for v1, v2, v3 in myContextMesh_facels:
                eekadoodle_faces.extend((v3, v1, v2) if v3 == 0 else (v1, v2, v3))
            bmesh.polygons.foreach_set("loop_start", range(0, nbr_faces * 3, 3))
            bmesh.polygons.foreach_set("loop_total", (3,) * nbr_faces)
            bmesh.loops.foreach_set("vertex_index", eekadoodle_faces)

            if bmesh.polygons and contextMeshUV:
                bmesh.uv_textures.new()
                uv_faces = bmesh.uv_textures.active.data[:]
            else:
                uv_faces = None

            for mat_idx, (matName, faces) in enumerate(myContextMeshMaterials):
                if matName is None:
                    bmat = None
                else:
                    bmat = MATDICT.get(matName)
                    # in rare cases no materials defined.
                    if bmat:
                        img = TEXTURE_DICT.get(bmat.name)
                    else:
                        print("    warning: material %r not defined!" % matName)
                        bmat = MATDICT[matName] = bpy.data.materials.new(matName)
                        img = None

                bmesh.materials.append(bmat)  # can be None

                if uv_faces  and img:
                    for fidx in faces:
                        bmesh.polygons[fidx].material_index = mat_idx
                        uv_faces[fidx].image = img
                else:
                    for fidx in faces:
                        bmesh.polygons[fidx].material_index = mat_idx

            if uv_faces:
                uvl = bmesh.uv_layers.active.data[:]
                for fidx, pl in enumerate(bmesh.polygons):
                    face = myContextMesh_facels[fidx]
                    v1, v2, v3 = face

                    # eekadoodle
                    if v3 == 0:
                        v1, v2, v3 = v3, v1, v2

                    uvl[pl.loop_start].uv = contextMeshUV[v1 * 2: (v1 * 2) + 2]
                    uvl[pl.loop_start + 1].uv = contextMeshUV[v2 * 2: (v2 * 2) + 2]
                    uvl[pl.loop_start + 2].uv = contextMeshUV[v3 * 2: (v3 * 2) + 2]
                    # always a tri

        bmesh.validate()
        bmesh.update()

        ob = bpy.data.objects.new(contextObName, bmesh)
        object_dictionary[contextObName] = ob
        SCN.objects.link(ob)
        importedObjects.append(ob)

        if contextMatrix_rot:
            ob.matrix_local = contextMatrix_rot
            object_matrix[ob] = contextMatrix_rot.copy()

    #a spare chunk
    new_chunk = chunk()
    temp_chunk = chunk()

    CreateBlenderObject = False

    def read_float_color(temp_chunk):
        temp_data = file.read(STRUCT_SIZE_3FLOAT)
        temp_chunk.bytes_read += STRUCT_SIZE_3FLOAT
        return [float(col) for col in struct.unpack('<3f', temp_data)]

    def read_float(temp_chunk):
        temp_data = file.read(STRUCT_SIZE_FLOAT)
        temp_chunk.bytes_read += STRUCT_SIZE_FLOAT
        return struct.unpack('<f', temp_data)[0]

    def read_short(temp_chunk):
        temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
        temp_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
        return struct.unpack('<H', temp_data)[0]

    def read_byte_color(temp_chunk):
        temp_data = file.read(struct.calcsize('3B'))
        temp_chunk.bytes_read += 3
        return [float(col) / 255 for col in struct.unpack('<3B', temp_data)]  # data [0,1,2] == rgb

    def read_texture(new_chunk, temp_chunk, name, mapto):
        new_texture = bpy.data.textures.new(name, type='IMAGE')

        u_scale, v_scale, u_offset, v_offset = 1.0, 1.0, 0.0, 0.0
        mirror = False
        extension = 'wrap'
        while (new_chunk.bytes_read < new_chunk.length):
            #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
            read_chunk(file, temp_chunk)

            if temp_chunk.ID == MAT_MAP_FILEPATH:
                texture_name, read_str_len = read_string(file)

                img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
                temp_chunk.bytes_read += read_str_len  # plus one for the null character that gets removed

            elif temp_chunk.ID == MAT_MAP_USCALE:
                u_scale = read_float(temp_chunk)
            elif temp_chunk.ID == MAT_MAP_VSCALE:
                v_scale = read_float(temp_chunk)

            elif temp_chunk.ID == MAT_MAP_UOFFSET:
                u_offset = read_float(temp_chunk)
            elif temp_chunk.ID == MAT_MAP_VOFFSET:
                v_offset = read_float(temp_chunk)

            elif temp_chunk.ID == MAT_MAP_TILING:
                tiling = read_short(temp_chunk)
                if tiling & 0x2:
                    extension = 'mirror'
                elif tiling & 0x10:
                    extension = 'decal'

            elif temp_chunk.ID == MAT_MAP_ANG:
                print("\nwarning: ignoring UV rotation")

            skip_to_end(file, temp_chunk)
            new_chunk.bytes_read += temp_chunk.bytes_read

        # add the map to the material in the right channel
        if img:
            add_texture_to_material(img, new_texture, (u_scale, v_scale),
                                    (u_offset, v_offset), extension, contextMaterial, mapto)

    dirname = os.path.dirname(file.name)

    #loop through all the data for this chunk (previous chunk) and see what it is
    while (previous_chunk.bytes_read < previous_chunk.length):
        #print '\t', previous_chunk.bytes_read, 'keep going'
        #read the next chunk
        #print 'reading a chunk'
        read_chunk(file, new_chunk)

        #is it a Version chunk?
        if new_chunk.ID == VERSION:
            #print 'if new_chunk.ID == VERSION:'
            #print 'found a VERSION chunk'
            #read in the version of the file
            #it's an unsigned short (H)
            temp_data = file.read(struct.calcsize('I'))
            version = struct.unpack('<I', temp_data)[0]
            new_chunk.bytes_read += 4  # read the 4 bytes for the version number
            #this loader works with version 3 and below, but may not with 4 and above
            if version > 3:
                print('\tNon-Fatal Error:  Version greater than 3, may not load correctly: ', version)

        #is it an object info chunk?
        elif new_chunk.ID == OBJECTINFO:
            #print 'elif new_chunk.ID == OBJECTINFO:'
            # print 'found an OBJECTINFO chunk'
            process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH)

            #keep track of how much we read in the main chunk
            new_chunk.bytes_read += temp_chunk.bytes_read

        #is it an object chunk?
        elif new_chunk.ID == OBJECT:

            if CreateBlenderObject:
                putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
                contextMesh_vertls = []
                contextMesh_facels = []

                ## preparando para receber o proximo objeto
                contextMeshMaterials = []  # matname:[face_idxs]
                contextMeshUV = None
                #contextMesh.vertexUV = 1 # Make sticky coords.
                # Reset matrix
                contextMatrix_rot = None
                #contextMatrix_tx = None

            CreateBlenderObject = True
            contextObName, read_str_len = read_string(file)
            new_chunk.bytes_read += read_str_len

        #is it a material chunk?
        elif new_chunk.ID == MATERIAL:

# 			print("read material")

            #print 'elif new_chunk.ID == MATERIAL:'
            contextMaterial = bpy.data.materials.new('Material')

        elif new_chunk.ID == MAT_NAME:
            #print 'elif new_chunk.ID == MAT_NAME:'
            material_name, read_str_len = read_string(file)

# 			print("material name", material_name)

            #plus one for the null character that ended the string
            new_chunk.bytes_read += read_str_len

            contextMaterial.name = material_name.rstrip()  # remove trailing  whitespace
            MATDICT[material_name] = contextMaterial

        elif new_chunk.ID == MAT_AMBIENT:
            #print 'elif new_chunk.ID == MAT_AMBIENT:'
            read_chunk(file, temp_chunk)
            if temp_chunk.ID == MAT_FLOAT_COLOR:
                contextMaterial.mirror_color = read_float_color(temp_chunk)
# 				temp_data = file.read(struct.calcsize('3f'))
# 				temp_chunk.bytes_read += 12
# 				contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
            elif temp_chunk.ID == MAT_24BIT_COLOR:
                contextMaterial.mirror_color = read_byte_color(temp_chunk)
# 				temp_data = file.read(struct.calcsize('3B'))
# 				temp_chunk.bytes_read += 3
# 				contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
            else:
                skip_to_end(file, temp_chunk)
            new_chunk.bytes_read += temp_chunk.bytes_read

        elif new_chunk.ID == MAT_DIFFUSE:
            #print 'elif new_chunk.ID == MAT_DIFFUSE:'
            read_chunk(file, temp_chunk)
            if temp_chunk.ID == MAT_FLOAT_COLOR:
                contextMaterial.diffuse_color = read_float_color(temp_chunk)
# 				temp_data = file.read(struct.calcsize('3f'))
# 				temp_chunk.bytes_read += 12
# 				contextMaterial.rgbCol = [float(col) for col in struct.unpack('<3f', temp_data)]
            elif temp_chunk.ID == MAT_24BIT_COLOR:
                contextMaterial.diffuse_color = read_byte_color(temp_chunk)
# 				temp_data = file.read(struct.calcsize('3B'))
# 				temp_chunk.bytes_read += 3
# 				contextMaterial.rgbCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
            else:
                skip_to_end(file, temp_chunk)

# 			print("read material diffuse color", contextMaterial.diffuse_color)

            new_chunk.bytes_read += temp_chunk.bytes_read

        elif new_chunk.ID == MAT_SPECULAR:
            #print 'elif new_chunk.ID == MAT_SPECULAR:'
            read_chunk(file, temp_chunk)
            if temp_chunk.ID == MAT_FLOAT_COLOR:
                contextMaterial.specular_color = read_float_color(temp_chunk)
# 				temp_data = file.read(struct.calcsize('3f'))
# 				temp_chunk.bytes_read += 12
# 				contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
            elif temp_chunk.ID == MAT_24BIT_COLOR:
                contextMaterial.specular_color = read_byte_color(temp_chunk)
# 				temp_data = file.read(struct.calcsize('3B'))
# 				temp_chunk.bytes_read += 3
# 				contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
            else:
                skip_to_end(file, temp_chunk)
            new_chunk.bytes_read += temp_chunk.bytes_read

        elif new_chunk.ID == MAT_TEXTURE_MAP:
            read_texture(new_chunk, temp_chunk, "Diffuse", "COLOR")

        elif new_chunk.ID == MAT_SPECULAR_MAP:
            read_texture(new_chunk, temp_chunk, "Specular", "SPECULARITY")

        elif new_chunk.ID == MAT_OPACITY_MAP:
            read_texture(new_chunk, temp_chunk, "Opacity", "ALPHA")

        elif new_chunk.ID == MAT_BUMP_MAP:
            read_texture(new_chunk, temp_chunk, "Bump", "NORMAL")

        elif new_chunk.ID == MAT_TRANSPARENCY:
            #print 'elif new_chunk.ID == MAT_TRANSPARENCY:'
            read_chunk(file, temp_chunk)
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)

            temp_chunk.bytes_read += 2
            contextMaterial.alpha = 1 - (float(struct.unpack('<H', temp_data)[0]) / 100)
            new_chunk.bytes_read += temp_chunk.bytes_read

        elif new_chunk.ID == OBJECT_LAMP:  # Basic lamp support.

            temp_data = file.read(STRUCT_SIZE_3FLOAT)

            x, y, z = struct.unpack('<3f', temp_data)
            new_chunk.bytes_read += STRUCT_SIZE_3FLOAT

            # no lamp in dict that would be confusing
            contextLamp[1] = bpy.data.lamps.new("Lamp", 'POINT')
            contextLamp[0] = ob = bpy.data.objects.new("Lamp", contextLamp[1])

            SCN.objects.link(ob)
            importedObjects.append(contextLamp[0])

            #print 'number of faces: ', num_faces
            #print x,y,z
            contextLamp[0].location = x, y, z

            # Reset matrix
            contextMatrix_rot = None
            #contextMatrix_tx = None
            #print contextLamp.name,

        elif new_chunk.ID == OBJECT_MESH:
            # print 'Found an OBJECT_MESH chunk'
            pass
        elif new_chunk.ID == OBJECT_VERTICES:
            '''
            Worldspace vertex locations
            '''
            # print 'elif new_chunk.ID == OBJECT_VERTICES:'
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            num_verts = struct.unpack('<H', temp_data)[0]
            new_chunk.bytes_read += 2

            # print 'number of verts: ', num_verts
            contextMesh_vertls = struct.unpack('<%df' % (num_verts * 3), file.read(STRUCT_SIZE_3FLOAT * num_verts))
            new_chunk.bytes_read += STRUCT_SIZE_3FLOAT * num_verts
            # dummyvert is not used atm!

            #print 'object verts: bytes read: ', new_chunk.bytes_read

        elif new_chunk.ID == OBJECT_FACES:
            # print 'elif new_chunk.ID == OBJECT_FACES:'
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            num_faces = struct.unpack('<H', temp_data)[0]
            new_chunk.bytes_read += 2
            #print 'number of faces: ', num_faces

            # print '\ngetting a face'
            temp_data = file.read(STRUCT_SIZE_4UNSIGNED_SHORT * num_faces)
            new_chunk.bytes_read += STRUCT_SIZE_4UNSIGNED_SHORT * num_faces  # 4 short ints x 2 bytes each
            contextMesh_facels = struct.unpack('<%dH' % (num_faces * 4), temp_data)
            contextMesh_facels = [contextMesh_facels[i - 3:i] for i in range(3, (num_faces * 4) + 3, 4)]

        elif new_chunk.ID == OBJECT_MATERIAL:
            # print 'elif new_chunk.ID == OBJECT_MATERIAL:'
            material_name, read_str_len = read_string(file)
            new_chunk.bytes_read += read_str_len  # remove 1 null character.

            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            num_faces_using_mat = struct.unpack('<H', temp_data)[0]
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT

            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * num_faces_using_mat)
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * num_faces_using_mat

            temp_data = struct.unpack("<%dH" % (num_faces_using_mat), temp_data)

            contextMeshMaterials.append((material_name, temp_data))

            #look up the material in all the materials

        elif new_chunk.ID == OBJECT_UV:
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            num_uv = struct.unpack('<H', temp_data)[0]
            new_chunk.bytes_read += 2

            temp_data = file.read(STRUCT_SIZE_2FLOAT * num_uv)
            new_chunk.bytes_read += STRUCT_SIZE_2FLOAT * num_uv
            contextMeshUV = struct.unpack('<%df' % (num_uv * 2), temp_data)

        elif new_chunk.ID == OBJECT_TRANS_MATRIX:
            # How do we know the matrix size? 54 == 4x4 48 == 4x3
            temp_data = file.read(STRUCT_SIZE_4x3MAT)
            data = list(struct.unpack('<ffffffffffff', temp_data))
            new_chunk.bytes_read += STRUCT_SIZE_4x3MAT

            contextMatrix_rot = mathutils.Matrix((data[:3] + [0],
                                                  data[3:6] + [0],
                                                  data[6:9] + [0],
                                                  data[9:] + [1],
                                                  )).transposed()

        elif  (new_chunk.ID == MAT_MAP_FILEPATH):
            texture_name, read_str_len = read_string(file)
            if contextMaterial.name not in TEXTURE_DICT:
                TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname, place_holder=False, recursive=IMAGE_SEARCH)

            new_chunk.bytes_read += read_str_len  # plus one for the null character that gets removed
        elif new_chunk.ID == EDITKEYFRAME:
            pass

        # including these here means their EK_OB_NODE_HEADER are scanned
        elif new_chunk.ID in {ED_KEY_AMBIENT_NODE,
                               ED_KEY_OBJECT_NODE,
                               ED_KEY_CAMERA_NODE,
                               ED_KEY_TARGET_NODE,
                               ED_KEY_LIGHT_NODE,
                               ED_KEY_L_TARGET_NODE,
                               ED_KEY_SPOTLIGHT_NODE}:  # another object is being processed
            child = None

        elif new_chunk.ID == EK_OB_NODE_HEADER:
            object_name, read_str_len = read_string(file)
            new_chunk.bytes_read += read_str_len
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * 2)
            new_chunk.bytes_read += 4
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            hierarchy = struct.unpack('<H', temp_data)[0]
            new_chunk.bytes_read += 2

            child = object_dictionary.get(object_name)

            if child is None:
                child = bpy.data.objects.new(object_name, None)  # create an empty object
                SCN.objects.link(child)
                importedObjects.append(child)

            object_list.append(child)
            object_parent.append(hierarchy)
            pivot_list.append(mathutils.Vector((0.0, 0.0, 0.0)))

        elif new_chunk.ID == EK_OB_INSTANCE_NAME:
            object_name, read_str_len = read_string(file)
            # child.name = object_name
            child.name += "." + object_name
            object_dictionary[object_name] = child
            new_chunk.bytes_read += read_str_len
            # print("new instance object:", object_name)

        elif new_chunk.ID == EK_OB_PIVOT:  # translation
                temp_data = file.read(STRUCT_SIZE_3FLOAT)
                pivot = struct.unpack('<3f', temp_data)
                new_chunk.bytes_read += STRUCT_SIZE_3FLOAT
                pivot_list[len(pivot_list) - 1] = mathutils.Vector(pivot)

        elif new_chunk.ID == EK_OB_POSITION_TRACK:  # translation
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 5
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * 5)
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            nkeys = struct.unpack('<H', temp_data)[0]
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 2
            for i in range(nkeys):
                temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
                nframe = struct.unpack('<H', temp_data)[0]
                new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
                temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * 2)
                new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 2
                temp_data = file.read(STRUCT_SIZE_3FLOAT)
                loc = struct.unpack('<3f', temp_data)
                new_chunk.bytes_read += STRUCT_SIZE_3FLOAT
                if nframe == 0:
                    child.location = loc

        elif new_chunk.ID == EK_OB_ROTATION_TRACK:  # rotation
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 5
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * 5)
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            nkeys = struct.unpack('<H', temp_data)[0]
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 2
            for i in range(nkeys):
                temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
                nframe = struct.unpack('<H', temp_data)[0]
                new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
                temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * 2)
                new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 2
                temp_data = file.read(STRUCT_SIZE_4FLOAT)
                rad, axis_x, axis_y, axis_z = struct.unpack("<4f", temp_data)
                new_chunk.bytes_read += STRUCT_SIZE_4FLOAT
                if nframe == 0:
                    child.rotation_euler = mathutils.Quaternion((axis_x, axis_y, axis_z), -rad).to_euler()   # why negative?

        elif new_chunk.ID == EK_OB_SCALE_TRACK:  # translation
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 5
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * 5)
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            nkeys = struct.unpack('<H', temp_data)[0]
            temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
            new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 2
            for i in range(nkeys):
                temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
                nframe = struct.unpack('<H', temp_data)[0]
                new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
                temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * 2)
                new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * 2
                temp_data = file.read(STRUCT_SIZE_3FLOAT)
                sca = struct.unpack('<3f', temp_data)
                new_chunk.bytes_read += STRUCT_SIZE_3FLOAT
                if nframe == 0:
                    child.scale = sca

        else:  # (new_chunk.ID!=VERSION or new_chunk.ID!=OBJECTINFO or new_chunk.ID!=OBJECT or new_chunk.ID!=MATERIAL):
            # print 'skipping to end of this chunk'
            #print("unknown chunk: "+hex(new_chunk.ID))
            buffer_size = new_chunk.length - new_chunk.bytes_read
            binary_format = "%ic" % buffer_size
            temp_data = file.read(struct.calcsize(binary_format))
            new_chunk.bytes_read += buffer_size

        #update the previous chunk bytes read
        # print 'previous_chunk.bytes_read += new_chunk.bytes_read'
        # print previous_chunk.bytes_read, new_chunk.bytes_read
        previous_chunk.bytes_read += new_chunk.bytes_read
        ## print 'Bytes left in this chunk: ', previous_chunk.length - previous_chunk.bytes_read

    # FINISHED LOOP
    # There will be a number of objects still not added
    if CreateBlenderObject:
        putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)

    # Assign parents to objects
    # check _if_ we need to assign first because doing so recalcs the depsgraph
    for ind, ob in enumerate(object_list):
        parent = object_parent[ind]
        if parent == ROOT_OBJECT:
            if ob.parent is not None:
                ob.parent = None
        else:
            if ob.parent != object_list[parent]:
                ob.parent = object_list[parent]

            # pivot_list[ind] += pivot_list[parent]  # XXX, not sure this is correct, should parent space matrix be applied before combining?
    # fix pivots
    for ind, ob in enumerate(object_list):
        if ob.type == 'MESH':
            pivot = pivot_list[ind]
            pivot_matrix = object_matrix.get(ob, mathutils.Matrix())  # unlikely to fail
            pivot_matrix = mathutils.Matrix.Translation(pivot_matrix.to_3x3() * -pivot)
            ob.data.transform(pivot_matrix)
Esempio n. 8
0
def get_mesh_string(obj, boneWeightCount):
    mesh = obj.to_mesh(bpy.context.scene, True, "PREVIEW")

    vertices = []
    normals = []
    tangents = []
    colors = []
    uvs = []
    bones = []
    boneIndices = []
    boneWeights = []

    vertex_number = -1
    for face in obj.data.polygons:
        vertices_in_face = face.vertices[:]

        for vertex in vertices_in_face:

            vertex_number += 1

            vertices.append(obj.data.vertices[vertex].co.x)
            vertices.append(obj.data.vertices[vertex].co.y)
            vertices.append(obj.data.vertices[vertex].co.z)

            normals.append(obj.data.vertices[vertex].normal.x)
            normals.append(obj.data.vertices[vertex].normal.y)
            normals.append(obj.data.vertices[vertex].normal.z)

    if len(mesh.tessface_uv_textures) > 0:
        for data in mesh.tessface_uv_textures.active.data:

            uvs.append(data.uv1.x)
            uvs.append(data.uv1.y)
            uvs.append(data.uv2.x)
            uvs.append(data.uv2.y)
            uvs.append(data.uv3.x)
            uvs.append(data.uv3.y)

    if len(mesh.tessface_vertex_colors) > 0:
        for data in mesh.tessface_vertex_colors.active.data:
            colors.append(data.color1.r)
            colors.append(data.color1.g)
            colors.append(data.color1.b)
            colors.append(data.color2.r)
            colors.append(data.color2.g)
            colors.append(data.color2.b)
            colors.append(data.color3.r)
            colors.append(data.color3.g)
            colors.append(data.color3.b)

    if (len(bpy.data.armatures) > 0):
        armature, armatureObject = get_armature()

        for face in obj.data.polygons:
            vertices_in_face = face.vertices[:]

            for vertex_index in vertices_in_face:
                vertex = obj.data.vertices[vertex_index]

                bone_array = []

                for group in vertex.groups:
                    index = group.group
                    weight = group.weight

                    bone_array.append([index, weight])

                bone_array.sort(key=operator.itemgetter(1), reverse=True)

                total_weight = 0.0
                for i in range(len(bone_array)):
                    total_weight += bone_array[i][1]
                for i in range(len(bone_array)):
                    bone_array[i][1] /= total_weight

                for i in range(boneWeightCount):
                    if i < len(bone_array):
                        bone_proxy = bone_array[i]

                        found = 0
                        index = bone_proxy[0]
                        weight = bone_proxy[1]

                        for j, bone in enumerate(armature.bones):
                            if obj.vertex_groups[index].name == bone.name:
                                boneIndices.append(j)
                                boneWeights.append(weight)
                                found = 1
                                break

                        if found != 1:
                            boneIndices.append(0)
                            boneWeights.append(0)

                    else:
                        boneIndices.append(0)
                        boneWeights.append(0)

        bone_id = -1
        for bone in armature.bones:
            bone_id += 1

            parent_index = -1
            weight = 0
            skinned = "0"
            name = bone.name

            matrix_local = bone.matrix_local
            pos = mathutils.Vector((1.0, 1.0, 1.0))
            rot = mathutils.Quaternion((0.0, 0.0, 0.0, 1.0))
            scl = mathutils.Vector((1.0, 1.0, 1.0))

            if bone.parent != None:
                parent_index = i = 0

                matrix_local = bone.parent.matrix_local.inverted(
                ) * matrix_local

                for parent in armature.bones:
                    if parent.name == bone.parent.name:
                        parent_index = i
                    i += 1

            pos, rot, scl = matrix_local.decompose()
            bindPose = bone.matrix_local

            j = -1
            for boneIndex in boneIndices:
                j += 1
                if int(boneIndex) == bone_id:
                    weight += float(boneWeights[j])

            if weight > 0:
                skinned = "1"

            bones.append(
                TEMPLATE_BONE % {
                    "parent":
                    parent_index,
                    "name":
                    name,
                    "skinned":
                    skinned,
                    "bindPose":
                    mat4_string(bindPose.inverted()),
                    "position":
                    ", ".join(
                        [float_str(pos.x),
                         float_str(pos.y),
                         float_str(pos.z)]),
                    "rotation":
                    ", ".join([
                        float_str(rot.x),
                        float_str(rot.y),
                        float_str(rot.z),
                        float_str(rot.w)
                    ]),
                    "scale":
                    ", ".join(
                        [float_str(scl.x),
                         float_str(scl.y),
                         float_str(scl.z)])
                })

    return TEMPLATE_FILE % {
        "vertices": flat_array(vertices),
        "normals": flat_array(normals),
        "colors": flat_array(colors),
        "uvs": flat_array(uvs),
        "bones": ",".join(bones),
        "boneWeightCount": str(boneWeightCount),
        "boneIndices": flat_array(boneIndices),
        "boneWeights": flat_array(boneWeights)
    }
Esempio n. 9
0
import mathutils
import math
import bmesh
import threading
import socket
import queue

from bpy.props import (
    BoolProperty,
    StringProperty,
    FloatProperty,
    PointerProperty
    )


ROTATE_X_90 = mathutils.Quaternion((1.0, 0.0, 0.0), math.radians(90.0))

def unity_quaternion_to_blender(w, x, y, z):
    return ROTATE_X_90 @ mathutils.Quaternion((-float(w), float(x), float(y), -float(z)))

### IMPORT ###


def import_ar_recording(context, report,
        filepath,
        include_camera, include_cloud, include_planes,
        include_camera_position, include_camera_rotation,
        *args, **kwargs):
    scene = context.scene
    fps = scene.render.fps
    start_time = None
Esempio n. 10
0
def FM_constraints(ob):

    # Pseudo code for special constraint treatment:
    #
    # If tol1dist or tol1rot is exceeded:
    #     If normal constraint: It will be detached
    #     If spring constraint: It will be set to active
    # If tol2dist or tol2rot is exceeded:
    #     If spring constraint: It will be detached

    print()
    print("Creating Fracture Modifier constraints from BCB data...")
    time_const = time.time()

    scene = bpy.context.scene

    md = ob.modifiers["Fracture"]
    fmode_bak = md.fracture_mode
    md.fracture_mode = 'EXTERNAL'

    ### Create dict of FM mesh islands (speed optimization)
    mesh_islands = {}
    for mi in md.mesh_islands:
        mesh_islands[mi.name] = mi

    ### Unpack BCB data from text file
    try:
        s = bpy.data.texts[asciiExportName + ".txt"].as_string()
    except:
        print(
            "Error: No export data found, couldn't build Fracture Modifier object."
        )
        return
    cDef, exData, exPairs, objNames = pickle.loads(
        zlib.decompress(base64.decodestring(s.encode())))

    ### Overwrite mesh island settings with those from the original RBs (FM overwrites this state)
    #    # Remove refresh handler from memory (required to overwrite settings)
    #    if len(bpy.app.handlers.fracture_refresh) > 0:
    #        bpy.app.handlers.fracture_refresh.clear()
    #        qHandler = 1
    #    else: qHandler = 0
    # Overwrite mesh island settings
    for mi in md.mesh_islands:
        obj_rb = scene.objects[mi.name].rigid_body
        #print("mass", mi.rigidbody.mass, mi.name)
        mi.rigidbody.type = obj_rb.type
        mi.rigidbody.kinematic = obj_rb.kinematic
        mi.rigidbody.collision_shape = obj_rb.collision_shape
        mi.rigidbody.mass = obj_rb.mass
        mi.rigidbody.friction = obj_rb.friction
        mi.rigidbody.restitution = obj_rb.restitution
        mi.rigidbody.use_margin = obj_rb.use_margin
        mi.rigidbody.collision_margin = obj_rb.collision_margin

#    # Reload refresh handler
#    if qHandler:
#        bpy.app.handlers.fracture_refresh.append(FM_shards)

### Copy custom (not BCB generated) constraints between original shards to the FM
    try:
        emptyObjs = bpy.data.groups["RigidBodyConstraints"].objects
    except:
        emptyObjs = []
    emptyObjs = [
        obj for obj in emptyObjs if obj.type == 'EMPTY' and not obj.hide and
        obj.is_visible(bpy.context.scene) and obj.rigid_body_constraint != None
    ]
    for objConst in emptyObjs:
        if "BCB_FM" not in objConst.keys():
            objA = objConst.rigid_body_constraint.object1
            objB = objConst.rigid_body_constraint.object2
            if objA != None and objB != None \
            and objA.name in objNames and objB.name in objNames:
                cProps = getAttribsOfConstraint(objConst.rigid_body_constraint)
                ### Add settings to constraint
                try:
                    con = md.mesh_constraints.new(mesh_islands[objA.name],
                                                  mesh_islands[objB.name],
                                                  cProps["type"])
                except:
                    pass
                else:
                    objConst["BCB_FM"] = 1  # Mark empty as used in FM
                    con.name = objConst.name
                    con.location = objConst.location
                    if objConst.rotation_mode == "QUATERNION":
                        con.rotation = objConst.rotation_quaternion
                    else:
                        con.rotation = objConst.rotation_euler.to_quaternion()
                    ### Write constraint parameters
                    for p in cProps.items():
                        if p[0] not in {"object1", "object2"}:
                            try:
                                attr = getattr(con, p[0])  # Current value
                            except:
                                if p[0] not in missingAttribs:
                                    missingAttribs.append(p[0])
                            else:
                                if p[1] != attr:  # Overwrite only when different
                                    #print("Set: ", p[0], p[1])
                                    setattr(con, p[0], p[1])

    ### Create BCB constraints
    cnt = 0
    missingAttribs = []
    for pair in exPairs:
        ### Get data that is only stored once per connection
        ob1 = pair[0]
        ob2 = pair[1]
        consts = pair[2]

        for const in consts:
            cProps, cDatb = exData[const]

            ### Get data that can be individual for each constraint
            name = cDatb[
                0]  # A name is not mandatory, mainly for debugging purposes
            loc = cDatb[1]
            tol1 = cDatb[4]
            tol2 = cDatb[5]
            rotm = cDatb[6]
            rot = cDatb[7]
            try:
                type = cProps["type"]
            except:
                type = cDef["type"]

            ### Decode custom BCB attributes
            # 1st tolerances (elastic -> plastic)
            # ["TOLERANCE", tol1dist, tol1rot]
            if tol1 is not None and tol1[0] in {"TOLERANCE"}:
                tol1dist = tol1[1]
                tol1rot = tol1[2]
            else:
                tol1dist = -1
                tol1rot = -1
            # 2nd tolerances (plastic -> broken)
            # ["PLASTIC"/"PLASTIC_OFF", tol2dist, tol2rot]
            if tol2 is not None and tol2[0] in {"PLASTIC", "PLASTIC_OFF"}:
                tol2dist = tol2[1]
                tol2rot = tol2[2]
                if tol2[0] == "PLASTIC": plastic = True
                else: plastic = False
            else:
                tol2dist = -1
                tol2rot = -1
                plastic = False

            # Rotation
            if rotm == "QUATERNION":  # If no quaternion exists we assume no rotation is available
                rot = mathutils.Quaternion(rot)
            else:  # If None or EULER then no rotation is available
                rot = mathutils.Quaternion((1.0, 0.0, 0.0, 0.0))

            ### Add settings to constraint
            try:
                con = md.mesh_constraints.new(mesh_islands[ob1],
                                              mesh_islands[ob2], type)
            except:
                pass
            else:
                con.name = name
                con.location = loc
                con.rotation = rot
                con.plastic = plastic
                con.breaking_distance = tol1dist
                con.breaking_angle = tol1rot
                con.plastic_distance = tol2dist
                con.plastic_angle = tol2rot

                ### Obsolete since FM now uses Blender defaults for constraints:
                ### Write constraint defaults first (FM doesn't set constraint to Blender defaults)
                for p in cDef.items():
                    if p[0] not in {"object1", "object2"}:
                        try:
                            attr = getattr(con, p[0])  # Current value
                        except:
                            if p[0] not in missingAttribs:
                                missingAttribs.append(p[0])
                        else:
                            if p[1] != attr:  # Overwrite only when different
                                #print("attr", p[0], p[1], attr)
                                setattr(con, p[0], p[1])
                ### Write own changed parameters (because it's a diff based on defaults)
                for p in cProps.items():
                    if p[0] not in {"object1", "object2"}:
                        try:
                            attr = getattr(con, p[0])  # Current value
                        except:
                            if p[0] not in missingAttribs:
                                missingAttribs.append(p[0])
                        else:
                            if p[1] != attr:  # Overwrite only when different
                                #print("Set: ", p[0], p[1])
                                setattr(con, p[0], p[1])
                cnt += 1

    if len(missingAttribs):
        print("Warning: Following constraint attribute(s) missing:")
        print(
            "(This is a bug in FM, branch seems not to be up to date with Blender.)"
        )
        for attr in missingAttribs:
            print(attr)

    md.fracture_mode = fmode_bak
    md.refresh = False

    print('Time constraints: %0.2f s' % (time.time() - time_const))
    print('Imported: %d constraints (%d shards)' % (cnt, len(md.mesh_islands)))

    # Remove this handler from memory (will be reloaded on FM_shards())
    bpy.app.handlers.fracture_constraint_refresh.clear()
Esempio n. 11
0
_obj = bpy.data.objects.new('obj111', _msh)

_verts = [(-2, -2, -2), (2, -2, -2), (0, 2, -2), (0, 0, 2)]
_verts = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]
_edgs = []  # [(0,1),(1,2),(2,0),(0,3),(1,3),(2,3)]
_fcs = [(0, 2, 1), (0, 1, 3), (1, 2, 3), (2, 0, 3)]

_verts = [
    (-1, -1, 0),
    (-1, 1, 0),
    (1, 1, 0),
    (1, -1, 0),
    (0, 0, 2),
]
_edgs = []
_fcs = [(0, 3, 2, 1), (0, 1, 4), (1, 2, 4), (2, 3, 4), (3, 0, 4)]

for i in range(len(_verts)):
    v = mathutils.Vector(_verts[i])
    _verts[i] = v

_msh.from_pydata(_verts, _edgs, _fcs)
_msh.validate()
bpy.context.scene.collection.objects.link(_obj)

_obj.rotation_mode = 'QUATERNION'
_obj.rotation_quaternion = mathutils.Quaternion(
    (0.4, 0.4, 0.4, math.sqrt(1 - 3 * 0.16)))
_obj.location = mathutils.Vector((0.1, 0.1, 0.1))
_obj.scale = mathutils.Vector((0.1, 0.1, 0.1))
Esempio n. 12
0
camera_data.sensor_width = 36
camera_data.sensor_height = 24

# Creamos el objeto de camara con los datos
camera_object = bpy.data.objects.new("Camera", camera_data)

# Cambiamos la camara activa
# > Localizacion
camera_object.location = mathutils.Vector(
    (float(parameters["location"]["x"]), float(parameters["location"]["y"]),
     float(parameters["location"]["z"])))

# > Rotacion (cuaterniones)
camera_object.rotation_mode = "QUATERNION"
camera_object.rotation_quaternion = mathutils.Quaternion(
    (float(parameters["qua"]["_w"]), float(parameters["qua"]["_x"]),
     float(parameters["qua"]["_y"]), float(parameters["qua"]["_z"])))

# Añadimos la camara a la escena
bpy.context.scene.collection.objects.link(camera_object)

# Ponemos la nueva camara como camara activa
bpy.context.scene.camera = camera_object

# Parametros de renderizado
# Transformacion del color filmica
bpy.context.scene.view_settings.view_transform = "Filmic"
bpy.context.scene.view_settings.look = "Medium Contrast"

bpy.context.scene.render.threads = 2
 def apply_to_frame(self, coord_system):
     assert isinstance(coord_system, CoordSystem)
     rotation = mathutils.Quaternion(self.axis, self.angle).to_matrix() * coord_system.orientation.to_matrix()
     return CoordSystem(coord_system.position + self.translation, rotation.to_quaternion().normalized())
################################################################

print(
    "==============================================================================="
)

armature = bpy.data.objects[armature_name]
action = armature.animation_data.action
fcurves = action.fcurves

rot_diffs = {}
for k in range(len(fcurves) // FCURVE_INFO_SIZE_PER_BONE):
    rot_idx = k * FCURVE_INFO_SIZE_PER_BONE + FCURVE_ROT_OFFSET
    src_ori = mathutils.Quaternion(
        (fcurves[rot_idx + 0].keyframe_points[0].co[1],
         fcurves[rot_idx + 1].keyframe_points[0].co[1],
         fcurves[rot_idx + 2].keyframe_points[0].co[1],
         fcurves[rot_idx + 3].keyframe_points[0].co[1]))
    dst_ori = mathutils.Quaternion(
        (fcurves[rot_idx + 0].keyframe_points[-1].co[1],
         fcurves[rot_idx + 1].keyframe_points[-1].co[1],
         fcurves[rot_idx + 2].keyframe_points[-1].co[1],
         fcurves[rot_idx + 3].keyframe_points[-1].co[1]))
    rot_diffs[rot_idx] = src_ori.rotation_difference(dst_ori)

for k in range(len(fcurves) // FCURVE_INFO_SIZE_PER_BONE):
    rot_idx = k * FCURVE_INFO_SIZE_PER_BONE + FCURVE_ROT_OFFSET
    num_frames = len(fcurves[rot_idx].keyframe_points)
    for i in range(num_frames - 1):
        ori = mathutils.Quaternion(
            (fcurves[rot_idx + 0].keyframe_points[i].co[1],
Esempio n. 15
0
	def explicit_rot(self, b, final, initial): 

		q = self.substract_rot(final, initial)
		null_rot = m.Quaternion((1.,0.,0.,0.))
		if q != null_rot: 
			print('self.rotate(\'{}\', m.Quaternion(({:.4f},{:.4f},{:.4f},{:.4f})))'.format(b, q.w,q.x,q.y,q.z))
Esempio n. 16
0
def unity_quaternion_to_blender(w, x, y, z):
    return ROTATE_X_90 @ mathutils.Quaternion((-float(w), float(x), float(y), -float(z)))
Esempio n. 17
0
	def test(self): 	

		self.armature.animation_data_create()
		self.armature.animation_data.action = bpy.data.actions.new(name = 'Run')
		reset_all()
		set_frame(1)

		self.move('footL', m.Vector((0.0000,-0.2786,0.4208)))
		self.move('footR', m.Vector((0.0000,0.2193,0.0000)))
		self.move('armL', m.Vector((-0.8331,0.0000,-0.8861)))
		self.move('armR', m.Vector((0.8090,0.0000,-0.9342)))
		self.rotate('pelvis', m.Quaternion((0.9610,-0.2493,-0.0302,-0.1163)))
		self.move('pelvis', m.Vector((0.0000,-0.0296,-0.1126)))
		self.rotate('spine1', m.Quaternion((0.9541,0.2909,-0.0625,0.0347)))
		self.rotate('spine2', m.Quaternion((0.9782,0.2017,-0.0433,0.0241)))
		self.rotate('head', m.Quaternion((1.0000,0.0000,-0.0000,0.0000)))

		confirm_animation_pose()
		add_frames(10)

		self.rotate('footL', m.Quaternion((0.9386,-0.3451,-0.0000,0.0000)))
		self.move('footL', m.Vector((0.0000,-0.5173,0.1142)))
		self.rotate('footR', m.Quaternion((-0.7016,-0.7126,-0.0000,0.0000)))
		self.move('footR', m.Vector((0.0000,0.5630,0.3252)))
		self.move('armL', m.Vector((-0.8331,0.5658,-0.6814)))
		self.move('armR', m.Vector((0.8090,-0.6300,-0.8901)))
		self.rotate('pelvis', m.Quaternion((0.9610,-0.2493,-0.0302,-0.1163)))
		self.move('pelvis', m.Vector((0.0000,-0.0296,-0.1126)))
		self.rotate('spine1', m.Quaternion((0.9541,0.2909,-0.0625,0.0347)))
		self.rotate('spine2', m.Quaternion((0.9782,0.2017,-0.0433,0.0241)))
		self.rotate('head', m.Quaternion((1.0000,0.0000,-0.0000,0.0000)))

		confirm_animation_pose()
		add_frames(10)

		self.move('footL', m.Vector((0.0000,0.2193,0.0000)))
		self.move('footR', m.Vector((0.0000,-0.2786,0.4208)))
		self.move('armL', m.Vector((-0.8090,0.0000,-0.9342)))
		self.move('armR', m.Vector((0.8331,0.0000,-0.8861)))
		self.rotate('pelvis', m.Quaternion((0.9610,-0.2493,0.0302,0.1163)))
		self.move('pelvis', m.Vector((0.0000,-0.0296,-0.1126)))
		self.rotate('spine1', m.Quaternion((0.9541,0.2909,0.0625,-0.0347)))
		self.rotate('spine2', m.Quaternion((0.9782,0.2017,0.0433,-0.0241)))
		self.rotate('head', m.Quaternion((1.0000,0.0000,0.0000,-0.0000)))

		confirm_animation_pose()
Esempio n. 18
0
def import_armature(data):
    """Scans an armature hierarchy, and returns a whole armature.
	This is done outside the normal node tree scan to allow for positioning
	of the bones before skins are attached."""
    bone_info = data.bone_info
    if bone_info:
        # armature_name = "Test"
        # b_armature_data = bpy.data.armatures.new(armature_name)
        # b_armature_data.display_type = 'STICK'
        # b_armature_data.show_axes = True
        # # set axis orientation for export
        # # b_armature_data.niftools.axis_forward = NifOp.props.axis_forward
        # # b_armature_data.niftools.axis_up = NifOp.props.axis_up
        # b_armature_obj = create_ob(armature_name, b_armature_data)
        # b_armature_obj.show_in_front = True
        # # LOD(b_armature_obj, 10)
        # bone_names = [matrix_util.bone_name_for_blender(n) for n in data.bone_names]
        # # print(bone_names)
        # # print("ovl order")
        # # make armature editable and create bones
        # bpy.ops.object.mode_set(mode='EDIT', toggle=False)
        # for bone_name, o_mat, o_parent_ind in zip(bone_names, bone_info.inverse_bind_matrices, bone_info.bone_parents):
        # 	# print(bone_name)
        # 	# create a new bone
        # 	if not bone_name:
        # 		bone_name = "Dummy"
        # 	b_edit_bone = b_armature_data.edit_bones.new(bone_name)
        # 	# get armature space matrix in blender's coordinate space
        # 	# n_bind = matrix_util.import_matrix(o_mat).inverted()
        # 	# it should not be needed once we are sure we read the right matrices
        # 	raw_mat = matrix_util.import_matrix(o_mat)
        # 	# print(bone_name, list(int(round(math.degrees(x))) for x in raw_mat.to_euler()))
        # 	# print(bone_name, list(int(round(math.degrees(x))) for x in raw_mat.inverted().to_euler()), "inv")
        # 	n_bind = raw_mat.inverted_safe()
        # 	b_bind = matrix_util.nif_bind_to_blender_bind(n_bind)
        # 	# the following is a workaround because blender can no longer set matrices to bones directly
        # 	tail, roll = matrix_util.mat3_to_vec_roll(b_bind.to_3x3())
        # 	b_edit_bone.head = b_bind.to_translation()
        # 	b_edit_bone.tail = tail + b_edit_bone.head
        # 	b_edit_bone.roll = roll
        # 	# link to parent
        # 	try:
        # 		if o_parent_ind != 255:
        # 			b_parent_bone = b_armature_data.edit_bones[bone_names[o_parent_ind]]
        # 			b_edit_bone.parent = b_parent_bone
        # 	except:
        # 		pass
        #
        # fix_bone_lengths(b_armature_data)
        # bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

        armature_name = "Test"
        b_armature_data = bpy.data.armatures.new(armature_name)
        b_armature_data.display_type = 'STICK'
        # b_armature_data.show_axes = True
        # set axis orientation for export
        # b_armature_data.niftools.axis_forward = NifOp.props.axis_forward
        # b_armature_data.niftools.axis_up = NifOp.props.axis_up
        b_armature_obj = create_ob(armature_name, b_armature_data)
        b_armature_obj.show_in_front = True
        # LOD(b_armature_obj, 10)
        bone_names = [
            matrix_util.bone_name_for_blender(n) for n in data.bone_names
        ]
        # make armature editable and create bones
        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
        mats = {}
        bones = bone_info.jwe_bones if bone_info.jwe_bones else bone_info.pz_bones
        for bone_name, bone, o_parent_ind in zip(bone_names, bones,
                                                 bone_info.bone_parents):
            if not bone_name:
                bone_name = "Dummy"
            b_edit_bone = b_armature_data.edit_bones.new(bone_name)

            # local space matrix, in ms2 orientation
            n_bind = mathutils.Quaternion((bone.rot.w, bone.rot.x, bone.rot.y,
                                           bone.rot.z)).to_matrix().to_4x4()
            n_bind.translation = (bone.loc.x, bone.loc.y, bone.loc.z)

            # link to parent
            try:
                if o_parent_ind != 255:
                    parent_name = bone_names[o_parent_ind]
                    b_parent_bone = b_armature_data.edit_bones[parent_name]
                    b_edit_bone.parent = b_parent_bone
                    # calculate ms2 armature space matrix
                    n_bind = mats[parent_name] @ n_bind
            except:
                print(
                    f"Bone hierarchy error for bone {bone_name} with parent index {o_parent_ind}"
                )

            # store the ms2 armature space matrix
            mats[bone_name] = n_bind

            print()
            print(bone_name)
            print("ms2\n", n_bind)
            # change orientation for blender bones
            b_bind = matrix_util.nif_bind_to_blender_bind(n_bind)
            # b_bind = n_bind
            # print("n_bindxflip")
            # print(matrix_util.xflip @ n_bind)
            # set orientation to blender bone
            tail, roll = bpy.types.Bone.AxisRollFromMatrix(b_bind.to_3x3())
            b_edit_bone.head = b_bind.to_translation()
            b_edit_bone.tail = tail + b_edit_bone.head
            b_edit_bone.roll = roll
            print("bbind\n", b_bind, "\noutput\n",
                  matrix_util.blender_bind_to_nif_bind(b_edit_bone.matrix),
                  "\nb edit\n", matrix_util.xflipper(b_edit_bone.matrix))
            #print(n_bind - matrix_util.blender_bind_to_nif_bind(b_edit_bone.matrix))

        fix_bone_lengths(b_armature_data)
        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

        # print("blender order")
        # for bone in b_armature_data.bones:
        # 	print(bone.name)
        # print("restored order")
        # bone_names_restored = ovl_bones(b_armature_data)
        # for bone in bone_names_restored:
        # 	print(bone)

        for i, bone_name in enumerate(bone_names):
            # print(i, bone_name)
            bone = b_armature_obj.pose.bones[bone_name]
            # bone = b_armature_data.bones[bone_name]
            bone["index"] = i

        return b_armature_obj
Esempio n. 19
0
def convert_swizzle_rotation(rot):
    """
    Converts a quaternion rotation from Blender coordinate system to glTF coordinate system.
    'w' is still at first position.
    """
    return mathutils.Quaternion((rot[0], rot[1], rot[3], -rot[2]))
Esempio n. 20
0
    def import_constraint(self, hkbody):
        """Imports a bone havok constraint as Blender object constraint."""
        assert (isinstance(hkbody, NifFormat.bhkRigidBody))

        # check for constraints
        if not hkbody.constraints:
            return

        # find objects
        if len(collision.DICT_HAVOK_OBJECTS[hkbody]) != 1:
            NifLog.warn(
                "Rigid body with no or multiple shapes, constraints skipped")
            return

        b_hkobj = collision.DICT_HAVOK_OBJECTS[hkbody][0]

        NifLog.info(f"Importing constraints for b_hkobj.name")

        # now import all constraints
        for hkconstraint in hkbody.constraints:

            # check constraint entities
            if not hkconstraint.num_entities == 2:
                NifLog.warn("Constraint with more than 2 entities, skipped")
                continue
            if not hkconstraint.entities[0] is hkbody:
                NifLog.warn("First constraint entity not self, skipped")
                continue
            if not hkconstraint.entities[1] in collision.DICT_HAVOK_OBJECTS:
                NifLog.warn("Second constraint entity not imported, skipped")
                continue

            # get constraint descriptor
            if isinstance(hkconstraint, NifFormat.bhkRagdollConstraint):
                hkdescriptor = hkconstraint.ragdoll
                b_hkobj.rigid_body.enabled = True
            elif isinstance(hkconstraint, NifFormat.bhkLimitedHingeConstraint):
                hkdescriptor = hkconstraint.limited_hinge
                b_hkobj.rigid_body.enabled = True
            elif isinstance(hkconstraint, NifFormat.bhkHingeConstraint):
                hkdescriptor = hkconstraint.hinge
                b_hkobj.rigid_body.enabled = True
            elif isinstance(hkconstraint, NifFormat.bhkMalleableConstraint):
                if hkconstraint.type == 7:
                    hkdescriptor = hkconstraint.ragdoll
                    b_hkobj.rigid_body.enabled = False
                elif hkconstraint.type == 2:
                    hkdescriptor = hkconstraint.limited_hinge
                    b_hkobj.rigid_body.enabled = False
                else:
                    NifLog.warn(
                        f"Unknown malleable type ({hkconstraint.type:s}), skipped"
                    )
                # TODO [constraint][flag] Damping parameters not yet in Blender Python API
                # TODO [constraint][flag] tau (force between bodies) not supported by Blender
            else:
                NifLog.warn(
                    f"Unknown constraint type ({hkconstraint.__class__.__name__}), skipped"
                )
                continue

            # todo [constraints] the following is no longer possible, fixme
            return

            # add the constraint as a rigid body joint
            b_constr = b_hkobj.constraints.new('RIGID_BODY_JOINT')
            b_constr.name = b_hkobj.name
            b_constr.show_pivot = True

            # note: rigidbodyjoint parameters (from Constraint.c)
            # CONSTR_RB_AXX 0.0
            # CONSTR_RB_AXY 0.0
            # CONSTR_RB_AXZ 0.0
            # CONSTR_RB_EXTRAFZ 0.0
            # CONSTR_RB_MAXLIMIT0 0.0
            # CONSTR_RB_MAXLIMIT1 0.0
            # CONSTR_RB_MAXLIMIT2 0.0
            # CONSTR_RB_MAXLIMIT3 0.0
            # CONSTR_RB_MAXLIMIT4 0.0
            # CONSTR_RB_MAXLIMIT5 0.0
            # CONSTR_RB_MINLIMIT0 0.0
            # CONSTR_RB_MINLIMIT1 0.0
            # CONSTR_RB_MINLIMIT2 0.0
            # CONSTR_RB_MINLIMIT3 0.0
            # CONSTR_RB_MINLIMIT4 0.0
            # CONSTR_RB_MINLIMIT5 0.0
            # CONSTR_RB_PIVX 0.0
            # CONSTR_RB_PIVY 0.0
            # CONSTR_RB_PIVZ 0.0
            # CONSTR_RB_TYPE 12
            # LIMIT 63
            # PARSIZEY 63
            # TARGET [Object "capsule.002"]

            # limit 3, 4, 5 correspond to angular limits along x, y and z
            # and are measured in degrees

            # pivx/y/z is the pivot point

            # set constraint target
            b_constr.target = collision.DICT_HAVOK_OBJECTS[
                hkconstraint.entities[1]][0]
            # set rigid body type (generic)
            b_constr.pivot_type = 'GENERIC_6_DOF'
            # limiting parameters (limit everything)
            b_constr.use_angular_limit_x = True
            b_constr.use_angular_limit_y = True
            b_constr.use_angular_limit_z = True

            # get pivot point
            pivot = mathutils.Vector(
                (hkdescriptor.pivot_b.x, hkdescriptor.pivot_b.y,
                 hkdescriptor.pivot_b.z)) * self.HAVOK_SCALE

            # get z- and x-axes of the constraint
            # (also see export_nif.py NifImport.export_constraints)
            if isinstance(hkdescriptor, NifFormat.RagdollDescriptor):
                b_constr.pivot_type = 'CONE_TWIST'
                # for ragdoll, take z to be the twist axis (central axis of the
                # cone, that is)
                axis_z = mathutils.Vector(
                    (hkdescriptor.twist_a.x, hkdescriptor.twist_a.y,
                     hkdescriptor.twist_a.z))
                # for ragdoll, let x be the plane vector
                axis_x = mathutils.Vector(
                    (hkdescriptor.plane_a.x, hkdescriptor.plane_a.y,
                     hkdescriptor.plane_a.z))
                # set the angle limits
                # (see http://niftools.sourceforge.net/wiki/Oblivion/Bhk_Objects/Ragdoll_Constraint
                # for a nice picture explaining this)
                b_constr.limit_angle_min_x = hkdescriptor.plane_min_angle
                b_constr.limit_angle_max_x = hkdescriptor.plane_max_angle

                b_constr.limit_angle_min_y = -hkdescriptor.cone_max_angle
                b_constr.limit_angle_max_y = hkdescriptor.cone_max_angle

                b_constr.limit_angle_min_z = hkdescriptor.twist_min_angle
                b_constr.limit_angle_max_z = hkdescriptor.twist_max_angle

                b_hkobj.niftools_constraint.LHMaxFriction = hkdescriptor.max_friction

            elif isinstance(hkdescriptor, NifFormat.LimitedHingeDescriptor):
                # for hinge, y is the vector on the plane of rotation defining
                # the zero angle
                axis_y = mathutils.Vector((hkdescriptor.perp_2_axle_in_a_1.x,
                                           hkdescriptor.perp_2_axle_in_a_1.y,
                                           hkdescriptor.perp_2_axle_in_a_1.z))
                # for hinge, take x to be the the axis of rotation
                # (this corresponds with Blender's convention for hinges)
                axis_x = mathutils.Vector(
                    (hkdescriptor.axle_a.x, hkdescriptor.axle_a.y,
                     hkdescriptor.axle_a.z))
                # for hinge, z is the vector on the plane of rotation defining
                # the positive direction of rotation
                axis_z = mathutils.Vector((hkdescriptor.perp_2_axle_in_a_2.x,
                                           hkdescriptor.perp_2_axle_in_a_2.y,
                                           hkdescriptor.perp_2_axle_in_a_2.z))
                # they should form a orthogonal basis
                if (mathutils.Vector.cross(axis_x, axis_y) -
                        axis_z).length > 0.01:
                    # either not orthogonal, or negative orientation
                    if (mathutils.Vector.cross(-axis_x, axis_y) -
                            axis_z).length > 0.01:
                        NifLog.warn(
                            f"Axes are not orthogonal in {hkdescriptor.__class__.__name__}; Arbitrary orientation has been chosen"
                        )
                        axis_z = mathutils.Vector.cross(axis_x, axis_y)
                    else:
                        # fix orientation
                        NifLog.warn(
                            f"X axis flipped in {hkdescriptor.__class__.__name__} to fix orientation"
                        )
                        axis_x = -axis_x
                # getting properties with no blender constraint equivalent and setting as obj properties
                b_constr.limit_angle_max_x = hkdescriptor.max_angle
                b_constr.limit_angle_min_x = hkdescriptor.min_angle
                b_hkobj.niftools_constraint.LHMaxFriction = hkdescriptor.max_friction

                if hasattr(hkconstraint, "tau"):
                    b_hkobj.niftools_constraint.tau = hkconstraint.tau
                    b_hkobj.niftools_constraint.damping = hkconstraint.damping

            elif isinstance(hkdescriptor, NifFormat.HingeDescriptor):
                # for hinge, y is the vector on the plane of rotation defining
                # the zero angle
                axis_y = mathutils.Vector((hkdescriptor.perp_2_axle_in_a_1.x,
                                           hkdescriptor.perp_2_axle_in_a_1.y,
                                           hkdescriptor.perp_2_axle_in_a_1.z))
                # for hinge, z is the vector on the plane of rotation defining
                # the positive direction of rotation
                axis_z = mathutils.Vector((hkdescriptor.perp_2_axle_in_a_2.x,
                                           hkdescriptor.perp_2_axle_in_a_2.y,
                                           hkdescriptor.perp_2_axle_in_a_2.z))
                # take x to be the the axis of rotation
                # (this corresponds with Blender's convention for hinges)
                axis_x = mathutils.Vector.cross(axis_y, axis_z)
                b_hkobj.niftools_constraint.LHMaxFriction = hkdescriptor.max_friction
            else:
                raise ValueError("Unknown descriptor {0}".format(
                    hkdescriptor.__class__.__name__))

            # transform pivot point and constraint matrix into object
            # coordinates
            # (also see export_nif.py NifImport.export_constraints)

            # the pivot point v is in hkbody coordinates
            # however blender expects it in object coordinates, v'
            # v * R * B = v' * O * T * B'
            # with R = rigid body transform (usually unit tf)
            # B = nif bone matrix
            # O = blender object transform
            # T = bone tail matrix (translation in Y direction)
            # B' = blender bone matrix
            # so we need to cancel out the object transformation by
            # v' = v * R * B * B'^{-1} * T^{-1} * O^{-1}

            # the local rotation L at the pivot point must be such that
            # (axis_z + v) * R * B = ([0 0 1] * L + v') * O * T * B'
            # so (taking the rotation parts of all matrices!!!)
            # [0 0 1] * L = axis_z * R * B * B'^{-1} * T^{-1} * O^{-1}
            # and similarly
            # [1 0 0] * L = axis_x * R * B * B'^{-1} * T^{-1} * O^{-1}
            # hence these give us the first and last row of L
            # which is exactly enough to provide the euler angles

            # multiply with rigid body transform
            if isinstance(hkbody, NifFormat.bhkRigidBodyT):
                # set rotation
                transform = mathutils.Quaternion(
                    (hkbody.rotation.w, hkbody.rotation.x, hkbody.rotation.y,
                     hkbody.rotation.z)).to_matrix()
                transform.resize_4x4()
                # set translation
                transform[0][3] = hkbody.translation.x * self.HAVOK_SCALE
                transform[1][3] = hkbody.translation.y * self.HAVOK_SCALE
                transform[2][3] = hkbody.translation.z * self.HAVOK_SCALE
                # apply transform
                # pivot = pivot * transform
                transform = transform.to_3x3()
                axis_z = axis_z * transform
                axis_x = axis_x * transform

            # TODO [armature] update this to use the new bone system
            # next, cancel out bone matrix correction
            # note that B' = X * B with X = self.nif_import.dict_bones_extra_matrix[B]
            # so multiply with the inverse of X
            # for niBone in self.nif_import.dict_bones_extra_matrix:
            # if niBone.collision_object \
            # and niBone.collision_object.body is hkbody:
            # transform = mathutils.Matrix(
            # self.nif_import.dict_bones_extra_matrix[niBone])
            # transform.invert()
            # pivot = pivot * transform
            # transform = transform.to_3x3()
            # axis_z = axis_z * transform
            # axis_x = axis_x * transform
            # break

            # # cancel out bone tail translation
            # if b_hkobj.parent_bone:
            #     pivot[1] -= b_hkobj.parent.data.bones[
            #         b_hkobj.parent_bone].length

            # cancel out object transform
            transform = mathutils.Matrix(b_hkobj.matrix_local)
            transform.invert()
            # pivot = pivot * transform
            transform = transform.to_3x3()
            axis_z = axis_z * transform
            axis_x = axis_x * transform

            # set pivot point
            b_constr.pivot_x = pivot[0]
            b_constr.pivot_y = pivot[1]
            b_constr.pivot_z = pivot[2]

            # set euler angles
            constr_matrix = mathutils.Matrix(
                (axis_x, mathutils.Vector.cross(axis_z, axis_x), axis_z))
            constr_euler = constr_matrix.to_euler()
            b_constr.axis_x = constr_euler.x
            b_constr.axis_y = constr_euler.y
            b_constr.axis_z = constr_euler.z
            # DEBUG
            assert ((axis_x - mathutils.Vector(
                (1, 0, 0)) * constr_matrix).length < 0.0001)
            assert ((axis_z - mathutils.Vector(
                (0, 0, 1)) * constr_matrix).length < 0.0001)

            # the generic rigid body type is very buggy... so for simulation purposes let's transform it into ball and hinge
            if isinstance(hkdescriptor, NifFormat.RagdollDescriptor):
                # cone_twist
                b_constr.pivot_type = 'CONE_TWIST'
            elif isinstance(
                    hkdescriptor,
                (NifFormat.LimitedHingeDescriptor, NifFormat.HingeDescriptor)):
                # (limited) hinge
                b_constr.pivot_type = 'HINGE'
            else:
                raise ValueError("Unknown descriptor {0}".format(
                    hkdescriptor.__class__.__name__))
Esempio n. 21
0
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

    Args:
      position(list): The position to include in the dictionary.
      rotation(list): The rotation to include into the dictionary, either euler angle or quaternion.
      pivot(list, optional): The pivot point. (Default value = (0)
      0: 
      0): 

    Returns:
      : 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
def animate_rotation_quaternion(export_settings, rotation_quaternion, interpolation, node_type, node_name, action_name, matrix_correction, matrix_basis):
    """
    Calculates/gathers the key value pairs for quaternion transformations.
    """
    joint_cache = export_settings['gltf_joint_cache'][action_name]
    if not joint_cache.get(node_name):
        joint_cache[node_name] = {}
    
    keys = animate_gather_keys(export_settings, rotation_quaternion, interpolation)

    times = animate_convert_keys(keys)
    
    result = {}
    result_in_tangent = {}
    result_out_tangent = {}

    keyframe_index = 0
    for timeIndex, time in enumerate(times):
        rotation = [1.0, 0.0, 0.0, 0.0]
        in_tangent = [1.0, 0.0, 0.0, 0.0]
        out_tangent = [1.0, 0.0, 0.0, 0.0]
        
        if node_type == 'JOINT':
            if joint_cache[node_name].get(keys[keyframe_index]):
                tmp_location, rotation, tmp_scale = joint_cache[node_name][keys[keyframe_index]]
            else:
                bpy.context.scene.frame_set(keys[keyframe_index])
                
                matrix = matrix_correction * matrix_basis 
    
                tmp_location, rotation, tmp_scale = matrix.decompose()
                
                joint_cache[node_name][keys[keyframe_index]] = [tmp_location, rotation, tmp_scale]
        else:
            channel_index = 0
            for blender_fcurve in rotation_quaternion:
                
                if blender_fcurve is not None:
                    if interpolation == 'CUBICSPLINE':
                        blender_key_frame = blender_fcurve.keyframe_points[keyframe_index]

                        rotation[channel_index] = blender_key_frame.co[1]

                        if timeIndex == 0:
                            in_tangent_value = 0.0
                        else:
                            in_tangent_value = 3.0 * (blender_key_frame.co[1] - blender_key_frame.handle_left[1]) / (time - times[timeIndex - 1])

                        if timeIndex == len(times) - 1:
                            out_tangent_value = 0.0
                        else:
                            out_tangent_value = 3.0 * (blender_key_frame.handle_right[1] - blender_key_frame.co[1]) / (times[timeIndex + 1] - time)

                        in_tangent[channel_index] = in_tangent_value
                        out_tangent[channel_index] = out_tangent_value
                    else: 
                        value = blender_fcurve.evaluate(keys[keyframe_index]) 
                        
                        rotation[channel_index] = value
                
                channel_index += 1 
        
            rotation = mathutils.Quaternion((rotation[0], rotation[1], rotation[2], rotation[3]))
            in_tangent = convert_swizzle_rotation(in_tangent, export_settings)
            out_tangent = convert_swizzle_rotation(out_tangent, export_settings)

            # handle parent inverse
            matrix = rotation.to_matrix().to_4x4()
            matrix = matrix_correction * matrix
            rotation = matrix.to_quaternion()

            # Bring back to internal Quaternion notation.
            rotation = convert_swizzle_rotation([rotation[0], rotation[1], rotation[2], rotation[3]], export_settings)

        # Bring to glTF Quaternion notation.
        rotation = [rotation[1], rotation[2], rotation[3], rotation[0]]
        in_tangent = [in_tangent[1], in_tangent[2], in_tangent[3], in_tangent[0]]
        out_tangent = [out_tangent[1], out_tangent[2], out_tangent[3], out_tangent[0]]
        
        result[time] = rotation
        result_in_tangent[time] = in_tangent
        result_out_tangent[time] = out_tangent
        
        keyframe_index += 1 

    return result, result_in_tangent, result_out_tangent
    def draw_limits(cls):
        bgl.glEnable(bgl.GL_BLEND)
        bgl.glDisable(bgl.GL_DEPTH_TEST)

        cam = bpy.context.active_object

        if (cam is not None and cam.type == "CAMERA"
                and cam.data.b4w_show_limits_in_viewport
                and cam_has_limits(cam)):

            ms = cam.data.b4w_move_style

            if ms == "TARGET":
                # get orientation
                view_dir = cam.data.b4w_target - cam.location
                orientation = get_camera_orientation(cam, view_dir)

                # get limits
                hor_rot_limits = get_target_hor_rot_limits(cam, orientation)
                vert_rot_limits = get_target_vert_rot_limits(cam, orientation)
                dist_limits = get_target_distance_limits(cam)

                # draw limits
                rotation_mat = mathutils.Matrix.Rotation(-math.pi / 2, 3, 'Z')
                draw_target_limits(cam, hor_rot_limits, dist_limits,
                                   rotation_mat, BLUE_COLOR,
                                   cam.data.b4w_use_horizontal_clamping)

                rotation_mat = mathutils.Matrix.Rotation(-math.pi / 2, 3, 'X')
                phi_middle = (
                    wrap_2pi(hor_rot_limits[1] - hor_rot_limits[0]) / 2 +
                    hor_rot_limits[0] - math.pi / 2)
                rotation_mat.rotate(mathutils.Quaternion((0, 0, 1),
                                                         phi_middle))
                draw_target_limits(cam, vert_rot_limits, dist_limits,
                                   rotation_mat, RED_COLOR,
                                   cam.data.b4w_use_vertical_clamping)

                bgl.glColor4f(ORANGE_COLOR[0], ORANGE_COLOR[1],
                              ORANGE_COLOR[2], 1)
                draw_point(cam.data.b4w_target, NORMAL_POINT_SIZE)
            elif ms == "EYE":
                # get orientation
                view_dir = mathutils.Vector((0, 0, -1))
                view_dir.rotate(cam.matrix_world.to_quaternion())
                orientation = get_camera_orientation(cam, view_dir)

                # get limits
                hor_rot_limits = get_eye_hor_rot_limits(cam, orientation)
                vert_rot_limits = get_eye_vert_rot_limits(cam, orientation)

                # draw limits
                rotation_mat = mathutils.Matrix.Rotation(math.pi / 2, 3, 'Z')
                draw_eye_limits(cam, hor_rot_limits, rotation_mat, BLUE_COLOR,
                                cam.data.b4w_use_horizontal_clamping)

                rotation_mat = mathutils.Matrix.Rotation(math.pi / 2, 3, 'X')
                phi_middle = (
                    wrap_2pi(hor_rot_limits[1] - hor_rot_limits[0]) / 2 +
                    hor_rot_limits[0] + math.pi / 2)
                rotation_mat.rotate(mathutils.Quaternion((0, 0, 1),
                                                         phi_middle))
                draw_eye_limits(cam, vert_rot_limits, rotation_mat, RED_COLOR,
                                cam.data.b4w_use_vertical_clamping)
            elif ms == "HOVER":
                # get orientation
                view_dir = mathutils.Vector((0, 0, -1))
                view_dir.rotate(cam.matrix_world.to_quaternion())
                orientation = get_camera_orientation(cam, view_dir)

                # get limits
                res = mathutils.geometry.intersect_line_plane(
                    cam.location, cam.location + view_dir,
                    mathutils.Vector((0, 0, cam.data.b4w_hover_zero_level)),
                    mathutils.Vector((0, 0, 1)))
                cross_point = (mathutils.Vector(
                    (cam.location.x, cam.location.y,
                     cam.data.b4w_hover_zero_level)) if res is None else res)
                rad_vec = cam.location - cross_point

                hor_trans_limits = get_hover_hor_trans_limits(cam)
                vert_trans_limits = get_hover_vert_trans_limits(cam)
                zoom_limits = get_hover_zoom_limits(cam, orientation["theta"],
                                                    rad_vec.length)

                hover_pivot = calc_hover_pivot(cross_point, hor_trans_limits,
                                               vert_trans_limits)

                rotation_mat = mathutils.Matrix.Rotation(
                    orientation["phi"] - math.pi / 2, 3, 'Z')
                draw_hover_limits(cam, hover_pivot, hor_trans_limits,
                                  vert_trans_limits, zoom_limits, rotation_mat,
                                  orientation["theta"], rad_vec)

                bgl.glColor4f(ORANGE_COLOR[0], ORANGE_COLOR[1],
                              ORANGE_COLOR[2], 1)
                draw_point(hover_pivot, NORMAL_POINT_SIZE)
Esempio n. 24
0
def convert_swizzle_rotation(rot):
    return mathutils.Quaternion((rot[0], rot[1], rot[3], -rot[2]))
Esempio n. 25
0
import mathutils

# zero length vector
vec = mathutils.Vector((0.0, 0.0, 1.0))

# unit length vector
vec_a = vec.normalized()

vec_b = mathutils.Vector((0.0, 1.0, 2.0))

vec2d = mathutils.Vector((1.0, 2.0))
vec3d = mathutils.Vector((1.0, 0.0, 0.0))
vec4d = vec_a.to_4d()

# other mathutuls types
quat = mathutils.Quaternion()
matrix = mathutils.Matrix()

# Comparison operators can be done on Vector classes:

# (In)equality operators == and != test component values, e.g. 1,2,3 != 3,2,1
vec_a == vec_b
vec_a != vec_b

# Ordering operators >, >=, > and <= test vector length.
vec_a > vec_b
vec_a >= vec_b
vec_a < vec_b
vec_a <= vec_b

# Math can be performed on Vector classes
Esempio n. 26
0
def applyANM(header, boneList):
    import bpy

    # http://blender.stackexchange.com/a/8392
    # http://blender.stackexchange.com/a/31709

    try:
        bpy.ops.objects['lolArmature'].mode_set(mode='EDIT')
        print("TEST")
    except:
        pass

    scene = bpy.context.scene
    ob = bpy.context.scene.objects['lolArmature']
    editBones = ob.data.edit_bones
    poseBones = ob.pose.bones

    parentOffset = {}
    parentOffRot = {}

    for editBone in editBones:
        if editBone.parent != None:
            # get offset from parent bone in bone's object space
            parentOffset[editBone.name] = mathutils.Vector(
                editBone.head - editBone.parent.head) @ editBone.matrix
            # get bone rotation relative to the parent bone
            parentOffRot[editBone.name] = editBone.parent.matrix.to_quaternion(
            ).rotation_difference(editBone.matrix.to_quaternion())
        else:
            parentOffset[editBone.name] = mathutils.Vector(
                editBone.head) @ editBone.matrix
            parentOffRot[editBone.name] = mathutils.Quaternion(
                [1.0, 0.0, 0.0,
                 0.0]).rotation_difference(editBone.matrix.to_quaternion())

    if header.version in [1, 3, 4, 5]:
        scene.render.fps = header.playbackFPS
        scene.frame_end = header.numFrames - 1
        scene.frame_start = 0
        for f in range(header.numFrames):
            print("frame %s processing" % f)
            scene.frame_set(f)

            for b in boneList:
                n = b.name
                boneRotation = b.orientations[f]
                bonePosition = b.positions[f]

                poseBone = poseBones[n]
                editBone = editBones[n]

                if poseBone.parent:
                    # bonePosition is in parent bone's object space so convert to absolute position
                    bonePosition = bonePosition @ poseBone.parent.matrix.inverted(
                    )

                # convert absolute position to position in bone's object space
                bonePosition = bonePosition @ editBone.matrix

                poseBone.rotation_quaternion = parentOffRot[n].inverted(
                ) @ boneRotation
                poseBone.location = bonePosition - parentOffset[n]

                for dp in ["rotation_quaternion", "location"]:
                    poseBone.keyframe_insert(data_path=dp, frame=f)
            # ob.keyframe_insert(data_path="pose")

    elif header.version == 4:
        raise NotImplementedError("version 4 not supported yet")
    else:
        raise ValueError("Version not supported", header.version)
Esempio n. 27
0
    def PecSimulation(self, nFrame, pFS, startFrame):
        # print("Pecs")
        if self.sPecFinTopL == None or self.sPecFinTopR == None:
            return

        #Update State and main angle
        self.sPecState = self.sPecState + 360.0 / pFS.pMaxPecFreq
        xPecAngle = math.sin(math.radians(self.sPecState)) * math.radians(
            pFS.pMaxPecAngle)
        yPecAngle = math.sin(
            math.radians(self.sPecState + 90.0)) * math.radians(
                pFS.pMaxPecAngle * 2)

        #Rest Period Calculations

        if nFrame >= self.sRestartFrame:
            self.sRestAmount = max(0.0, self.sRestAmount - pFS.pPecTransition)
            if self.sRestAmount < 0.1:
                self.sRestFrame = nFrame + pFS.pPecDuration
                self.sRestartFrame = self.sRestFrame + pFS.pPecDuty * pFS.pPecDuration

        if (nFrame >= self.sRestFrame and nFrame < self.sRestartFrame
                and self.sRestAmount < 1.0):
            self.sRestAmount = min(1.0, self.sRestAmount + pFS.pPecTransition)

        # print("RestAmount: ", self.sRestAmount, self.sRestFrame, self.sRestartFrame)

        #Add the same side fin wobble to the pec fins to stop them looking boring when not flapping
        SideFinRot = math.radians(
            math.sin(math.radians(self.sState + pFS.pSideFinPhase)) *
            pFS.pMaxSideFinAngle)

        #Slerp between oscillating angle and rest angle depending on hover status and reset periods
        # xRestAmount = 1 means no flapping due to either resting or not hovering
        xRestAmount = (1.0 - (1.0 - self.sRestAmount) * self.sHoverMode)
        # print("xRestAmaount: ", xRestAmount)
        # print("RestAmount: ", self.sRestAmount, self.sRestFrame, self.sRestartFrame)
        # print("HoverMode: ", self.sHoverMode)
        yAng = mathutils.Quaternion((0.0, 1.0, 0.0), yPecAngle)
        # yAng = mathutils.Quaternion((0.0, 1.0, 0.0), 0)
        xAng = yAng * mathutils.Quaternion((1.0, 0.0, 0.0), -xPecAngle)
        xAng = xAng.slerp(
            mathutils.Quaternion((1.0, 0.0, 0.0),
                                 math.radians(pFS.pPecOffset)), xRestAmount)
        self.sPecFinPalmL.rotation_quaternion = xAng * mathutils.Quaternion(
            (1.0, 0.0, 0.0), SideFinRot)
        self.sPecFinPalmL.keyframe_insert(data_path='rotation_quaternion',
                                          frame=(nFrame))
        # print("Palm Animate: ", nFrame)

        #Tip deflection based on phase offset
        xMaxPecScale = pFS.pMaxPecAngle * (1.0 /
                                           pFS.pPecStiffness) * 0.2 / 30.0

        self.sPec_scale = 1.0 + math.sin(
            math.radians(self.sPecState -
                         pFS.pPecPhase)) * xMaxPecScale * (1.0 - xRestAmount)

        self.sPecFinTopL.scale[1] = self.sPec_scale
        self.sPecFinBottomL.scale[1] = 1 - (
            1 - self.sPec_scale) * pFS.pPecStubRatio
        self.sPecFinTopL.keyframe_insert(data_path='scale', frame=(nFrame))
        self.sPecFinBottomL.keyframe_insert(data_path='scale', frame=(nFrame))

        #copy to the right fin

        #If fins are opposing
        if not pFS.pPecSynch:
            yAng = mathutils.Quaternion((0.0, 1.0, 0.0), yPecAngle)
            xAng = yAng * mathutils.Quaternion((1.0, 0.0, 0.0), xPecAngle)
            xAng = xAng.slerp(
                mathutils.Quaternion((1.0, 0.0, 0.0),
                                     math.radians(pFS.pPecOffset)),
                xRestAmount)
            self.sPecFinPalmR.rotation_quaternion = xAng * mathutils.Quaternion(
                (1.0, 0.0, 0.0), SideFinRot)
            self.sPecFinTopR.scale[1] = 1 / self.sPec_scale
            self.sPecFinBottomR.scale[1] = 1 - (
                1 - 1 / self.sPec_scale) * pFS.pPecStubRatio
        else:
            yAng = mathutils.Quaternion((0.0, 1.0, 0.0), -yPecAngle)
            xAng = yAng * mathutils.Quaternion((1.0, 0.0, 0.0), -xPecAngle)
            xAng = xAng.slerp(
                mathutils.Quaternion((1.0, 0.0, 0.0),
                                     math.radians(pFS.pPecOffset)),
                xRestAmount)
            self.sPecFinPalmR.rotation_quaternion = xAng * mathutils.Quaternion(
                (1.0, 0.0, 0.0), SideFinRot)
            self.sPecFinTopR.scale[1] = self.sPec_scale
            self.sPecFinBottomR.scale[1] = 1 - (
                1 - self.sPec_scale) * pFS.pPecStubRatio
        self.sPecFinPalmR.keyframe_insert(data_path='rotation_quaternion',
                                          frame=(nFrame))
        self.sPecFinTopR.keyframe_insert(data_path='scale', frame=(nFrame))
        self.sPecFinBottomR.keyframe_insert(data_path='scale', frame=(nFrame))
Esempio n. 28
0
def exportANM(skelObj, output_filepath, input_filepath, OVERWRITE_FILE_VERSION,
              VERSION):
    import bpy

    (import_header, import_bonelist) = importANM(input_filepath)

    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.select_all(action='DESELECT')
    skelObj.select = True
    bpy.ops.object.mode_set(mode='EDIT')

    scene = bpy.context.scene
    objBones = skelObj.data.bones
    pb = skelObj.pose.bones
    numBones = len(objBones)

    header = import_header
    if OVERWRITE_FILE_VERSION:
        header.version = VERSION

        #Apply changes to the header based on the new version here

    if header.version in [0, 2, 3]:
        header.numBones = numBones
        header.numFrames = scene.frame_end - scene.frame_start + 1

        boneList = []
        parentOffset = {}
        parentOffRot = {}

        for i, b in enumerate(objBones):
            boneList.append(anmBone())
            boneList[-1].name = b.name

            #most bones have a value of zero / bones without parent have a value of 2 /
            if b.parent != None:
                boneList[-1].unknown = 0

                parentOffset[b.name] = mathutils.Vector(
                    b.matrix_local.decompose()[0] -
                    b.parent.matrix_local.decompose()[0]) @ b.matrix_local
                parentOffRot[b.name] = objBones[
                    b.parent.name].matrix_local.to_quaternion(
                    ).rotation_difference(b.matrix_local.to_quaternion())
            else:
                boneList[-1].unknown = 2

                parentOffset[b.name] = mathutils.Vector(
                    b.head) @ b.matrix_local
                parentOffRot[b.name] = mathutils.Quaternion(
                    [1.0, 0.0, 0.0, 0.0])

        for f in range(scene.frame_start, scene.frame_end + 1):
            bpy.context.scene.frame_set(f)

            for b in boneList:
                n = b.name
                objBone = objBones[n]
                poseBone = pb[n]
                bonePos = poseBone.location

                bonePos = bonePos + parentOffset[n]
                boneOrient = parentOffRot[n] @ poseBone.rotation_quaternion

                if objBone.parent != None:
                    bonePos = bonePos @ objBone.matrix_local.inverted()
                    bonePos = bonePos @ poseBone.parent.matrix

                bonePos[2] = -bonePos[2]

                b.add_frame(bonePos, boneOrient)

        anmFid = open(output_filepath, 'wb')

        header.toFile(anmFid)

        for b in boneList:
            b.toFile(anmFid, import_header.version)

        anmFid.close()

    else:
        raise ValueError("Version %d not supported!" % header.version)
def rotateQuaternion(cubelets, axis, angle):
    vecByAxis = {'X': (1, 0, 0), 'Y': (0, 1, 0), 'Z': (0, 0, 1)}
    qDelta = mathutils.Quaternion(vecByAxis[axis], angle)
    for cubelet in cubelets:
        cubelet.rotation_quaternion = qDelta @ cubelet.rotation_quaternion
Esempio n. 30
0
    def execute(self, context):
        common.preferences().custom_normal_blend = self.custom_normal_blend

        bpy.ops.object.mode_set(mode='OBJECT')
        ob = context.active_object
        me = ob.data
        is_shaped = bool(me.shape_keys)

        pre_selected_objects = context.selected_objects[:]
        pre_mode = ob.mode

        if is_shaped:
            pre_relative_keys = [
                s.relative_key.name for s in me.shape_keys.key_blocks
            ]
            pre_active_shape_key_index = ob.active_shape_key_index

            shape_names = [s.name for s in me.shape_keys.key_blocks]
            shape_deforms = []
            for shape in me.shape_keys.key_blocks:
                shape_deforms.append(
                    [shape.data[v.index].co.copy() for v in me.vertices])

            ob.active_shape_key_index = len(me.shape_keys.key_blocks) - 1
            for i in me.shape_keys.key_blocks[:]:
                ob.shape_key_remove(ob.active_shape_key)

            new_shape_deforms = []
            for shape_index, deforms in enumerate(shape_deforms):

                temp_ob = ob.copy()
                temp_me = me.copy()
                temp_ob.data = temp_me
                context.scene.objects.link(temp_ob)

                for vert in temp_me.vertices:
                    vert.co = deforms[vert.index].copy()

                override = context.copy()
                override['object'] = temp_ob
                for index, mod in enumerate(temp_ob.modifiers):
                    if self.is_applies[index]:
                        try:
                            bpy.ops.object.modifier_apply(override,
                                                          modifier=mod.name)
                        except:
                            ob.modifiers.remove(mod)

                new_shape_deforms.append(
                    [v.co.copy() for v in temp_me.vertices])

                common.remove_data(temp_ob)
                common.remove_data(temp_me)

        if ob.active_shape_key_index != 0:
            ob.active_shape_key_index = 0
            me.update()

        copy_modifiers = ob.modifiers[:]

        for index, mod in enumerate(copy_modifiers):
            if self.is_applies[index] and mod.type != 'ARMATURE':

                if mod.type == 'MIRROR':
                    for vg in ob.vertex_groups[:]:
                        replace_list = ((r'\.L$', ".R"), (r'\.R$', ".L"),
                                        (r'\.l$', ".r"), (r'\.r$', ".l"),
                                        (r'_L$', "_R"), (r'_R$', "_L"),
                                        (r'_l$', "_r"), (r'_r$', "_l"))
                        for before, after in replace_list:
                            mirrored_name = re.sub(before, after, vg.name)
                            if mirrored_name not in ob.vertex_groups:
                                ob.vertex_groups.new(mirrored_name)

                try:
                    bpy.ops.object.modifier_apply(modifier=mod.name)
                except:
                    ob.modifiers.remove(mod)

        arm_ob = None
        for mod in ob.modifiers:
            if mod.type == "ARMATURE":
                arm_ob = mod.object

        if arm_ob:
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.object.mode_set(mode='OBJECT')

            arm = arm_ob.data
            arm_pose = arm_ob.pose

            pose_quats = {}
            for bone in arm.bones:
                pose_bone = arm_pose.bones[bone.name]

                bone_quat = bone.matrix_local.to_quaternion()
                pose_quat = pose_bone.matrix.to_quaternion()
                result_quat = pose_quat * bone_quat.inverted()

                pose_quats[bone.name] = result_quat.copy()

            custom_normals = []
            for loop in me.loops:
                vert = me.vertices[loop.vertex_index]
                no = vert.normal.copy()

                total_weight = 0.0
                for vge in vert.groups:
                    vg = ob.vertex_groups[vge.group]
                    try:
                        pose_quats[vg.name]
                    except KeyError:
                        continue
                    total_weight += vge.weight

                total_quat = mathutils.Quaternion()
                for vge in vert.groups:
                    vg = ob.vertex_groups[vge.group]
                    try:
                        total_quat = total_quat.slerp(
                            pose_quats[vg.name], vge.weight / total_weight)
                    except KeyError:
                        pass

                no.rotate(total_quat)
                custom_normals.append(no)

        for index, mod in enumerate(copy_modifiers):
            if self.is_applies[index] and mod.type == 'ARMATURE':
                try:
                    bpy.ops.object.modifier_apply(modifier=mod.name)
                except:
                    ob.modifiers.remove(mod)

        context.scene.objects.active = ob

        if is_shaped:

            for deforms in new_shape_deforms:
                if len(me.vertices) != len(deforms):
                    self.report(
                        type={'ERROR'},
                        message=
                        "ミラー等が原因で頂点数が変わっているためシェイプキーを格納できません、中止するのでCtrl+Z等で元に戻し修正してください。"
                    )
                    return {'CANCELLED'}

            for shape_index, deforms in enumerate(new_shape_deforms):

                bpy.ops.object.shape_key_add(from_mix=False)
                shape = ob.active_shape_key
                shape.name = shape_names[shape_index]

                for vert in me.vertices:
                    shape.data[vert.index].co = deforms[vert.index].copy()

            for shape_index, shape in enumerate(me.shape_keys.key_blocks):
                shape.relative_key = me.shape_keys.key_blocks[
                    pre_relative_keys[shape_index]]

            ob.active_shape_key_index = pre_active_shape_key_index

        for temp_ob in pre_selected_objects:
            temp_ob.select = True
        bpy.ops.object.mode_set(mode=pre_mode)

        if arm_ob:
            for i, loop in enumerate(me.loops):
                vert = me.vertices[loop.vertex_index]
                no = vert.normal.copy()

                try:
                    custom_rot = mathutils.Vector(
                        (0.0, 0.0, 1.0)).rotation_difference(custom_normals[i])
                except:
                    continue
                original_rot = mathutils.Vector(
                    (0.0, 0.0, 1.0)).rotation_difference(no)
                output_rot = original_rot.slerp(custom_rot,
                                                self.custom_normal_blend)

                output_no = mathutils.Vector((0.0, 0.0, 1.0))
                output_no.rotate(output_rot)

                custom_normals[i] = output_no
            me.use_auto_smooth = True
            me.normals_split_custom_set(custom_normals)

        return {'FINISHED'}