def _get_bone_pose_matrix_cleaned(self, bone):
   offset_m4 = (Matrix.Translation(bone.location) * Quaternion(bone.rotation_quaternion).to_matrix().to_4x4())
   pose_matrix_cleaned = bone.pose_matrix * offset_m4.inverted()
   print(bone.pose_matrix)   # pose matrix not update after translate hand
   return pose_matrix_cleaned
Beispiel #2
0
    def run(self, objects, set_location_func, set_rotation_func):

        apply_location_dict = {}
        apply_rotation_dict = {}

        receive = True

        sync = False

        try:
            data = self.sock.recv( 1024 )
        except:
            data = None

            if self.next_sync:
                apply_location_dict = self.next_location_dict.copy()
                apply_rotation_dict = self.next_rotation_dict.copy()
                self.next_location_dict = {}
                self.next_rotation_dict = {}
                self.next_sync = False
                sync = True

            receive = False

        trash = data
        while(receive):
            data = trash

            decoded = OSC.decodeOSC(data)
            ob_name = str(decoded[0], "utf-8")

            try:
                if (ob_name.startswith("@")):
                    # Something to play with:
                    # values that begin with a @ are python expressions,
                    # and there is one parameter after the address in the OSC message
                    # if you set something such as
                    # bpy.data.objects"['Cube']".location.x= {V}
                    # into a OSC path for, say, a face shape smile controller
                    # you can move an object by smiling
                    to_evaluate = ob_name[1:]
                    to_evaluate += str(decoded[2])
                    try:
                        print(exec(to_evaluate))
                    except Exception as e:
                        print(to_evaluate)
                        print(str(e))
                elif (ob_name.startswith("?")):
                    # This one could be used for something such as mapping
                    # "thumbs up" gesture for rendering
                    # Add the following path to a gesture controller OSC path
                    # ?bpy.ops.render.render()
                    to_evaluate = ob_name[1:]
                    try:
                        print(exec(to_evaluate))
                    except Exception as e:
                        print(to_evaluate)
                        print(str(e))
                elif len(decoded) == 3: #one value
                    if ob_name == "NI_mate_sync":
                        if sync:
                            self.next_sync = True
                        else:
                            sync = True
                            apply_location_dict = self.location_dict.copy()
                            apply_rotation_dict = self.rotation_dict.copy()
                            self.location_dict = {}
                            self.rotation_dict = {}
                            self.next_location_dict = {}
                            self.next_rotation_dict = {}
                    else:
                        if sync:
                            self.next_location_dict[ob_name] = Vector([decoded[2], 0, 0])
                        else:
                            self.location_dict[ob_name] = Vector([decoded[2], 0, 0])

                elif len(decoded) == 5: #location
                    if sync:
                        self.next_location_dict[ob_name] = Vector([decoded[2],
                                                        -decoded[4], decoded[3]])
                    else:
                        self.location_dict[ob_name] = Vector([decoded[2],
                                                        -decoded[4], decoded[3]])

                elif len(decoded) == 6: #quaternion
                    if sync:
                        self.next_rotation_dict[ob_name] = Quaternion((-decoded[2],
                                            decoded[3], -decoded[5], decoded[4]))
                    else:
                        self.rotation_dict[ob_name] = Quaternion((-decoded[2],
                                            decoded[3], -decoded[5], decoded[4]))

                elif len(decoded) == 9: #location & quaternion
                    if sync:
                        self.next_location_dict[ob_name] = Vector([decoded[2],
                                                        -decoded[4], decoded[3]])
                        self.next_rotation_dict[ob_name] = Quaternion((-decoded[5],
                                            decoded[6], -decoded[8], decoded[7]))
                    else:
                        self.location_dict[ob_name] = Vector([decoded[2],
                                                        -decoded[4], decoded[3]])
                        self.rotation_dict[ob_name] = Quaternion((-decoded[5],
                                        decoded[6], -decoded[8], decoded[7]))
            except:
                print("NI mate Tools error parsing OSC message: " + str(decoded))
                pass

            try:
                trash = self.sock.recv(1024)
            except:
                break

        if sync:
            for key, value in apply_location_dict.items():
                set_location_func(objects, key, value, self.original_locations)

            for key, value in apply_rotation_dict.items():
                set_rotation_func(objects, key, value, self.original_rotations)

            self.location_dict = {}
            self.rotation_dict = {}
        else:
            for key, value in self.location_dict.items():
                set_location_func(objects, key, value, self.location_dict)

            for key, value in self.rotation_dict.items():
                set_rotation_func(objects, key, value, self.rotation_dict)
def angle_axis_to_quat(angle, axis):
    w = math.cos(angle / 2.0)
    xyz = axis.normalized() * math.sin(angle / 2.0)
    return Quaternion((w, xyz.x, xyz.y, xyz.z))
Beispiel #4
0
 def pitch_down(self, angle):
     """Pitch the turtle down about the right axis"""
     self.dir.rotate(Quaternion(self.right, radians(-angle)))
     self.dir.normalize()
    def recursive_node_traverse(self,
                                blender_object,
                                blender_bone,
                                parent_uuid,
                                parent_coll_matrix_world,
                                armature_uuid=None,
                                dupli_world_matrix=None):
        node = VExportNode()
        node.uuid = str(uuid.uuid4())
        node.parent_uuid = parent_uuid
        node.set_blender_data(blender_object, blender_bone)

        # add to parent if needed
        if parent_uuid is not None:
            self.add_children(parent_uuid, node.uuid)
        else:
            self.roots.append(node.uuid)

        # Set blender type
        if blender_bone is not None:
            node.blender_type = VExportNode.BONE
            self.nodes[armature_uuid].bones[blender_bone.name] = node.uuid
            node.use_deform = blender_bone.id_data.data.bones[
                blender_bone.name].use_deform
        elif blender_object.type == "ARMATURE":
            node.blender_type = VExportNode.ARMATURE
        elif blender_object.type == "CAMERA":
            node.blender_type = VExportNode.CAMERA
        elif blender_object.type == "LIGHT":
            node.blender_type = VExportNode.LIGHT
        elif blender_object.instance_type == "COLLECTION":
            node.blender_type = VExportNode.COLLECTION
        else:
            node.blender_type = VExportNode.OBJECT

        # For meshes with armature modifier (parent is armature), keep armature uuid
        if node.blender_type == VExportNode.OBJECT:
            modifiers = {m.type: m for m in blender_object.modifiers}
            if "ARMATURE" in modifiers and modifiers[
                    "ARMATURE"].object is not None:
                if parent_uuid is None or not self.nodes[
                        parent_uuid].blender_type == VExportNode.ARMATURE:
                    # correct workflow is to parent skinned mesh to armature, but ...
                    # all users don't use correct workflow
                    print(
                        "WARNING: Armature must be the parent of skinned mesh")
                    print(
                        "Armature is selected by its name, but may be false in case of instances"
                    )
                    # Search an armature by name, and use the first found
                    # This will be done after all objects are setup
                    node.armature_needed = modifiers["ARMATURE"].object.name
                else:
                    node.armature = parent_uuid

        # For bones, store uuid of armature
        if blender_bone is not None:
            node.armature = armature_uuid

        # for bone/bone parenting, store parent, this will help armature tree management
        if parent_uuid is not None and self.nodes[
                parent_uuid].blender_type == VExportNode.BONE and node.blender_type == VExportNode.BONE:
            node.parent_bone_uuid = parent_uuid

        # Objects parented to bone
        if parent_uuid is not None and self.nodes[
                parent_uuid].blender_type == VExportNode.BONE and node.blender_type != VExportNode.BONE:
            node.parent_bone_uuid = parent_uuid

        # World Matrix
        # Store World Matrix for objects
        if dupli_world_matrix is not None:
            node.matrix_world = dupli_world_matrix
        elif node.blender_type in [
                VExportNode.OBJECT, VExportNode.COLLECTION,
                VExportNode.ARMATURE, VExportNode.CAMERA, VExportNode.LIGHT
        ]:
            # Matrix World of object is expressed based on collection instance objects are
            # So real world matrix is collection world_matrix @ "world_matrix" of object
            node.matrix_world = parent_coll_matrix_world @ blender_object.matrix_world.copy(
            )
            if node.blender_type == VExportNode.CAMERA and self.export_settings[
                    gltf2_blender_export_keys.CAMERAS]:
                correction = Quaternion((2**0.5 / 2, -2**0.5 / 2, 0.0, 0.0))
                node.matrix_world @= correction.to_matrix().to_4x4()
            elif node.blender_type == VExportNode.LIGHT and self.export_settings[
                    gltf2_blender_export_keys.LIGHTS]:
                correction = Quaternion((2**0.5 / 2, -2**0.5 / 2, 0.0, 0.0))
                node.matrix_world @= correction.to_matrix().to_4x4()
        elif node.blender_type == VExportNode.BONE:
            node.matrix_world = self.nodes[
                node.armature].matrix_world @ blender_bone.matrix
            axis_basis_change = Matrix.Identity(4)
            if self.export_settings[gltf2_blender_export_keys.YUP]:
                axis_basis_change = Matrix(
                    ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0),
                     (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0)))
            node.matrix_world = node.matrix_world @ axis_basis_change

        # Force empty ?
        # For duplis, if instancer is not display, we should create an empty
        if blender_object.is_instancer is True and blender_object.show_instancer_for_render is False:
            node.force_as_empty = True

        # Storing this node
        self.add_node(node)

        ###### Manage children ######

        # standard children
        if blender_bone is None and blender_object.is_instancer is False:
            for child_object in blender_object.children:
                if child_object.parent_bone:
                    # Object parented to bones
                    # Will be manage later
                    continue
                else:
                    # Classic parenting
                    self.recursive_node_traverse(child_object, None, node.uuid,
                                                 parent_coll_matrix_world)

        # Collections
        if blender_object.instance_type == 'COLLECTION' and blender_object.instance_collection:
            for dupli_object in blender_object.instance_collection.objects:
                if dupli_object.parent is not None:
                    continue
                self.recursive_node_traverse(dupli_object, None, node.uuid,
                                             node.matrix_world)

        # Armature : children are bones with no parent
        if blender_object.type == "ARMATURE" and blender_bone is None:
            for b in [
                    b for b in blender_object.pose.bones if b.parent is None
            ]:
                self.recursive_node_traverse(blender_object, b, node.uuid,
                                             parent_coll_matrix_world,
                                             node.uuid)

        # Bones
        if blender_object.type == "ARMATURE" and blender_bone is not None:
            for b in blender_bone.children:
                self.recursive_node_traverse(blender_object, b, node.uuid,
                                             parent_coll_matrix_world,
                                             armature_uuid)

        # Object parented to bone
        if blender_bone is not None:
            for child_object in [
                    c for c in blender_object.children
                    if c.parent_bone is not None
                    and c.parent_bone == blender_bone.name
            ]:
                self.recursive_node_traverse(child_object, None, node.uuid,
                                             parent_coll_matrix_world)

        # Duplis
        if blender_object.is_instancer is True and blender_object.instance_type != 'COLLECTION':
            depsgraph = bpy.context.evaluated_depsgraph_get()
            for (dupl,
                 mat) in [(dup.object.original, dup.matrix_world.copy())
                          for dup in depsgraph.object_instances if dup.parent
                          and id(dup.parent.original) == id(blender_object)]:
                self.recursive_node_traverse(dupl,
                                             None,
                                             node.uuid,
                                             parent_coll_matrix_world,
                                             dupli_world_matrix=mat)
