Exemplo n.º 1
0
    def get_ms3d_group_by_material_add_if(self, ms3d_model, ms3d_material):
        if ms3d_material.__index < 0 \
                or ms3d_material.__index >= len(ms3d_model.materials):
            return None

        markerName = "MaterialGroup.{}".format(ms3d_material.__index)
        markerComment = "MaterialGroup({})".format(ms3d_material.name)

        for ms3d_group in ms3d_model._groups:
            if ms3d_group.name == markerName \
                    and ms3d_group._comment_object \
                    and ms3d_group._comment_object.comment == markerComment:
                return ms3d_group

        ms3d_group = Ms3dGroup()
        ms3d_group.__index = len(ms3d_model._groups)
        ms3d_group.name = markerName
        ms3d_group._comment_object = Ms3dCommentEx()
        ms3d_group._comment_object.comment = markerComment
        ms3d_group._comment_object.index = len(ms3d_model._groups)
        ms3d_group.material_index = ms3d_material.__index

        ms3d_model._groups.append(ms3d_group)

        return ms3d_group
Exemplo n.º 2
0
    def get_ms3d_group_default_material_add_if(self, ms3d_model):
        markerName = "MaterialGroupDefault"
        markerComment = "group without material"

        for ms3d_group in ms3d_model._groups:
            if ms3d_group.material_index == \
                    Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX \
                    and ms3d_group.name == markerName \
                    and ms3d_group._comment_object \
                    and ms3d_group._comment_object.comment == markerComment:
                return ms3d_group

        ms3d_group = Ms3dGroup()
        ms3d_group.__index = len(ms3d_model._groups)
        ms3d_group.name = markerName
        ms3d_group._comment_object = Ms3dCommentEx()
        ms3d_group._comment_object.comment = markerComment
        ms3d_group._comment_object.index = len(ms3d_model._groups)
        ms3d_group.material_index = Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX

        ms3d_model._groups.append(ms3d_group)

        return ms3d_group