Beispiel #6
0
BILLBOARDMODE_ALL = '7'

# used in Mesh constructor, defined in BABYLON.PhysicsImpostor
SPHERE_IMPOSTER = 1
BOX_IMPOSTER = 2
#PLANE_IMPOSTER = 3
MESH_IMPOSTER = 4
CAPSULE_IMPOSTER = 5
CONE_IMPOSTER = 6
CYLINDER_IMPOSTER = 7
PARTICLE_IMPOSTER = 8

SHAPE_KEY_GROUPS_ALLOWED = False

ZERO_V = Vector((0, 0, 0))
ZERO_Q = Quaternion((1, 0, 0, 0))


#===============================================================================
class Mesh(FCurveAnimatable):
    def __init__(self, bpyMesh, scene, exporter):
        self.scene = scene
        self.name = bpyMesh.name
        Logger.log('processing begun of mesh:  ' + self.name)
        self.define_animations(
            bpyMesh, True, True,
            True)  #Should animations be done when forcedParent

        self.isVisible = bpyMesh.visible_get()
        self.isPickable = not bpyMesh.hide_select
        self.isEnabled = not bpyMesh.hide_render
Beispiel #7
0
    def _add_bone_to_scene(self, scene_node, armature):
        # Let's get all the data collection out of the way
        joint_index = scene_node.Attribute('JOINTINDEX', int)
        joint_binding_data = self.mesh_binding_data[
            'JointBindings'][joint_index]
        inv_bind_matrix = joint_binding_data['InvBindMatrix']
        inv_bind_matrix = Matrix([inv_bind_matrix[:4],
                                  inv_bind_matrix[4:8],
                                  inv_bind_matrix[8:12],
                                  inv_bind_matrix[12:]])
        inv_bind_matrix.transpose()
        bind_trans = joint_binding_data['BindTranslate']
        bind_rot = joint_binding_data['BindRotate']
        bind_sca = joint_binding_data['BindScale']

        # Assign the bind matrix so we can do easy lookup of it later for
        # applying animations.
        # Ironically, the inverse bind matrix is strored uninverted, and the
        # bind matrix is stored inverted...
        self.inv_bind_matrices[scene_node.Name] = inv_bind_matrix

        # Let's create the bone now
        # All changes to Bones have to be in EDIT mode or _bad things happen_
        with edit_object(armature) as data:
            bone = data.edit_bones.new(scene_node.Name)
            bone.use_inherit_rotation = True
            bone.use_inherit_scale = True

            self.scn.objects[scene_node.Name]['bind_data'] = (
                Vector(bind_trans[:3]),
                Quaternion((bind_rot[3],
                            bind_rot[0],
                            bind_rot[1],
                            bind_rot[2])),
                Vector(bind_sca[:3]))
            """
            self.bind_matrices[scene_node.Name] = (Vector(bind_trans[:3]),
                                                   Quaternion((bind_rot[3],
                                                           bind_rot[0],
                                                           bind_rot[1],
                                                           bind_rot[2])),
                                                   Vector(bind_sca[:3]))
            """

            if scene_node.parent.Type == 'JOINT':
                bone.matrix = self.inv_bind_matrices[scene_node.parent.Name]

            bone.tail = inv_bind_matrix.inverted().to_translation()

            if bone.length == 0:
                bone.tail = bone.head + Vector([0, 10 ** (-4), 0])

            if scene_node.parent.Type == 'JOINT':
                bone.parent = armature.data.edit_bones[scene_node.parent.Name]

            bone.use_connect = True

            # NMS defines some bones used in animations with 0 transform, eg.
            # Toy Cube.
            # This causes bone creation to fail, we need to move the tail
            # slightly.
            # Note that MMD Tools would have to deal with this too.
            while scene_node:
                if scene_node.Transform['Trans'] != (0.0, 0.0, 0.0):
                    break
                bone.tail += Vector([0, 0, 10 ** (-4)])
                scene_node = scene_node.parent
Beispiel #8
0
class HierarchyPivot(Struct):
    name = ""
    parentID = -1
    position = Vector((0.0, 0.0, 0.0))
    eulerAngles = Vector((0.0, 0.0, 0.0))
    rotation = Quaternion((1.0, 0.0, 0.0, 0.0))
Beispiel #9
0
# Animate center of the sphere.
center = Vector((0.0, 0.0, 0.0))
startcenter = Vector((0.0, -4.0, 0.0))
stopcenter = Vector((0.0, 4.0, 0.0))

# Rotate cubes around the surface of the sphere.
pt = Vector((0.0, 0.0, 0.0))
rotpt = Vector((0.0, 0.0, 0.0))

# Change the axis of rotation for the point.
baseaxis = Vector((0.0, 1.0, 0.0))
axis = Vector((0.0, 0.0, 0.0))

# Slerp between two rotations for each cube.
startrot = Quaternion((0.0, 1.0, 0.0), pi)
stoprot = Quaternion((1.0, 0.0, 0.0), pi * 1.5)
currot = Quaternion()

for i in range(0, latitude, 1):
    iprc = i * invlatitude
    phi = pi * (i + 1) * invlatitude

    sinphi = sin(phi)
    cosphi = cos(phi)

    rad = 0.01 + sz * abs(sinphi) * 0.99
    pt.z = cosphi * diameter

    for j in range(0, longitude, 1):
        jprc = j * invlongitude
 def convert_quat(q):
     return Quaternion([q[3], q[0], q[1], q[2]])
Beispiel #11
0
    def load_nodes(self, offset, export_order, parent=None):
        self.mdl.seek(MDL_OFFSET + offset)

        type_flags = self.mdl.get_uint16()
        node_number = self.mdl.get_uint16()
        name_index = self.mdl.get_uint16()
        self.mdl.skip(2)  # padding
        off_root = self.mdl.get_uint32()
        off_parent = self.mdl.get_uint32()
        position = [self.mdl.get_float() for _ in range(3)]
        orientation = [self.mdl.get_float() for _ in range(4)]
        children_arr = self.get_array_def()
        controller_arr = self.get_array_def()
        controller_data_arr = self.get_array_def()

        name = self.names[name_index]
        node_type = self.get_node_type(type_flags)
        node = self.new_node(name, node_type)

        self.node_by_number[node_number] = node

        if parent:
            node.parent = parent
            node.from_root = parent.from_root

        node.node_number = node_number
        node.export_order = export_order
        node.position = position
        node.orientation = orientation
        node.from_root = node.from_root @ Matrix.Translation(Vector(position)) @ Quaternion(orientation).to_matrix().to_4x4()

        if offset == self.off_anim_root:
            self.model.animroot = name

        if type_flags & NODE_LIGHT:
            flare_radius = self.mdl.get_float()
            unknown_arr = self.get_array_def()
            flare_size_arr = self.get_array_def()
            flare_position_arr = self.get_array_def()
            flare_color_shift_arr = self.get_array_def()
            flare_tex_name_arr = self.get_array_def()
            light_priority = self.mdl.get_int32()
            ambient_only = self.mdl.get_uint32()
            dynamic_type = self.mdl.get_uint32()
            affect_dynamic = self.mdl.get_uint32()
            shadow = self.mdl.get_uint32()
            flare = self.mdl.get_uint32()
            fading_light = self.mdl.get_uint32()

            node.shadow = shadow
            node.lightpriority = light_priority
            node.ambientonly = ambient_only
            node.dynamictype = dynamic_type
            node.affectdynamic = affect_dynamic
            node.fadinglight = fading_light
            node.lensflares = flare
            node.flareradius = flare_radius
            node.flare_list = FlareList()

        if type_flags & NODE_EMITTER:
            dead_space = self.mdl.get_float()
            blast_radius = self.mdl.get_float()
            blast_length = self.mdl.get_float()
            num_branches = self.mdl.get_uint32()
            ctrl_point_smoothing = self.mdl.get_float()
            x_grid = self.mdl.get_uint32()
            y_grid = self.mdl.get_uint32()
            spawn_type = self.mdl.get_uint32()
            update = self.mdl.get_c_string_up_to(32)
            emitter_render = self.mdl.get_c_string_up_to(32)
            blend = self.mdl.get_c_string_up_to(32)
            texture = self.mdl.get_c_string_up_to(32)
            chunk_name = self.mdl.get_c_string_up_to(16)
            twosided_tex = self.mdl.get_uint32()
            loop = self.mdl.get_uint32()
            render_order = self.mdl.get_uint16()
            frame_blending = self.mdl.get_uint8()
            depth_texture_name = self.mdl.get_c_string_up_to(32)
            self.mdl.skip(1)  # padding
            flags = self.mdl.get_uint32()

            # object data
            node.deadspace = dead_space
            node.blastradius = blast_radius
            node.blastlength = blast_length
            node.num_branches = num_branches
            node.controlptsmoothing = ctrl_point_smoothing
            node.xgrid = x_grid
            node.ygrid = y_grid
            node.spawntype = spawn_type
            node.update = update
            node.emitter_render = emitter_render
            node.blend = blend
            node.texture = texture
            node.chunk_name = chunk_name
            node.twosidedtex = twosided_tex != 0
            node.loop = loop != 0
            node.renderorder = render_order
            node.frame_blending = frame_blending != 0
            node.depth_texture_name = depth_texture_name if len(depth_texture_name) > 0 and depth_texture_name.lower() != "null" else defines.NULL
            # flags
            node.p2p = flags & EMITTER_FLAG_P2P != 0
            node.p2p_sel = flags & EMITTER_FLAG_P2P_SEL != 0
            node.affected_by_wind = flags & EMITTER_FLAG_AFFECTED_WIND != 0
            node.tinted = flags & EMITTER_FLAG_TINTED != 0
            node.bounce = flags & EMITTER_FLAG_BOUNCE != 0
            node.random = flags & EMITTER_FLAG_RANDOM != 0
            node.inherit = flags & EMITTER_FLAG_INHERIT != 0
            node.inheritvel = flags & EMITTER_FLAG_INHERIT_VEL != 0
            node.inherit_local = flags & EMITTER_FLAG_INHERIT_LOCAL != 0
            node.splat = flags & EMITTER_FLAG_SPLAT != 0
            node.inherit_part = flags & EMITTER_FLAG_INHERIT_PART != 0
            node.depth_texture = flags & EMITTER_FLAG_DEPTH_TEXTURE != 0

        if type_flags & NODE_REFERENCE:
            ref_model = self.mdl.get_c_string_up_to(32)
            reattachable = self.mdl.get_uint32()

            node.refmodel = ref_model
            node.reattachable = reattachable

        if type_flags & NODE_MESH:
            fn_ptr1 = self.mdl.get_uint32()
            fn_ptr2 = self.mdl.get_uint32()
            face_arr = self.get_array_def()
            bouding_box = [self.mdl.get_float() for _ in range(6)]
            radius = self.mdl.get_float()
            average = [self.mdl.get_float() for _ in range(3)]
            diffuse = [self.mdl.get_float() for _ in range(3)]
            ambient = [self.mdl.get_float() for _ in range(3)]
            transparency_hint = self.mdl.get_uint32()
            bitmap = self.mdl.get_c_string_up_to(32)
            bitmap2 = self.mdl.get_c_string_up_to(32)
            bitmap3 = self.mdl.get_c_string_up_to(12)
            bitmap4 = self.mdl.get_c_string_up_to(12)
            index_count_arr = self.get_array_def()
            index_offset_arr = self.get_array_def()
            inv_counter_arr = self.get_array_def()
            self.mdl.skip(3 * 4)  # unknown
            self.mdl.skip(8)  # saber unknown
            animate_uv = self.mdl.get_uint32()
            uv_dir_x = self.mdl.get_float()
            uv_dir_y = self.mdl.get_float()
            uv_jitter = self.mdl.get_float()
            uv_jitter_speed = self.mdl.get_float()
            mdx_data_size = self.mdl.get_uint32()
            mdx_data_bitmap = self.mdl.get_uint32()
            off_mdx_verts = self.mdl.get_uint32()
            off_mdx_normals = self.mdl.get_uint32()
            off_mdx_colors = self.mdl.get_uint32()
            off_mdx_uv1 = self.mdl.get_uint32()
            off_mdx_uv2 = self.mdl.get_uint32()
            off_mdx_uv3 = self.mdl.get_uint32()
            off_mdx_uv4 = self.mdl.get_uint32()
            off_mdx_tan_space1 = self.mdl.get_uint32()
            off_mdx_tan_space2 = self.mdl.get_uint32()
            off_mdx_tan_space3 = self.mdl.get_uint32()
            off_mdx_tan_space4 = self.mdl.get_uint32()
            num_verts = self.mdl.get_uint16()
            num_textures = self.mdl.get_uint16()
            has_lightmap = self.mdl.get_uint8()
            rotate_texture = self.mdl.get_uint8()
            background_geometry = self.mdl.get_uint8()
            shadow = self.mdl.get_uint8()
            beaming = self.mdl.get_uint8()
            render = self.mdl.get_uint8()

            if self.tsl:
                dirt_enabled = self.mdl.get_uint8()
                self.mdl.skip(1)  # padding
                dirt_texture = self.mdl.get_uint16()
                dirt_coord_space = self.mdl.get_uint16()
                hide_in_holograms = self.mdl.get_uint8()
                self.mdl.skip(1)  # padding

            self.mdl.skip(2)  # padding
            total_area = self.mdl.get_float()
            self.mdl.skip(4)  # padding
            mdx_offset = self.mdl.get_uint32()
            if not self.xbox:
                off_vert_arr = self.mdl.get_uint32()

            node.render = render
            node.shadow = shadow
            node.lightmapped = has_lightmap
            node.beaming = beaming
            node.tangentspace = 1 if mdx_data_bitmap & MDX_FLAG_TANGENT1 else 0
            node.rotatetexture = rotate_texture
            node.background_geometry = background_geometry
            node.animateuv = animate_uv
            node.uvdirectionx = uv_dir_x
            node.uvdirectiony = uv_dir_y
            node.uvjitter = uv_jitter
            node.uvjitterspeed = uv_jitter_speed
            node.transparencyhint = transparency_hint
            node.ambient = ambient
            node.diffuse = diffuse
            node.center = average

            if len(bitmap) > 0 and bitmap.lower() != "null":
                node.bitmap = bitmap
            if len(bitmap2) > 0 and bitmap2.lower() != "null":
                node.bitmap2 = bitmap2

            if self.tsl:
                node.dirt_enabled = dirt_enabled
                node.dirt_texture = dirt_texture
                node.dirt_worldspace = dirt_coord_space
                node.hologram_donotdraw = hide_in_holograms

        if type_flags & NODE_SKIN:
            unknown_arr = self.get_array_def()
            off_mdx_bone_weights = self.mdl.get_uint32()
            off_mdx_bone_indices = self.mdl.get_uint32()
            off_bonemap = self.mdl.get_uint32()
            num_bonemap = self.mdl.get_uint32()
            qbone_arr = self.get_array_def()
            tbone_arr = self.get_array_def()
            garbage_arr = self.get_array_def()
            bone_indices = [self.mdl.get_uint16() for _ in range(16)]
            self.mdl.skip(4)  # padding

        if type_flags & NODE_DANGLY:
            constraint_arr = self.get_array_def()
            displacement = self.mdl.get_float()
            tightness = self.mdl.get_float()
            period = self.mdl.get_float()
            off_vert_data = self.mdl.get_uint32()

            node.displacement = displacement
            node.period = period
            node.tightness = tightness

        if type_flags & NODE_AABB:
            off_root_aabb = self.mdl.get_uint32()
            self.load_aabb(off_root_aabb)

        if type_flags & NODE_SABER:
            off_saber_verts = self.mdl.get_uint32()
            off_saber_uv = self.mdl.get_uint32()
            off_saber_normals = self.mdl.get_uint32()
            inv_count1 = self.mdl.get_uint32()
            inv_count2 = self.mdl.get_uint32()

        if controller_arr.count > 0:
            controllers = self.load_controllers(controller_arr, controller_data_arr)
            if type_flags & NODE_MESH:
                node.alpha = controllers[CTRL_MESH_ALPHA][0][1] if CTRL_MESH_ALPHA in controllers else 1.0
                node.scale = controllers[CTRL_MESH_SCALE][0][1] if CTRL_MESH_SCALE in controllers else 1.0
                node.selfillumcolor = controllers[CTRL_MESH_SELFILLUMCOLOR][0][1:] if CTRL_MESH_SELFILLUMCOLOR in controllers else [0.0] * 3
            elif type_flags & NODE_LIGHT:
                node.radius = controllers[CTRL_LIGHT_RADIUS][0][1] if CTRL_LIGHT_RADIUS in controllers else 1.0
                node.multiplier = controllers[CTRL_LIGHT_MULTIPLIER][0][1] if CTRL_LIGHT_MULTIPLIER in controllers else 1.0
                node.color = controllers[CTRL_LIGHT_COLOR][0][1:] if CTRL_LIGHT_COLOR in controllers else [1.0] * 3
            elif type_flags & NODE_EMITTER:
                for val, key, dim in EMITTER_CONTROLLER_KEYS:
                    if val not in controllers:
                        continue
                    if dim == 1:
                        setattr(node, key, controllers[val][0][1])
                    else:
                        setattr(node, key, controllers[val][0][1:dim+1])

        if type_flags & NODE_LIGHT:
            self.mdl.seek(MDL_OFFSET + flare_size_arr.offset)
            node.flare_list.sizes = [self.mdl.get_float() for _ in range(flare_size_arr.count)]

            self.mdl.seek(MDL_OFFSET + flare_position_arr.offset)
            node.flare_list.positions = [self.mdl.get_float() for _ in range(flare_position_arr.count)]

            self.mdl.seek(MDL_OFFSET + flare_color_shift_arr.offset)
            for _ in range(flare_color_shift_arr.count):
                color_shift = [self.mdl.get_float() for _ in range(3)]
                node.flare_list.colorshifts.append(color_shift)

            self.mdl.seek(MDL_OFFSET + flare_tex_name_arr.offset)
            tex_name_offsets = [self.mdl.get_uint32() for _ in range(flare_tex_name_arr.count)]
            for tex_name_offset in tex_name_offsets:
                self.mdl.seek(MDL_OFFSET + tex_name_offset)
                node.flare_list.textures.append(self.mdl.get_c_string())

        if type_flags & NODE_SKIN:
            if num_bonemap > 0:
                self.mdl.seek(MDL_OFFSET + off_bonemap)
                if self.xbox:
                    bonemap = [self.mdl.get_uint16() for _ in range(num_bonemap)]
                else:
                    bonemap = [int(self.mdl.get_float()) for _ in range(num_bonemap)]
            else:
                bonemap = []
            node_by_bone = dict()
            for node_idx, bone_idx in enumerate(bonemap):
                if bone_idx == -1:
                    continue
                node_by_bone[bone_idx] = node_idx

        if type_flags & NODE_MESH:
            node.facelist = FaceList()
            if type_flags & NODE_SABER:
                for face in SABER_FACES:
                    node.facelist.vertices.append(face)
                    node.facelist.uv.append(face)
                    node.facelist.materials.append(0)
            elif face_arr.count > 0:
                self.mdl.seek(MDL_OFFSET + face_arr.offset)
                for _ in range(face_arr.count):
                    normal = [self.mdl.get_float() for _ in range(3)]
                    plane_distance = self.mdl.get_float()
                    material_id = self.mdl.get_uint32()
                    adjacent_faces = [self.mdl.get_uint16() for _ in range(3)]
                    vert_indices = [self.mdl.get_uint16() for _ in range(3)]
                    node.facelist.vertices.append(tuple(vert_indices))
                    node.facelist.uv.append(tuple(vert_indices))
                    node.facelist.materials.append(material_id)
                if index_count_arr.count > 0:
                    self.mdl.seek(MDL_OFFSET + index_count_arr.offset)
                    num_indices = self.mdl.get_uint32()
                if index_offset_arr.count > 0:
                    self.mdl.seek(MDL_OFFSET + index_offset_arr.offset)
                    off_indices = self.mdl.get_uint32()

            node.verts = []
            node.uv1 = []
            node.uv2 = []
            node.weights = []

            if type_flags & NODE_SABER:
                saber_verts = []
                self.mdl.seek(MDL_OFFSET + off_saber_verts)
                for i in range(NUM_SABER_VERTS):
                    saber_verts.append([self.mdl.get_float() for _ in range(3)])
                saber_tverts = []
                self.mdl.seek(MDL_OFFSET + off_saber_uv)
                for i in range(NUM_SABER_VERTS):
                    saber_tverts.append([self.mdl.get_float() for _ in range(2)])
                saber_normals = []
                self.mdl.seek(MDL_OFFSET + off_saber_normals)
                for i in range(NUM_SABER_VERTS):
                    saber_normals.append([self.mdl.get_float() for _ in range(3)])

                for i in range(8):
                    node.verts.append(saber_verts[i])
                    node.normals.append(saber_normals[i])
                    node.uv1.append(saber_tverts[i])
                for i in range(88, 96):
                    node.verts.append(saber_verts[i])
                    node.normals.append(saber_normals[i])
                    node.uv1.append(saber_tverts[i])

            elif mdx_data_size > 0:
                for i in range(num_verts):
                    self.mdx.seek(mdx_offset + i * mdx_data_size + off_mdx_verts)
                    node.verts.append(tuple([self.mdx.get_float() for _ in range(3)]))
                    if mdx_data_bitmap & MDX_FLAG_NORMAL:
                        self.mdx.seek(mdx_offset + i * mdx_data_size + off_mdx_normals)
                        if self.xbox:
                            comp = self.mdx.get_uint32()
                            node.normals.append(self.decompress_vector_xbox(comp))
                        else:
                            node.normals.append(tuple([self.mdx.get_float() for _ in range(3)]))
                    if mdx_data_bitmap & MDX_FLAG_UV1:
                        self.mdx.seek(mdx_offset + i * mdx_data_size + off_mdx_uv1)
                        node.uv1.append(tuple([self.mdx.get_float() for _ in range(2)]))
                    if mdx_data_bitmap & MDX_FLAG_UV2:
                        self.mdx.seek(mdx_offset + i * mdx_data_size + off_mdx_uv2)
                        node.uv2.append(tuple([self.mdx.get_float() for _ in range(2)]))
                    if type_flags & NODE_SKIN:
                        self.mdx.seek(mdx_offset + i * mdx_data_size + off_mdx_bone_weights)
                        bone_weights = [self.mdx.get_float() for _ in range(4)]
                        self.mdx.seek(mdx_offset + i * mdx_data_size + off_mdx_bone_indices)
                        if self.xbox:
                            bone_indices = [self.mdx.get_uint16() for _ in range(4)]
                        else:
                            bone_indices = [int(self.mdx.get_float()) for _ in range(4)]
                        vert_weights = []
                        for i in range(4):
                            bone_idx = bone_indices[i]
                            if bone_idx == -1:
                                continue
                            node_idx = node_by_bone[bone_idx]
                            node_name = self.node_names[node_idx]
                            vert_weights.append([node_name, bone_weights[i]])
                        node.weights.append(vert_weights)

        if type_flags & NODE_DANGLY:
            self.mdl.seek(MDL_OFFSET + constraint_arr.offset)
            node.constraints = [self.mdl.get_float() for _ in range(constraint_arr.count)]

        self.mdl.seek(MDL_OFFSET + children_arr.offset)
        child_offsets = [self.mdl.get_uint32() for _ in range(children_arr.count)]
        for child_idx, off_child in enumerate(child_offsets):
            child = self.load_nodes(off_child, child_idx, node)
            node.children.append(child)

        return node