Exemplo n.º 3
0
    def create_geometry(self, blender_context, ms3d_model,
                        blender_mesh_objects, blender_to_ms3d_bones):
        blender_scene = blender_context.scene

        blender_to_ms3d_vertices = {}
        blender_to_ms3d_triangles = {}
        blender_to_ms3d_groups = {}
        blender_to_ms3d_materials = {}

        for blender_mesh_object in blender_mesh_objects:
            blender_mesh = blender_mesh_object.data

            ms3d_model._model_ex_object.joint_size = \
                    blender_mesh.ms3d.joint_size
            ms3d_model._model_ex_object.alpha_ref = blender_mesh.ms3d.alpha_ref
            ms3d_model._model_ex_object.transparency_mode = \
                    Ms3dUi.transparency_mode_to_ms3d(
                    blender_mesh.ms3d.transparency_mode)

            if blender_mesh.ms3d.comment:
                ms3d_model._comment_object = Ms3dComment(
                    blender_mesh.ms3d.comment)

            ##########################
            # prepare ms3d groups if available
            # works only for exporting active object
            ##EXPORT_ACTIVE_ONLY:
            for ms3d_local_group_index, blender_ms3d_group in enumerate(
                    blender_mesh.ms3d.groups):
                ms3d_group = Ms3dGroup()
                ms3d_group.__index = len(ms3d_model._groups)
                ms3d_group.name = blender_ms3d_group.name
                ms3d_group.flags = Ms3dUi.flags_to_ms3d(
                    blender_ms3d_group.flags)
                if blender_ms3d_group.comment:
                    ms3d_group._comment_object = Ms3dCommentEx()
                    ms3d_group._comment_object.comment = \
                            blender_ms3d_group.comment
                    ms3d_group._comment_object.index = len(ms3d_model._groups)
                ms3d_group.material_index = None  # to mark as not set
                ms3d_model._groups.append(ms3d_group)
                blender_to_ms3d_groups[blender_ms3d_group.id] = ms3d_group

            ##########################
            # i have to use BMesh, because there are several custom data stored.
            # BMesh doesn't support quads_convert_to_tris()
            # so, i use that very ugly way:
            # create a complete copy of mesh and bend object data
            # to be able to apply operations to it.

            # temporary, create a full heavy copy of the model
            # (object, mesh, modifiers)
            blender_mesh_temp = blender_mesh_object.data.copy()
            blender_mesh_object_temp = blender_mesh_object.copy()
            blender_mesh_object_temp.data = blender_mesh_temp
            blender_scene.objects.link(blender_mesh_object_temp)
            blender_scene.objects.active = blender_mesh_object_temp

            # apply transform
            if self.options_apply_transform:
                matrix_transform = blender_mesh_object_temp.matrix_basis
            else:
                matrix_transform = 1

            # apply modifiers
            for modifier in blender_mesh_object_temp.modifiers:
                if self.options_apply_modifiers:
                    # disable only armature modifiers and only,
                    # when use_animation is enabled
                    if  self.options_use_animation \
                            and modifier.type in {'ARMATURE', }:
                        modifier.show_viewport = False
                        modifier.show_render = False
                else:
                    # disable all modifiers,
                    # to be able to add and apply triangulate modifier later
                    modifier.show_viewport = False
                    modifier.show_render = False

            # convert to tris by using the triangulate modifier
            blender_mesh_object_temp.modifiers.new("temp", 'TRIANGULATE')
            blender_mesh_temp = blender_mesh_object_temp.to_mesh(
                blender_scene, True, self.options_apply_modifiers_mode)

            enable_edit_mode(True, blender_context)
            bm = bmesh.new()
            bm.from_mesh(blender_mesh_temp)

            layer_texture = bm.faces.layers.tex.get(
                ms3d_str['OBJECT_LAYER_TEXTURE'])
            if layer_texture is None:
                layer_texture = bm.faces.layers.tex.new(
                    ms3d_str['OBJECT_LAYER_TEXTURE'])

            layer_smoothing_group = bm.faces.layers.int.get(
                ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
            if layer_smoothing_group is None:
                layer_smoothing_group = bm.faces.layers.int.new(
                    ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])

            layer_group = bm.faces.layers.int.get(
                ms3d_str['OBJECT_LAYER_GROUP'])
            if layer_group is None:
                layer_group = bm.faces.layers.int.new(
                    ms3d_str['OBJECT_LAYER_GROUP'])

            layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV'])
            if layer_uv is None:
                if bm.loops.layers.uv:
                    layer_uv = bm.loops.layers.uv[0]
                else:
                    layer_uv = bm.loops.layers.uv.new(
                        ms3d_str['OBJECT_LAYER_UV'])

            layer_deform = bm.verts.layers.deform.active

            layer_extra = bm.verts.layers.int.get(
                ms3d_str['OBJECT_LAYER_EXTRA'])
            if layer_extra is None:
                layer_extra = bm.verts.layers.int.new(
                    ms3d_str['OBJECT_LAYER_EXTRA'])

            ##########################
            # handle vertices
            for bmv in bm.verts:
                item = blender_to_ms3d_vertices.get(bmv)
                if item is None:
                    index = len(ms3d_model._vertices)
                    ms3d_vertex = Ms3dVertex()
                    ms3d_vertex.__index = index

                    ms3d_vertex._vertex = self.geometry_correction(
                        matrix_transform * bmv.co)

                    if self.options_use_animation and layer_deform:
                        blender_vertex_group_ids = bmv[layer_deform]
                        if blender_vertex_group_ids:
                            bone_weights = {}
                            for blender_index, blender_weight \
                                    in blender_vertex_group_ids.items():
                                ms3d_joint = blender_to_ms3d_bones.get(
                                        blender_mesh_object_temp.vertex_groups[\
                                                blender_index].name)
                                if ms3d_joint:
                                    weight = bone_weights.get(
                                        ms3d_joint.__index)
                                    if not weight:
                                        weight = 0
                                    bone_weights[
                                        ms3d_joint.
                                        __index] = weight + blender_weight

                            # sort (bone_id: weight) according its weights
                            # to skip only less important weights in the next pass
                            bone_weights_sorted = sorted(
                                bone_weights.items(),
                                key=lambda item: item[1],
                                reverse=True)

                            count = 0
                            bone_ids = []
                            weights = []
                            for ms3d_index, blender_weight \
                                    in bone_weights_sorted:

                                if count == 0:
                                    ms3d_vertex.bone_id = ms3d_index
                                    weights.append(blender_weight)
                                elif count == 1:
                                    bone_ids.append(ms3d_index)
                                    weights.append(blender_weight)
                                elif count == 2:
                                    bone_ids.append(ms3d_index)
                                    weights.append(blender_weight)
                                elif count == 3:
                                    bone_ids.append(ms3d_index)
                                    if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
                                        self.report(
                                            {'WARNING', 'INFO'}, ms3d_str[
                                                'WARNING_EXPORT_SKIP_WEIGHT'])
                                else:
                                    # only first three weights will be supported / four bones
                                    if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
                                        self.report({
                                            'WARNING', 'INFO'
                                        }, ms3d_str[
                                            'WARNING_EXPORT_SKIP_WEIGHT_EX'])
                                    break
                                count += 1

                            # normalize weights to 100%
                            if self.options_normalize_weights:
                                weight_sum = 0.0
                                for weight in weights:
                                    weight_sum += weight

                                if weight_sum > 0.0:
                                    weight_normalize = 1.0 / weight_sum
                                else:
                                    weight_normalize = 1.0

                                weight_sum = 100
                                for index, weight in enumerate(weights):
                                    if index >= count - 1 or index >= 2:
                                        # take the full rest instead of calculate,
                                        # that should fill up to exactly 100%
                                        # (in some cases it is only 99% bacaus of roulding errors)
                                        weights[index] = int(weight_sum)
                                        break
                                    normalized_weight = int(
                                        weight * weight_normalize * 100)
                                    weights[index] = normalized_weight
                                    weight_sum -= normalized_weight

                            # fill up missing values
                            while len(bone_ids) < 3:
                                bone_ids.append(
                                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID)
                            while len(weights) < 3:
                                weights.append(0)

                            ms3d_vertex._vertex_ex_object._bone_ids = \
                                    tuple(bone_ids)
                            ms3d_vertex._vertex_ex_object._weights = \
                                    tuple(weights)

                    if layer_extra:
                        #ms3d_vertex._vertex_ex_object.extra = bmv[layer_extra]
                        # bm.verts.layers.int does only support signed int32
                        # convert signed int32 to unsigned int32 (little-endian)
                        signed_int32 = bmv[layer_extra]
                        bytes_int32 = signed_int32.to_bytes(4,
                                                            byteorder='little',
                                                            signed=True)
                        unsigned_int32 = int.from_bytes(bytes_int32,
                                                        byteorder='little',
                                                        signed=False)
                        ms3d_vertex._vertex_ex_object.extra = unsigned_int32

                    ms3d_model._vertices.append(ms3d_vertex)
                    blender_to_ms3d_vertices[bmv] = ms3d_vertex

            ##########################
            # handle faces / tris
            for bmf in bm.faces:
                item = blender_to_ms3d_triangles.get(bmf)
                if item is None:
                    index = len(ms3d_model._triangles)
                    ms3d_triangle = Ms3dTriangle()
                    ms3d_triangle.__index = index
                    bmv0 = bmf.verts[0]
                    bmv1 = bmf.verts[1]
                    bmv2 = bmf.verts[2]
                    ms3d_vertex0 = blender_to_ms3d_vertices[bmv0]
                    ms3d_vertex1 = blender_to_ms3d_vertices[bmv1]
                    ms3d_vertex2 = blender_to_ms3d_vertices[bmv2]
                    ms3d_vertex0.reference_count += 1
                    ms3d_vertex1.reference_count += 1
                    ms3d_vertex2.reference_count += 1
                    ms3d_triangle._vertex_indices = (
                        ms3d_vertex0.__index,
                        ms3d_vertex1.__index,
                        ms3d_vertex2.__index,
                    )
                    ms3d_triangle._vertex_normals = (
                        self.geometry_correction(bmv0.normal),
                        self.geometry_correction(bmv1.normal),
                        self.geometry_correction(bmv2.normal),
                    )
                    ms3d_triangle._s = (
                        bmf.loops[0][layer_uv].uv.x,
                        bmf.loops[1][layer_uv].uv.x,
                        bmf.loops[2][layer_uv].uv.x,
                    )
                    ms3d_triangle._t = (
                        1.0 - bmf.loops[0][layer_uv].uv.y,
                        1.0 - bmf.loops[1][layer_uv].uv.y,
                        1.0 - bmf.loops[2][layer_uv].uv.y,
                    )

                    ms3d_triangle.smoothing_group = bmf[layer_smoothing_group]
                    ms3d_model._triangles.append(ms3d_triangle)

                    ms3d_material = self.get_ms3d_material_add_if(
                        blender_mesh, ms3d_model, blender_to_ms3d_materials,
                        bmf.material_index)
                    ms3d_group = blender_to_ms3d_groups.get(bmf[layer_group])

                    ##EXPORT_ACTIVE_ONLY:
                    if ms3d_group is not None:
                        if ms3d_material is None:
                            ms3d_group.material_index = \
                                    Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX
                        else:
                            if ms3d_group.material_index is None:
                                ms3d_group.material_index = \
                                        ms3d_material.__index
                            else:
                                if ms3d_group.material_index != \
                                        ms3d_material.__index:
                                    ms3d_group = \
                                            self.get_ms3d_group_by_material_add_if(
                                            ms3d_model, ms3d_material)
                    else:
                        if ms3d_material is not None:
                            ms3d_group = self.get_ms3d_group_by_material_add_if(
                                ms3d_model, ms3d_material)
                        else:
                            ms3d_group = self.get_ms3d_group_default_material_add_if(
                                ms3d_model)

                    if ms3d_group is not None:
                        ms3d_group._triangle_indices.append(
                            ms3d_triangle.__index)
                        ms3d_triangle.group_index = ms3d_group.__index

                    blender_to_ms3d_triangles[bmf] = ms3d_triangle

            if bm is not None:
                bm.free()

            enable_edit_mode(False, blender_context)

            ##########################
            # remove the temporary data
            blender_scene.objects.unlink(blender_mesh_object_temp)
            if blender_mesh_temp is not None:
                blender_mesh_temp.user_clear()
                blender_context.blend_data.meshes.remove(blender_mesh_temp)
            blender_mesh_temp = None
            if blender_mesh_object_temp is not None:
                blender_mesh_temp = blender_mesh_object_temp.data.user_clear()
                blender_mesh_object_temp.user_clear()
                blender_context.blend_data.objects.remove(
                    blender_mesh_object_temp)
            if blender_mesh_temp is not None:
                blender_mesh_temp.user_clear()
                blender_context.blend_data.meshes.remove(blender_mesh_temp)