Beispiel #12
0
def create_object(mu, muobj, parent):
    if muobj in mu.imported_objects:
        # the object has already been processed (probably an armature)
        return None
    mu.imported_objects.add(muobj)

    xform = muobj.transform

    component_data = []
    for component in muobj.components:
        if type(component) in type_handlers:
            data = type_handlers[type(component)](mu, muobj, component, xform.name)
            if data:
                component_data.append(data)
        else:
            print(f"unhandled component {component}")

    if muobj.transform.name == 'SkirtArmature':
        print(dir(muobj))
    if hasattr(muobj, "bone") and not component_data and not muobj.force_import:
        return None

    if hasattr(muobj, "armature_obj") or len(component_data) != 1:
        #empty or multiple components
        obj = None
        if hasattr(muobj, "armature_obj"):
            obj = muobj.armature_obj
            set_transform(obj, muobj.transform)
            mu.collection.objects.link(obj)
        if not obj:
            #if a mesh is present, use it for the main object
            for component in component_data:
                if component[0] == "mesh":
                    component_data.remove(component)
                    component = (None,) + component[1:]
                    obj = create_component_object(mu.collection, component,
                                                  xform.name, xform)
                    break
        if not obj:
            obj = create_data_object(mu.collection, xform.name, None, xform)
        for component in component_data:
            cobj = create_component_object(mu.collection, component,
                                           xform.name, None)
            cobj.parent = obj
    else:
        component = component_data[0]
        component = (None,) + component[1:]
        obj = create_component_object(mu.collection, component, xform.name,
                                      xform)
    if obj.name not in mu.collection.objects:
        mu.collection.objects.link(obj)

    if not obj.data:
        if xform.name[:5] == "node_":
            #print(name, xform.name[:5])
            obj.empty_display_type = 'SINGLE_ARROW'
            #print(obj.empty_display_type)
            # Blender's empties use the +Z axis for single-arrow
            # display, so that is the most natural orientation for
            # nodes in blender.
            # However, KSP uses the transform's +Z (Unity) axis which
            # is Blender's +Y, so rotate -90 degrees around local X to
            # go from KSP to Blender
            #print(obj.rotation_quaternion)
            rot = Quaternion((0.5**0.5, -(0.5**0.5), 0, 0))
            obj.rotation_quaternion @= rot
            #print(obj.rotation_quaternion)

    muobj.bobj = obj
    if hasattr(muobj, "bone") and hasattr(muobj, "armature"):
        set_transform(obj, None)
        parent_to_bone(obj, muobj.armature.armature_obj, muobj.bone)
    else:
        obj.parent = parent

    if hasattr(muobj, "tag_and_layer"):
        obj.muproperties.tag = muobj.tag_and_layer.tag
        obj.muproperties.layer = muobj.tag_and_layer.layer

    for child in muobj.children:
        create_object(mu, child, obj)
    if hasattr(muobj, "animation"):
        for clip in muobj.animation.clips:
            create_action(mu, muobj.path, clip)
    return obj
    def set_convert_functions(gltf):
        if bpy.app.debug_value != 100:
            # Unit conversion factor in (Blender units) per meter
            u = 1.0 / bpy.context.scene.unit_settings.scale_length

            # glTF Y-Up space --> Blender Z-up space
            # X,Y,Z --> X,-Z,Y
            def convert_loc(x):
                return u * Vector([x[0], -x[2], x[1]])

            def convert_quat(q):
                return Quaternion([q[3], q[0], -q[2], q[1]])

            def convert_scale(s):
                return Vector([s[0], s[2], s[1]])

            def convert_matrix(m):
                return Matrix([
                    [m[0], -m[8], m[4], m[12] * u],
                    [-m[2], m[10], -m[6], -m[14] * u],
                    [m[1], -m[9], m[5], m[13] * u],
                    [m[3] / u, -m[11] / u, m[7] / u, m[15]],
                ])

            # Batch versions operate in place on a numpy array
            def convert_locs_batch(locs):
                # x,y,z -> x,-z,y
                locs[:, [1, 2]] = locs[:, [2, 1]]
                locs[:, 1] *= -1
                # Unit conversion
                if u != 1: locs *= u

            def convert_normals_batch(ns):
                ns[:, [1, 2]] = ns[:, [2, 1]]
                ns[:, 1] *= -1

            # Correction for cameras and lights.
            # glTF: right = +X, forward = -Z, up = +Y
            # glTF after Yup2Zup: right = +X, forward = +Y, up = +Z
            # Blender: right = +X, forward = -Z, up = +Y
            # Need to carry Blender --> glTF after Yup2Zup
            gltf.camera_correction = Quaternion(
                (2**0.5 / 2, 2**0.5 / 2, 0.0, 0.0))

        else:

            def convert_loc(x):
                return Vector(x)

            def convert_quat(q):
                return Quaternion([q[3], q[0], q[1], q[2]])

            def convert_scale(s):
                return Vector(s)

            def convert_matrix(m):
                return Matrix([m[0::4], m[1::4], m[2::4], m[3::4]])

            def convert_locs_batch(_locs):
                return

            def convert_normals_batch(_ns):
                return

            # Same convention, no correction needed.
            gltf.camera_correction = None

        gltf.loc_gltf_to_blender = convert_loc
        gltf.locs_batch_gltf_to_blender = convert_locs_batch
        gltf.quaternion_gltf_to_blender = convert_quat
        gltf.normals_batch_gltf_to_blender = convert_normals_batch
        gltf.scale_gltf_to_blender = convert_scale
        gltf.matrix_gltf_to_blender = convert_matrix
def do_import(path, DELETE_TOP_BONE=True):

    # get scene
    scn = bpy.context.scene
    if scn == None:
        return "No scene to import to!"

    # open the file
    try:
        file = open(path, 'r')
    except IOError:
        return "Failed to open the file!"

    try:
        if not path.endswith(".cn6"):
            raise IOError
    except IOError:
        return "Must be an cn6 file!"

    # Load Armature
    try:
        lines = getNextLine(file).split()
        if len(lines) != 1 or lines[0] != "skeleton":
            raise ValueError
    except ValueError:
        return "File invalid!"

    # Before adding any meshes or armatures go into Object mode.
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='OBJECT')

    armature = bpy.data.armatures.new("Armature")
    armOb = bpy.data.objects.new("ArmatureObject", armature)
    armature.draw_type = 'STICK'
    scn.objects.link(armOb)
    scn.objects.active = armOb

    # read bones
    boneNames = []
    bpy.ops.object.editmode_toggle()
    bpy.types.EditBone.rot_matrix = bpy.props.FloatVectorProperty(
        name="Rot Matrix", size=9)

    currentLine = ""

    boneCount = 0
    boneNameDict = []
    parentBoneIds = []
    positions = []
    quaternions = []

    while (not currentLine.startswith('meshes')):
        currentLine = getNextLine(file)

        if (not currentLine.startswith('meshes')):
            lines = shlex.split(currentLine)
            boneNameDict.append(lines[1])
            parentBoneIds.append(int(lines[2]))
            positions.append(
                [float(lines[3]),
                 float(lines[4]),
                 float(lines[5])])
            quaternions.append([
                float(lines[6]),
                float(lines[7]),
                float(lines[8]),
                float(lines[9])
            ])
            boneCount = boneCount + 1

    print(boneNameDict)
    for i in range(boneCount):
        # read name
        fullName = boneNameDict[i]
        boneNames.append(fullName)
        bone = armature.edit_bones.new(fullName)

        # read parent
        if parentBoneIds[i] >= 0:
            parentBoneName = boneNameDict[
                parentBoneIds[i]]  #getNextLine(file)[1:-1]
            bone.parent = armature.bones.data.edit_bones[parentBoneName]

        pos = positions[i]
        quat = quaternions[i]

        # Granny Rotation Quaternions are stored X,Y,Z,W but Blender uses W,X,Y,Z
        quaternion = Quaternion((quat[3], quat[0], quat[1], quat[2]))
        rotMatrix = quaternion.to_matrix()
        rotMatrix.transpose(
        )  # Need to transpose to get same behaviour as 2.49 script

        print("Bone Data")
        print(fullName)
        print(pos)
        print(rotMatrix)

        boneLength = 3
        # set position and orientation
        if bone.parent:
            bone_parent_matrix = Matrix([[
                bone.parent.rot_matrix[0], bone.parent.rot_matrix[1],
                bone.parent.rot_matrix[2]
            ],
                                         [
                                             bone.parent.rot_matrix[3],
                                             bone.parent.rot_matrix[4],
                                             bone.parent.rot_matrix[5]
                                         ],
                                         [
                                             bone.parent.rot_matrix[6],
                                             bone.parent.rot_matrix[7],
                                             bone.parent.rot_matrix[8]
                                         ]])
            bone.head = Vector(pos) * bone_parent_matrix + bone.parent.head
            bone.tail = bone.head + Vector([boneLength, 0, 0])
            tempM = rotMatrix * bone_parent_matrix
            bone.rot_matrix = [
                tempM[0][0], tempM[0][1], tempM[0][2], tempM[1][0],
                tempM[1][1], tempM[1][2], tempM[2][0], tempM[2][1], tempM[2][2]
            ]
            bone.matrix = Matrix([[
                -bone.rot_matrix[3], bone.rot_matrix[0], bone.rot_matrix[6],
                bone.head[0]
            ],
                                  [
                                      -bone.rot_matrix[4], bone.rot_matrix[1],
                                      bone.rot_matrix[7], bone.head[1]
                                  ],
                                  [
                                      -bone.rot_matrix[5], bone.rot_matrix[2],
                                      bone.rot_matrix[8], bone.head[2]
                                  ], [0, 0, 0, 1]])
        else:
            bone.head = Vector(pos)
            bone.tail = bone.head + Vector([boneLength, 0, 0])
            bone.rot_matrix = [
                rotMatrix[0][0], rotMatrix[0][1], rotMatrix[0][2],
                rotMatrix[1][0], rotMatrix[1][1], rotMatrix[1][2],
                rotMatrix[2][0], rotMatrix[2][1], rotMatrix[2][2]
            ]
            bone.matrix = Matrix([[
                -bone.rot_matrix[3], bone.rot_matrix[0], bone.rot_matrix[6],
                bone.head[0]
            ],
                                  [
                                      -bone.rot_matrix[4], bone.rot_matrix[1],
                                      bone.rot_matrix[7], bone.head[1]
                                  ],
                                  [
                                      -bone.rot_matrix[5], bone.rot_matrix[2],
                                      bone.rot_matrix[8], bone.head[2]
                                  ], [0, 0, 0, 1]])

    # Roll fix for all bones
    for bone in armature.bones.data.edit_bones:
        roll = bone.roll
        bone.roll = roll - radians(90.0)

    # read the number of meshes
    try:
        lines = currentLine
        if not lines.startswith('meshes:'):
            raise ValueError
        numMeshes = int(lines.replace('meshes:', ''))
        if numMeshes < 0:
            raise ValueError
    except ValueError:
        return "Number of meshes is invalid!"

    # read meshes
    boneIds = [[], [], [], [], [], [], [], []]
    boneWeights = [[], [], [], [], [], [], [], []]
    meshVertexGroups = {}
    vCount = 0

    meshes = []
    meshObjects = []

    print('Num Meshes')
    print(numMeshes)

    for i in range(numMeshes):

        while (not currentLine.startswith('mesh:')):
            currentLine = getNextLine(file)

        lines = currentLine.split(':')

        meshName = lines[1][1:-1] + '#M'
        meshes.append(bpy.data.meshes.new(meshName))

        # read materials
        materialNames = []
        while (not currentLine.startswith('vertices')):
            currentLine = getNextLine(file)
            if (not currentLine.startswith('materials')
                    and not currentLine.startswith('vertices')):
                materialNames.append(currentLine[1:-1])

        print("materialNames")
        print(materialNames)

        # read vertices
        coords = []
        normals = []
        tangents = []
        binormals = []
        uvs = []
        uvs2 = []
        uvs3 = []
        numVerts = 0
        normalsTangentsBinormals = []
        originalTangentsBinormals = {}

        nonMatchingNormalTangentBinormal = True

        while (not currentLine.startswith('triangles')):
            currentLine = getNextLine(file)
            if (not currentLine.startswith('vertices')
                    and not currentLine.startswith('triangles')):
                lines = currentLine.split()
                if len(lines) != 34:
                    raise ValueError
                coords.append(
                    [float(lines[0]),
                     float(lines[1]),
                     float(lines[2])])
                normals.append(
                    [float(lines[3]),
                     float(lines[4]),
                     float(lines[5])])
                tangents.append(
                    [float(lines[6]),
                     float(lines[7]),
                     float(lines[8])])
                binormals.append(
                    [float(lines[9]),
                     float(lines[10]),
                     float(lines[11])])

                if (numVerts < 10):
                    #print("Normal/Tangent/Binormal Check")
                    #print(abs(float(lines[3]) - float(lines[6])))
                    #print(abs(float(lines[4]) - float(lines[7])))
                    #print(abs(float(lines[5]) - float(lines[8])))
                    if (abs(float(lines[3]) - float(lines[6])) < 0.000001 and
                            abs(float(lines[4]) - float(lines[7])) < 0.000001
                            and
                            abs(float(lines[5]) - float(lines[8])) < 0.000001
                            and
                            abs(float(lines[3]) - float(lines[9])) < 0.000001
                            and
                            abs(float(lines[4]) - float(lines[10])) < 0.000001
                            and abs(float(lines[5]) - float(lines[11])) <
                            0.000001):
                        nonMatchingNormalTangentBinormal = False
                    else:
                        nonMatchingNormalTangentBinormal = True

                uvs.append([float(lines[12]), 1 - float(lines[13])])
                uvs2.append([float(lines[14]), 1 - float(lines[15])])
                uvs3.append([float(lines[16]), 1 - float(lines[17])])

                normalsTangentsBinormals.append([
                    float(lines[3]),
                    float(lines[4]),
                    float(lines[5]),
                    float(lines[6]),
                    float(lines[7]),
                    float(lines[8]),
                    float(lines[9]),
                    float(lines[10]),
                    float(lines[11])
                ])

                boneIds[0].append(int(lines[18]))
                boneIds[1].append(int(lines[19]))
                boneIds[2].append(int(lines[20]))
                boneIds[3].append(int(lines[21]))
                boneIds[4].append(int(lines[22]))
                boneIds[5].append(int(lines[23]))
                boneIds[6].append(int(lines[24]))
                boneIds[7].append(int(lines[25]))

                boneWeights[0].append(float(lines[26]))
                boneWeights[1].append(float(lines[27]))
                boneWeights[2].append(float(lines[28]))
                boneWeights[3].append(float(lines[29]))
                boneWeights[4].append(float(lines[30]))
                boneWeights[5].append(float(lines[31]))
                boneWeights[6].append(float(lines[32]))
                boneWeights[7].append(float(lines[33]))

                meshVertexGroups[
                    vCount] = meshName  # uses the long mesh name - may be > 21 chars
                numVerts += 1

        #print ('nonMatchingNormalTangentBinormal:%s' % nonMatchingNormalTangentBinormal)

        meshes[i].vertices.add(len(coords))
        meshes[i].vertices.foreach_set("co", unpack_list(coords))
        meshOb = bpy.data.objects.new(meshName, meshes[i])

        for materialName in materialNames:
            material = bpy.data.materials.new(materialName)
            meshOb.data.materials.append(material)

        if (nonMatchingNormalTangentBinormal):
            meshOb.vertex_groups.new("VERTEX_KEYS")
            keyVertexGroup = meshOb.vertex_groups.get("VERTEX_KEYS")

            for v, vertex in enumerate(meshes[i].vertices):
                encoded_weight = (v / 2000000)
                keyVertexGroup.add([v], encoded_weight, 'ADD')
                #print ("encoded_weight {}".format(encoded_weight))
                #print ("vertex.bevel_weight {}".format(vertex.groups[keyVertexGroup.index].weight))
                originalTangentsBinormals[str(v)] = normalsTangentsBinormals[v]

        meshes[i]['originalTangentsBinormals'] = originalTangentsBinormals

        # read triangles
        faces = []
        while (not currentLine.startswith('mesh:')
               and not currentLine.startswith('end')):
            # read the triangle
            currentLine = getNextLine(file)
            if (not currentLine.startswith('mesh:')
                    and not currentLine.startswith('end')):
                lines = currentLine.split()
                if len(lines) != 4:  # Fourth element is material index
                    raise ValueError
                v1 = int(lines[0])
                v2 = int(lines[1])
                v3 = int(lines[2])
                mi = int(lines[3])

            if v1 < numVerts and v2 < numVerts and v3 < numVerts and mi < len(
                    materialNames):
                faces.append([v1, v2, v3, mi])

        # Create Meshes and import Normals
        mesh = meshes[i]
        mesh.loops.add(len(faces) * 3)
        mesh.polygons.add(len(faces))

        loops_vert_idx = []
        faces_loop_start = []
        faces_loop_total = []
        faces_material_index = []
        lidx = 0
        for f in faces:
            vidx = [f[0], f[1], f[2]]
            nbr_vidx = len(vidx)
            loops_vert_idx.extend(vidx)
            faces_loop_start.append(lidx)
            faces_loop_total.append(nbr_vidx)
            faces_material_index.append(f[3])
            lidx += nbr_vidx

        mesh.loops.foreach_set("vertex_index", loops_vert_idx)
        mesh.polygons.foreach_set("loop_start", faces_loop_start)
        mesh.polygons.foreach_set("loop_total", faces_loop_total)
        mesh.polygons.foreach_set("material_index", faces_material_index)

        mesh.create_normals_split()

        mesh.uv_textures.new('UV1')
        mesh.uv_textures.new('UV2')
        mesh.uv_textures.new('UV3')

        for l in mesh.loops:
            l.normal[:] = normals[l.vertex_index]
            mesh.uv_layers[0].data[l.index].uv = uvs[l.vertex_index]
            mesh.uv_layers[1].data[l.index].uv = uvs2[l.vertex_index]
            mesh.uv_layers[2].data[l.index].uv = uvs3[l.vertex_index]

        mesh.validate(clean_customdata=False)

        clnors = array.array('f', [0.0] * (len(mesh.loops) * 3))
        mesh.loops.foreach_get("normal", clnors)

        mesh.polygons.foreach_set("use_smooth", [True] * len(mesh.polygons))

        mesh.normals_split_custom_set(tuple(zip(*(iter(clnors), ) * 3)))
        mesh.use_auto_smooth = True
        mesh.show_edge_sharp = True

        #mesh.free_normals_split()
        ####NORMALS - End

        meshObjects.append(meshOb)
        scn.objects.link(meshObjects[i])

    for mesh in meshes:
        mesh.update()

    # Create Vertex Groups
    vi = 0
    for meshOb in meshObjects:
        mesh = meshOb.data
        for mvi, vertex in enumerate(mesh.vertices):
            for bi in range(boneCount):
                for j in range(8):
                    if bi == boneIds[j][vi]:
                        name = boneNames[bi]
                        if not meshOb.vertex_groups.get(name):
                            meshOb.vertex_groups.new(name)
                        grp = meshOb.vertex_groups.get(name)
                        normalizedWeight = boneWeights[j][vi] / 255
                        grp.add([mvi], normalizedWeight, 'ADD')
                        #print('Vertex: %d; Index: %d; Bone: %s; Weight: %f; ' % (mvi, j, name, normalizedWeight))
            vi = vi + 1

        # Give mesh object an armature modifier, using vertex groups but not envelopes
        mod = meshOb.modifiers.new('mod_' + mesh.name, 'ARMATURE')
        mod.object = armOb
        mod.use_bone_envelopes = False
        mod.use_vertex_groups = True
        # Parent Mesh Object to Armature Object
        meshOb.parent = armOb
        meshOb.parent_type = 'ARMATURE'

    if DELETE_TOP_BONE:
        # Adjust object names, remove top bone for Civ V
        bone = armature.bones.data.edit_bones[boneNames[0]]
        while not bone.parent is None:
            bone = bone.parent

        print('Found World Bone: %s' % bone.name)

        name = bone.name
        armOb.name = name

        # Delete top bone unless that would leave zero bones
        if (len(armature.bones.data.edit_bones) > 1):
            bpy.ops.object.select_pattern(pattern=name)
            bpy.ops.armature.delete()

    bpy.ops.object.editmode_toggle()
    bpy.ops.object.editmode_toggle()
    bpy.ops.object.editmode_toggle()

    return ""
 def matrix_quaternion(self, q):
     return Quaternion([q[0], q[1], q[2], q[3]])
Beispiel #16
0
def read_bones(self, context, filepath, root):

    skeleton_node = root.find("Skeleton")
    if (skeleton_node == None):
        return None, None

    bones = []
    bones_tag = []
    flags_list = []
    # LimitRotation and Unk0 have their special meanings, can be deduced if needed when exporting
    flags_restricted = set(["LimitRotation", "Unk0"])
    drawable_name = root.find("Name").text.split(".")[0]
    bones_node = skeleton_node.find("Bones")
    armature = context.object
    bpy.ops.object.mode_set(mode='EDIT')

    for bones_item in bones_node:
        name_item = bones_item.find("Name")
        tag_item = bones_item.find("Tag")
        parentindex_item = bones_item.find("ParentIndex")
        flags_item = bones_item.find("Flags")
        translation_item = bones_item.find("Translation")
        rotation_item = bones_item.find("Rotation")
        scale_item = bones_item.find("Scale")

        quaternion = Quaternion()
        quaternion.w = float(rotation_item.attrib["w"])
        quaternion.x = float(rotation_item.attrib["x"])
        quaternion.y = float(rotation_item.attrib["y"])
        quaternion.z = float(rotation_item.attrib["z"])
        mat_rot = quaternion.to_matrix().to_4x4()

        trans = Vector()
        trans.x = float(translation_item.attrib["x"])
        trans.y = float(translation_item.attrib["y"])
        trans.z = float(translation_item.attrib["z"])
        mat_loc = Matrix.Translation(trans)

        scale = Vector()
        scale.x = float(scale_item.attrib["x"])
        scale.y = float(scale_item.attrib["y"])
        scale.z = float(scale_item.attrib["z"])
        mat_sca = Matrix.Scale(1, 4, scale)

        edit_bone = armature.data.edit_bones.new(name_item.text)
        # edit_bone.bone_id = int(bone_tag.attrib["value"])
        if parentindex_item.attrib["value"] != "-1":
            edit_bone.parent = armature.data.edit_bones[int(
                parentindex_item.attrib["value"])]

        # https://github.com/LendoK/Blender_GTA_V_model_importer/blob/master/importer.py
        edit_bone.head = (0, 0, 0)
        edit_bone.tail = (0, 0.05, 0)
        edit_bone.matrix = mat_loc @ mat_rot @ mat_sca
        if edit_bone.parent != None:
            edit_bone.matrix = edit_bone.parent.matrix @ edit_bone.matrix

        if (flags_item != None and flags_item.text != None):
            flags = flags_item.text.strip().split(", ")

        flags_list.append(flags)

        # build a bones lookup table
        bones.append(name_item.text)
        bones_tag.append(int(tag_item.get('value')))

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

    for i in range(len(bones)):
        armature.pose.bones[i].bone.bone_properties.tag = bones_tag[i]
        for _flag in flags_list[i]:
            if (_flag in flags_restricted):
                continue

            flag = armature.pose.bones[i].bone.bone_properties.flags.add()
            flag.name = _flag

    bpy.ops.object.mode_set(mode='OBJECT')
    return bones, drawable_name
Beispiel #17
0
def importWoWOBJ(objectFile, givenParent=None):
    baseDir, fileName = os.path.split(objectFile)

    print('Parsing OBJ: ' + fileName)
    ### OBJ wide
    material_libs = set()
    mtlfile = ""
    verts = []
    normals = []
    uv = []
    meshes = []

    ### Per group
    class OBJMesh:
        def __init__(self):
            self.usemtl = ""
            self.name = ""
            self.faces = []

    curMesh = OBJMesh()
    meshIndex = -1
    with open(objectFile, 'rb') as f:
        for line in f:
            line_split = line.split()
            if not line_split:
                continue
            line_start = line_split[0]
            if line_start == b'mtllib':
                mtlfile = line_split[1]
            elif line_start == b'v':
                verts.append([float(v) for v in line_split[1:]])
            elif line_start == b'vn':
                normals.append([float(v) for v in line_split[1:]])
            elif line_start == b'vt':
                uv.append([float(v) for v in line_split[1:]])
            elif line_start == b'f':
                line_split = line_split[1:]
                meshes[meshIndex].faces.append(
                    (int(line_split[0].split(b'/')[0]),
                     int(line_split[1].split(b'/')[0]),
                     int(line_split[2].split(b'/')[0])))
            elif line_start == b'g':
                meshIndex += 1
                meshes.append(OBJMesh())
                meshes[meshIndex].name = line_split[1].decode("utf-8")
            elif line_start == b'usemtl':
                meshes[meshIndex].usemtl = line_split[1].decode("utf-8")

    ## Materials file (.mtl)
    materials = dict()
    matname = ""
    matfile = ""

    with open(os.path.join(baseDir, mtlfile.decode("utf-8")), 'r') as f:
        for line in f:
            line_split = line.split()
            if not line_split:
                continue
            line_start = line_split[0]

            if line_start == 'newmtl':
                matname = line_split[1]
            elif line_start == 'map_Kd':
                matfile = line_split[1]
                materials[matname] = os.path.join(baseDir, matfile)

    if bpy.ops.object.select_all.poll():
        bpy.ops.object.select_all(action='DESELECT')

    # TODO: Better handling for dupes?
    objname = os.path.basename(objectFile)

    if objname in bpy.data.objects:
        objindex = 1
        newname = objname
        while (newname in bpy.data.objects):
            newname = objname + '.' + str(objindex).rjust(3, '0')
            objindex += 1

    newmesh = bpy.data.meshes.new(objname)
    obj = bpy.data.objects.new(objname, newmesh)

    ## Textures
    # TODO: Must be a better way to do this!
    materialmapping = dict()

    for matname, texturelocation in materials.items():
        # Import material only once
        if (matname not in bpy.data.materials):
            mat = bpy.data.materials.new(name=matname)
            mat.use_nodes = True
            mat.blend_method = 'CLIP'
            principled = PrincipledBSDFWrapper(mat, is_readonly=False)
            principled.specular = 0.0
            principled.base_color_texture.image = load_image(texturelocation)
            mat.node_tree.links.new(
                mat.node_tree.nodes['Image Texture'].outputs[1],
                mat.node_tree.nodes['Principled BSDF'].inputs[18])

        obj.data.materials.append(bpy.data.materials[matname])

        # TODO: Must be a better way to do this!
        materialmapping[matname] = len(obj.data.materials) - 1

    ## Meshes
    bm = bmesh.new()

    i = 0
    for v in verts:
        vert = bm.verts.new(v)
        vert.normal = normals[i]
        i = i + 1

    bm.verts.ensure_lookup_table()
    bm.verts.index_update()

    for mesh in meshes:
        exampleFaceSet = False
        for face in mesh.faces:
            try:
                ## TODO: Must be a better way to do this, this is already much faster than doing material every face, but still.
                if exampleFaceSet == False:
                    bm.faces.new((bm.verts[face[0] - 1], bm.verts[face[1] - 1],
                                  bm.verts[face[2] - 1]))
                    bm.faces.ensure_lookup_table()
                    bm.faces[-1].material_index = materialmapping[mesh.usemtl]
                    bm.faces[-1].smooth = True
                    exampleFace = bm.faces[-1]
                    exampleFaceSet = True
                else:
                    ## Use example face if set to speed up material copy!
                    bm.faces.new((bm.verts[face[0] - 1], bm.verts[face[1] - 1],
                                  bm.verts[face[2] - 1]), exampleFace)
            except ValueError:
                ## TODO: Duplicate faces happen for some reason
                pass

    uv_layer = bm.loops.layers.uv.new()
    for face in bm.faces:
        for loop in face.loops:
            loop[uv_layer].uv = uv[loop.vert.index]

    bm.to_mesh(newmesh)
    bm.free()

    ## Rotate object the right way
    obj.rotation_euler = [0, 0, 0]
    obj.rotation_euler.x = radians(90)

    bpy.context.scene.collection.objects.link(obj)
    obj.select_set(True)

    ## WoW coordinate system
    max_size = 51200 / 3
    map_size = max_size * 2
    adt_size = map_size / 64

    ## Import doodads and/or WMOs
    csvPath = objectFile.replace('.obj', '_ModelPlacementInformation.csv')

    if os.path.exists(csvPath):
        with open(csvPath) as csvFile:
            reader = csv.DictReader(csvFile, delimiter=';')
            if 'Type' in reader.fieldnames:
                importType = 'ADT'

                wmoparent = bpy.data.objects.new("WMOs", None)
                wmoparent.parent = obj
                wmoparent.name = "WMOs"
                wmoparent.rotation_euler = [0, 0, 0]
                wmoparent.rotation_euler.x = radians(-90)
                bpy.context.scene.collection.objects.link(wmoparent)

                doodadparent = bpy.data.objects.new("Doodads", None)
                doodadparent.parent = obj
                doodadparent.name = "Doodads"
                doodadparent.rotation_euler = [0, 0, 0]
                doodadparent.rotation_euler.x = radians(-90)
                bpy.context.scene.collection.objects.link(doodadparent)
            else:
                importType = 'WMO'
                if not givenParent:
                    print('WMO import without given parent, creating..')
                    givenParent = bpy.data.objects.new("WMO parent", None)
                    givenParent.parent = obj
                    givenParent.name = "Doodads"
                    givenParent.rotation_euler = [0, 0, 0]
                    givenParent.rotation_euler.x = radians(-90)
                    bpy.context.scene.collection.objects.link(givenParent)
            for row in reader:
                if importType == 'ADT':
                    if 'importedModelIDs' in bpy.context.scene:
                        tempModelIDList = bpy.context.scene['importedModelIDs']
                    else:
                        tempModelIDList = []
                    if row['ModelId'] in tempModelIDList:
                        print('Skipping already imported model ' +
                              row['ModelId'])
                        continue
                    else:
                        tempModelIDList.append(row['ModelId'])

                    # ADT CSV
                    if row['Type'] == 'wmo':
                        print('ADT WMO import: ' + row['ModelFile'])

                        # Make WMO parent that holds WMO and doodads
                        parent = bpy.data.objects.new(
                            row['ModelFile'] + " parent", None)
                        parent.parent = wmoparent
                        parent.location = (17066 - float(row['PositionX']),
                                           (17066 - float(row['PositionZ'])) *
                                           -1, float(row['PositionY']))
                        parent.rotation_euler = [0, 0, 0]
                        parent.rotation_euler.x += radians(
                            float(row['RotationZ']))
                        parent.rotation_euler.y += radians(
                            float(row['RotationX']))
                        parent.rotation_euler.z = radians(
                            (-90 + float(row['RotationY'])))
                        if row['ScaleFactor']:
                            parent.scale = (float(row['ScaleFactor']),
                                            float(row['ScaleFactor']),
                                            float(row['ScaleFactor']))
                        bpy.context.scene.collection.objects.link(parent)

                        ## Only import OBJ if model is not yet in scene, otherwise copy existing
                        if row['ModelFile'] not in bpy.data.objects:
                            importedFile = importWoWOBJ(
                                os.path.join(baseDir, row['ModelFile']),
                                parent)
                        else:
                            ## Don't copy WMOs with doodads!
                            if os.path.exists(
                                    os.path.join(
                                        baseDir, row['ModelFile'].replace(
                                            '.obj',
                                            '_ModelPlacementInformation.csv'))
                            ):
                                importedFile = importWoWOBJ(
                                    os.path.join(baseDir, row['ModelFile']),
                                    parent)
                            else:
                                originalObject = bpy.data.objects[
                                    row['ModelFile']]
                                importedFile = originalObject.copy()
                                importedFile.data = originalObject.data.copy()
                                bpy.context.scene.collection.objects.link(
                                    importedFile)

                        importedFile.parent = parent
                    elif row['Type'] == 'm2':
                        print('ADT M2 import: ' + row['ModelFile'])

                        ## Only import OBJ if model is not yet in scene, otherwise copy existing
                        if row['ModelFile'] not in bpy.data.objects:
                            importedFile = importWoWOBJ(
                                os.path.join(baseDir, row['ModelFile']))
                        else:
                            originalObject = bpy.data.objects[row['ModelFile']]
                            importedFile = originalObject.copy()
                            importedFile.rotation_euler = [0, 0, 0]
                            importedFile.rotation_euler.x = radians(90)
                            bpy.context.scene.collection.objects.link(
                                importedFile)

                        importedFile.parent = doodadparent

                        importedFile.location.x = (17066 -
                                                   float(row['PositionX']))
                        importedFile.location.y = (
                            17066 - float(row['PositionZ'])) * -1
                        importedFile.location.z = float(row['PositionY'])
                        importedFile.rotation_euler.x += radians(
                            float(row['RotationZ']))
                        importedFile.rotation_euler.y += radians(
                            float(row['RotationX']))
                        importedFile.rotation_euler.z = radians(
                            90 + float(row['RotationY']))
                        if row['ScaleFactor']:
                            importedFile.scale = (float(row['ScaleFactor']),
                                                  float(row['ScaleFactor']),
                                                  float(row['ScaleFactor']))
                    bpy.context.scene['importedModelIDs'] = tempModelIDList
                else:
                    # WMO CSV
                    print('WMO M2 import: ' + row['ModelFile'])
                    if row['ModelFile'] not in bpy.data.objects:
                        importedFile = importWoWOBJ(
                            os.path.join(baseDir, row['ModelFile']))
                    else:
                        originalObject = bpy.data.objects[row['ModelFile']]
                        importedFile = originalObject.copy()
                        bpy.context.scene.collection.objects.link(importedFile)

                    importedFile.location = (float(row['PositionX']) * -1,
                                             float(row['PositionY']) * -1,
                                             float(row['PositionZ']))

                    importedFile.rotation_euler = [0, 0, 0]
                    rotQuat = Quaternion(
                        (float(row['RotationW']), float(row['RotationX']),
                         float(row['RotationY']), float(row['RotationZ'])))
                    rotEul = rotQuat.to_euler()
                    rotEul.x += radians(90)
                    rotEul.z += radians(180)
                    importedFile.rotation_euler = rotEul
                    importedFile.parent = givenParent or obj
                    if row['ScaleFactor']:
                        importedFile.scale = (float(row['ScaleFactor']),
                                              float(row['ScaleFactor']),
                                              float(row['ScaleFactor']))

    return obj


#objectFile = "D:\\models\\world\\maps\\azeroth\\azeroth_32_32.obj"
#objectFile = "D:\\models\\world\\maps\\kultiras\\kultiras_32_29.obj"
#objectFile = "D:\\models\\world\\wmo\\kultiras\\human\\8hu_kultiras_seabattlement01.obj"
#importWoWOBJ(objectFile)
 def getValue(self):
     return Quaternion(self.value)
def __gather_children(blender_object, export_settings):
    children = []
    # standard children
    for child_object in blender_object.children:
        if child_object.parent_bone:
            # this is handled further down,
            # as the object should be a child of the specific bone,
            # not the Armature object
            continue
        node = gather_node(child_object, export_settings)
        if node is not None:
            children.append(node)
    # blender dupli objects
    if bpy.app.version < (2, 80, 0):
        if blender_object.dupli_type == 'GROUP' and blender_object.dupli_group:
            for dupli_object in blender_object.dupli_group.objects:
                node = gather_node(dupli_object, export_settings)
                if node is not None:
                    children.append(node)
    else:
        if blender_object.instance_type == 'COLLECTION' and blender_object.instance_collection:
            for dupli_object in blender_object.instance_collection.objects:
                node = gather_node(dupli_object, export_settings)
                if node is not None:
                    children.append(node)

    # blender bones
    if blender_object.type == "ARMATURE":
        root_joints = []
        for blender_bone in blender_object.pose.bones:
            if not blender_bone.parent:
                joint = gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)
                children.append(joint)
                root_joints.append(joint)
        # handle objects directly parented to bones
        direct_bone_children = [child for child in blender_object.children if child.parent_bone]
        def find_parent_joint(joints, name):
            for joint in joints:
                if joint.name == name:
                    return joint
                parent_joint = find_parent_joint(joint.children, name)
                if parent_joint:
                    return parent_joint
            return None
        for child in direct_bone_children:
            # find parent joint
            parent_joint = find_parent_joint(root_joints, child.parent_bone)
            if not parent_joint:
                continue
            child_node = gather_node(child, export_settings)
            if child_node is None:
                continue
            blender_bone = blender_object.pose.bones[parent_joint.name]
            # fix rotation
            if export_settings[gltf2_blender_export_keys.YUP]:
                rot = child_node.rotation
                if rot is None:
                    rot = [0, 0, 0, 1]

                rot_quat = Quaternion(rot)
                axis_basis_change = Matrix(
                    ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, -1.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0)))
                mat = gltf2_blender_math.multiply(axis_basis_change, child.matrix_basis)
                mat = gltf2_blender_math.multiply(child.matrix_parent_inverse, mat)

                _, rot_quat, _ = mat.decompose()
                child_node.rotation = [rot_quat[1], rot_quat[2], rot_quat[3], rot_quat[0]]

            # fix translation (in blender bone's tail is the origin for children)
            trans, _, _ = child.matrix_local.decompose()
            if trans is None:
                trans = [0, 0, 0]
            # bones go down their local y axis
            bone_tail = [0, blender_bone.length, 0]
            child_node.translation = [trans[idx] + bone_tail[idx] for idx in range(3)]

            parent_joint.children.append(child_node)

    return children
 def getDefaultValue(cls):
     return Quaternion((1, 0, 0, 0))
Beispiel #21
0
def convert_quaternion(q):
    """Converts a glTF quaternion to Blender a quaternion."""
    # xyzw -> wxyz
    return Quaternion([q[3], q[0], q[1], q[2]])
Beispiel #22
0
def doodads(self, object1, mesh1, dmin, dmax):
    """function to generate the doodads"""
    global dVerts
    global dPolygons
    i = 0
    # on parcoure cette boucle pour ajouter des doodads a toutes les polygons
    # english translation: this loops adds doodads to all polygons
    while (i < len(object1.data.polygons)):
        if object1.data.polygons[i].select is False:
            continue

        doods_nbr = random.randint(dmin, dmax)
        j = 0

        while (j <= doods_nbr):
            origin_dood = randVertex(object1.data.polygons[i].vertices[0],
                                     object1.data.polygons[i].vertices[1],
                                     object1.data.polygons[i].vertices[2],
                                     object1.data.polygons[i].vertices[3],
                                     Verts)
            type_dood = random.randint(0, len(self.DISC_doodads) - 1)
            polygons_add = []
            verts_add = []

            # First we have to apply scaling and rotation to the mesh
            bpy.ops.object.select_pattern(pattern=self.DISC_doodads[type_dood],
                                          extend=False)
            bpy.context.view_layer.objects.active = bpy.data.objects[
                self.DISC_doodads[type_dood]]
            bpy.ops.object.transform_apply(location=False,
                                           rotation=True,
                                           scale=True)

            for polygon in bpy.data.objects[
                    self.DISC_doodads[type_dood]].data.polygons:
                polygons_add.append(polygon.vertices)
            for vertex in bpy.data.objects[
                    self.DISC_doodads[type_dood]].data.vertices:
                verts_add.append(vertex.co.copy())
            normal_original_polygon = object1.data.polygons[i].normal

            nor_def = Vector((0.0, 0.0, 1.0))
            qr = nor_def.rotation_difference(
                normal_original_polygon.normalized())

            if (test_v2_near_v1(nor_def, -normal_original_polygon)):
                qr = Quaternion((0.0, 0.0, 0.0, 0.0))

            # qr = angle_between_nor(nor_def, normal_original_polygon)
            for vertex in verts_add:
                vertex.rotate(qr)
                vertex += origin_dood
            findex = len(dVerts)

            for polygon in polygons_add:
                dPolygons.append([
                    polygon[0] + findex, polygon[1] + findex,
                    polygon[2] + findex, polygon[3] + findex
                ])
                i_dood_type.append(
                    bpy.data.objects[self.DISC_doodads[type_dood]].name)

            for vertex in verts_add:
                dVerts.append(vertex)
            j += 1
        i += 5
Beispiel #23
0
 def roll_left(self, angle):
     """Roll the turtle left about the direction it is facing"""
     self.right.rotate(Quaternion(self.dir, radians(-angle)))
     self.right.normalize()
Beispiel #24
0
 def perpendicular_direction(self):
     q0 = Quaternion(Vector((42, 1.618034, 2.71828)), 1.5707963)
     q1 = Quaternion(Vector((1.41421, 2, 1.73205)), -1.5707963)
     v = q1 * q0 * self
     return Direction(self.cross(v))
Beispiel #25
0
    def create(gltf, scene_idx):
        """Scene creation."""
        if scene_idx is not None:
            pyscene = gltf.data.scenes[scene_idx]
            list_nodes = pyscene.nodes

            # Create a new scene only if not already exists in .blend file
            # TODO : put in current scene instead ?
            if pyscene.name not in [scene.name for scene in bpy.data.scenes]:
                # TODO: There is a bug in 2.8 alpha that break CLEAR_KEEP_TRANSFORM
                # if we are creating a new scene
                scene = bpy.context.scene
                scene.render.engine = "BLENDER_EEVEE"

                gltf.blender_scene = scene.name
            else:
                gltf.blender_scene = pyscene.name

            # Switch to newly created main scene
            bpy.context.window.scene = bpy.data.scenes[gltf.blender_scene]

        else:
            # No scene in glTF file, create all objects in current scene
            scene = bpy.context.scene
            scene.render.engine = "BLENDER_EEVEE"
            gltf.blender_scene = scene.name
            list_nodes = BlenderScene.get_root_nodes(gltf)

        # Create Yup2Zup empty
        obj_rotation = bpy.data.objects.new("Yup2Zup", None)
        obj_rotation.rotation_mode = 'QUATERNION'
        obj_rotation.rotation_quaternion = Quaternion(
            (sqrt(2) / 2, sqrt(2) / 2, 0.0, 0.0))

        bpy.data.scenes[gltf.blender_scene].collection.objects.link(
            obj_rotation)

        if list_nodes is not None:
            for node_idx in list_nodes:
                BlenderNode.create(gltf, node_idx, None)  # None => No parent

        # Now that all mesh / bones are created, create vertex groups on mesh
        if gltf.data.skins:
            for skin_id, skin in enumerate(gltf.data.skins):
                if hasattr(skin, "node_ids"):
                    BlenderSkin.create_vertex_groups(gltf, skin_id)

            for skin_id, skin in enumerate(gltf.data.skins):
                if hasattr(skin, "node_ids"):
                    BlenderSkin.assign_vertex_groups(gltf, skin_id)

            for skin_id, skin in enumerate(gltf.data.skins):
                if hasattr(skin, "node_ids"):
                    BlenderSkin.create_armature_modifiers(gltf, skin_id)

        if gltf.data.animations:
            gltf.animation_managed = []
            for anim_idx, anim in enumerate(gltf.data.animations):
                gltf.current_animation_names = {}
                if list_nodes is not None:
                    for node_idx in list_nodes:
                        BlenderAnimation.anim(gltf, anim_idx, node_idx)
                for an in gltf.current_animation_names.values():
                    gltf.animation_managed.append(an)

        # Parent root node to rotation object
        if list_nodes is not None:
            exclude_nodes = []
            for node_idx in list_nodes:
                if gltf.data.nodes[node_idx].is_joint:
                    # Do not change parent if root node is already parented (can be the case for skinned mesh)
                    if not bpy.data.objects[gltf.data.nodes[node_idx].
                                            blender_armature_name].parent:
                        bpy.data.objects[
                            gltf.data.nodes[node_idx].
                            blender_armature_name].parent = obj_rotation
                    else:
                        exclude_nodes.append(node_idx)
                else:
                    # Do not change parent if root node is already parented (can be the case for skinned mesh)
                    if not bpy.data.objects[
                            gltf.data.nodes[node_idx].blender_object].parent:
                        bpy.data.objects[gltf.data.nodes[node_idx].
                                         blender_object].parent = obj_rotation
                    else:
                        exclude_nodes.append(node_idx)

            if gltf.animation_object is False:

                for node_idx in list_nodes:

                    if node_idx in exclude_nodes:
                        continue  # for root node that are parented by the process
                        # for example skinned meshes

                    for obj_ in bpy.context.scene.objects:
                        obj_.select_set(False)
                    if gltf.data.nodes[node_idx].is_joint:
                        bpy.data.objects[gltf.data.nodes[
                            node_idx].blender_armature_name].select_set(True)
                        bpy.context.view_layer.objects.active = bpy.data.objects[
                            gltf.data.nodes[node_idx].blender_armature_name]

                    else:
                        bpy.data.objects[gltf.data.nodes[node_idx].
                                         blender_object].select_set(True)
                        bpy.context.view_layer.objects.active = bpy.data.objects[
                            gltf.data.nodes[node_idx].blender_object]

                    bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM')

                # remove object
                bpy.context.scene.collection.objects.unlink(obj_rotation)
                bpy.data.objects.remove(obj_rotation)
Beispiel #26
0
 def __init__(self):
     self.translation = Vector((0, 0, 0))
     self.rotation = Quaternion()
     self.scale = 1
Beispiel #27
0
    def loadAnimation(self, path):
        data = self.teaSerializer.read(path)

        selectedObj = bpy.context.active_object

        #Walk up object tree to amature
        walkObj = selectedObj
        while not walkObj.name.endswith('-amt') and walkObj.parent:
            walkObj = walkObj.parent

        if not walkObj.name.endswith('-amt'):
            self.log.warning("Amature object nof found for: {}".format(
                obj.name))
            return

        armatureObj = walkObj
        obj = walkObj.children[0]

        bones = armatureObj.pose.bones

        bpy.context.scene.frame_set(1)
        for frame in data:
            bpy.context.scene.objects.active = obj

            if frame.translation:
                translation = frame.translation
                obj.location = (translation.x, translation.y, translation.z)
                obj.keyframe_insert(data_path='location')

            if frame.rotation:
                rotation = frame.rotation
                obj.rotation_quaternion = (rotation.w, rotation.x, rotation.y,
                                           rotation.z)
                obj.keyframe_insert(data_path='rotation_quaternion')

            #bpy.ops.anim.keyframe_insert(type='LocRotScale', confirm_success=False)

            bpy.context.scene.objects.active = armatureObj
            bpy.ops.object.mode_set(mode='POSE')

            if len(bones) != len(frame.groups):
                #raise InconsistentStateException("Bones in amature must match animation groups, existing {} new {}".format(len(bones), len(frame['groups'])))
                log.warning(
                    "Bones in amature must match animation groups, existing {} new {}"
                    .format(len(bones), len(frame.groups)))
                #break

            # This seems to be required to handle mismatched data
            maxBone = min(len(bones), len(frame.groups))

            for groupIndex in range(maxBone - 1, -1,
                                    -1):  # group index = bone index
                group = frame.groups[groupIndex]
                bone = bones[groupIndex]
                location = Vector(
                    (group.translate.x, group.translate.y, group.translate.z))
                #self.log.info("moving bone to %s" % str(group.translate))
                #bone.location = location
                rotation = Quaternion((group.Quaternion.w, group.Quaternion.x,
                                       group.Quaternion.y, group.Quaternion.z))
                #self.log.info("rotating bone to %s" % str(rotation))
                bone.rotation_quaternion = rotation
                scale = Vector((group.zoom.x, group.zoom.y, group.zoom.z))
                #self.log.info("scaling bone to %s" % str(group.zoom))
                #bone.scale = scale
                bone.keyframe_insert(data_path="location")
                bone.keyframe_insert(data_path="rotation_quaternion")
                bone.keyframe_insert(data_path="scale")
                #bpy.ops.anim.keyframe_insert(type='LocRotScale', confirm_success=False)
                # FIXME translation and zoom are both 0,0,0
                # TODO keyframes of rotation are glitchy. probably cause im not doing it right. keyframe has to be set via bpy.ops.anim.keyframe_insert but i dont know how to select the bone.

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

            bpy.context.scene.frame_set(bpy.context.scene.frame_current +
                                        frame.duration)
            #self.log.info("Loaded Frame")
        bpy.context.scene.frame_end = bpy.context.scene.frame_current
 def quaternion(self, q):
     return Quaternion([q[3], q[0], q[1], q[2]])
Beispiel #29
0
 def _read_quaternion(self, f):
     x, y, z, w = unpack('4f', f)
     return Quaternion((w, x, y, z))
def createAnnotationRotateGiz(group, annotationGen, objIndex):
    # Set Basis Matrix
    idx = 0
    rotateGizScale = 0.5
    for anno in annotationGen.annotations:
        basisMatrix = Matrix.Translation(Vector((0, 0, 0)))
        basisMatrix.translation = Vector(anno.gizLoc)
        obj = bpy.context.selected_objects[objIndex]
        mat = obj.matrix_world
        objrot = mat.to_quaternion()
        lineweight = 2
        baseAlpha = 0.15

        #Translate Op Gizmos
        #X
        annotationRotateX = group.gizmos.new("GIZMO_GT_move_3d")
        annotationRotateX.use_draw_modal = True
        opX = annotationRotateX.target_set_operator(
            "measureit_arch.rotate_annotation")
        opX.constrainAxis = (True, False, False)
        opX.objIndex = objIndex
        opX.idx = idx

        XbasisMatrix = basisMatrix.to_3x3()
        rot = Quaternion(Vector((0, 1, 0)), radians(90))
        XbasisMatrix.rotate(rot)
        XbasisMatrix.rotate(objrot)
        XbasisMatrix.resize_4x4()
        XbasisMatrix.translation = Vector(anno.gizLoc)

        annotationRotateX.matrix_basis = XbasisMatrix
        annotationRotateX.scale_basis = rotateGizScale
        annotationRotateX.line_width = lineweight

        annotationRotateX.color = 0.96, 0.2, 0.31
        annotationRotateX.alpha = baseAlpha

        annotationRotateX.color_highlight = 0.96, 0.2, 0.31
        annotationRotateX.alpha_highlight = 1

        #Y
        annotationRotateY = group.gizmos.new("GIZMO_GT_move_3d")
        annotationRotateY.use_draw_modal = True
        opY = annotationRotateY.target_set_operator(
            "measureit_arch.rotate_annotation")
        opY.constrainAxis = (False, True, False)
        opY.objIndex = objIndex
        opY.idx = idx

        YbasisMatrix = basisMatrix.to_3x3()
        rot = Quaternion(Vector((1, 0, 0)), radians(-90))
        YbasisMatrix.rotate(rot)
        YbasisMatrix.rotate(objrot)
        YbasisMatrix.resize_4x4()
        YbasisMatrix.translation = Vector(anno.gizLoc)

        annotationRotateY.matrix_basis = YbasisMatrix
        annotationRotateY.scale_basis = rotateGizScale
        annotationRotateY.line_width = lineweight

        annotationRotateY.color = 0.54, 0.86, 0
        annotationRotateY.alpha = baseAlpha

        annotationRotateY.color_highlight = 0.54, 0.86, 0
        annotationRotateY.alpha_highlight = 1

        #Z
        annotationRotateZ = group.gizmos.new("GIZMO_GT_move_3d")
        annotationRotateZ.use_draw_modal = True
        opZ = annotationRotateZ.target_set_operator(
            "measureit_arch.rotate_annotation")
        opZ.constrainAxis = (False, False, True)
        opZ.objIndex = objIndex
        opZ.idx = idx

        ZbasisMatrix = basisMatrix.to_3x3()
        ZbasisMatrix.rotate(objrot)
        ZbasisMatrix.resize_4x4()
        ZbasisMatrix.translation = Vector(anno.gizLoc)

        annotationRotateZ.matrix_basis = ZbasisMatrix
        annotationRotateZ.scale_basis = rotateGizScale
        annotationRotateZ.line_width = lineweight

        annotationRotateZ.color = 0.15, 0.56, 1
        annotationRotateZ.alpha = baseAlpha

        annotationRotateZ.color_highlight = 0.15, 0.56, 1
        annotationRotateZ.alpha_highlight = 1

        #add to group

        group.X_widget = annotationRotateX
        group.Y_widget = annotationRotateY
        group.Z_widget = annotationRotateZ
        idx += 1