Exemple #1
0
    def __init__(self):
        global optionSubmaterials
        global matList
        global numMats

        self.material_list = []

        # Get all of the materials used by non-collision object meshes
        for object in bpy.context.selected_objects:
            if collisionObject(object) == True:
                continue
            elif object.type != 'MESH':
                continue
            else:
                print(object.name + ': Constructing Materials')
                for slot in object.material_slots:
                    # if the material is not in the material_list, add it
                    if self.material_list.count(slot.material) == 0:
                        self.material_list.append(slot.material)
                        mat_wrap = node_shader_utils.PrincipledBSDFWrapper(
                            slot.material) if slot.material else None
                        # image = mat_wrap.base_color_texture.image
                        matList.append(slot.material.name)

        self.material_count = len(self.material_list)
        numMats = self.material_count

        # Raise an error if there are no materials found
        if self.material_count == 0:
            raise Error('Mesh must have at least one applied material')
        else:
            if (optionSubmaterials):
                self.dump = cSubMaterials(self.material_list)
            else:
                self.dump = cMultiMaterials(self.material_list)
Exemple #2
0
    def test_shader_material_w3x_rgb_colors_roundtrip(self):
        mesh = get_mesh(shader_mats=True)
        mesh.shader_materials = [
            get_shader_material(w3x=True, rgb_colors=True)
        ]

        for source in mesh.shader_materials:
            (material,
             _) = create_material_from_shader_material(self, mesh.name(),
                                                       source)
            principled = node_shader_utils.PrincipledBSDFWrapper(
                material, is_readonly=True)
            actual = retrieve_shader_material(self,
                                              material,
                                              principled,
                                              w3x=True)

            for prop in source.properties:
                if prop.name in [
                        'ColorAmbient', 'ColorEmissive', 'ColorDiffuse',
                        'ColorSpecular'
                ]:
                    prop.type = 5
                    prop.value = Vector(
                        (prop.value[0], prop.value[1], prop.value[2], 1.0))

            compare_shader_materials(self, source, actual)
Exemple #3
0
def image_get(mat):
    from bpy_extras import node_shader_utils

    if mat.use_nodes:
        mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat)
        base_color_tex = mat_wrap.base_color_texture
        if base_color_tex and base_color_tex.image:
            return base_color_tex.image
def create_material_from_vertex_material(name, vert_mat):
    name = name + "." + vert_mat.vm_name
    if name in bpy.data.materials:
        material = bpy.data.materials[name]
        principled = node_shader_utils.PrincipledBSDFWrapper(material,
                                                             is_readonly=False)
        return material, principled

    material = bpy.data.materials.new(name)
    material.material_type = 'VERTEX_MATERIAL'
    material.use_nodes = True
    material.blend_method = 'BLEND'
    material.show_transparent_back = False

    attributes = {'DEFAULT'}
    attribs = vert_mat.vm_info.attributes
    if attribs & USE_DEPTH_CUE:
        attributes.add('USE_DEPTH_CUE')
    if attribs & ARGB_EMISSIVE_ONLY:
        attributes.add('ARGB_EMISSIVE_ONLY')
    if attribs & COPY_SPECULAR_TO_DIFFUSE:
        attributes.add('COPY_SPECULAR_TO_DIFFUSE')
    if attribs & DEPTH_CUE_TO_ALPHA:
        attributes.add('DEPTH_CUE_TO_ALPHA')

    principled = node_shader_utils.PrincipledBSDFWrapper(material,
                                                         is_readonly=False)
    principled.base_color = vert_mat.vm_info.diffuse.to_vector_rgb()
    principled.alpha = vert_mat.vm_info.opacity
    principled.specular = vert_mat.vm_info.shininess
    principled.emission_color = vert_mat.vm_info.emissive.to_vector_rgb()

    material.attributes = attributes
    material.specular = vert_mat.vm_info.specular.to_vector_rgb()
    material.ambient = vert_mat.vm_info.ambient.to_vector_rgba()
    material.translucency = vert_mat.vm_info.translucency

    material.stage0_mapping = '0x%08X' % (attribs & STAGE0_MAPPING_MASK)
    material.stage1_mapping = '0x%08X' % (attribs & STAGE1_MAPPING_MASK)

    material.vm_args_0 = vert_mat.vm_args_0.replace('\r\n', ', ')
    material.vm_args_1 = vert_mat.vm_args_1.replace('\r\n', ', ')

    return material, principled
Exemple #5
0
def get_plane_color(obj):
    """Get the object's emission and base color, or 0.5 gray if no color is found."""
    if obj.active_material is None:
        color = (0.5, ) * 3
    elif obj.active_material:
        from bpy_extras import node_shader_utils
        wrapper = node_shader_utils.PrincipledBSDFWrapper(obj.active_material)
        color = Color(wrapper.base_color[:3]) + wrapper.emission_color

    return str(list(color))
Exemple #6
0
    def test_vertex_material_no_attributes_roundtrip(self):
        mesh = get_mesh()

        for source in mesh.vert_materials:
            source.vm_info.attributes = 0
            (material,
             _) = create_material_from_vertex_material(mesh.name(), source)
            principled = node_shader_utils.PrincipledBSDFWrapper(
                material, is_readonly=True)
            actual = retrieve_vertex_material(material, principled)
            compare_vertex_materials(self, source, actual)
    def test_vertex_material_vm_args_with_spaces(self):
        mesh = get_mesh()

        for source in mesh.vert_materials:
            (material,
             _) = create_material_from_vertex_material(mesh.name(), source)
            material.vm_args_0 = ' UPerSec  =  -2.0 , VPerSec = 0.0 ,UScale = 1.0, VScale = 1.0 '
            material.vm_args_0 = ' UPerSec  =  -2.0 , VPerSec = 0.0 ,UScale = 1.0, VScale = 1.0 '

            principled = node_shader_utils.PrincipledBSDFWrapper(
                material, is_readonly=True)
            actual = retrieve_vertex_material(material, principled)
            compare_vertex_materials(self, source, actual)
Exemple #8
0
    def test_vertex_material_roundtrip(self):
        mesh = get_mesh()

        copyfile(
            up(up(self.relpath())) + '/testfiles/texture.dds',
            self.outpath() + 'texture.dds')

        for source in mesh.vert_materials:
            (material,
             _) = create_material_from_vertex_material(mesh.name(), source)
            principled = node_shader_utils.PrincipledBSDFWrapper(
                material, is_readonly=True)
            actual = retrieve_vertex_material(material, principled)
            compare_vertex_materials(self, source, actual)
Exemple #9
0
    def test_shader_material_w3x_two_tex_roundtrip(self):
        mesh = get_mesh(shader_mats=True)
        mesh.shader_materials = [get_shader_material(w3x=True, two_tex=True)]

        for source in mesh.shader_materials:
            (material,
             _) = create_material_from_shader_material(self, mesh.name(),
                                                       source)
            principled = node_shader_utils.PrincipledBSDFWrapper(
                material, is_readonly=True)
            actual = retrieve_shader_material(self,
                                              material,
                                              principled,
                                              w3x=True)
            compare_shader_materials(self, source, actual)
Exemple #10
0
def retrieve_principled_bsdf(material):
    result = PrincipledBSDF()

    principled = node_shader_utils.PrincipledBSDFWrapper(material,
                                                         is_readonly=True)
    result.base_color = principled.base_color
    result.alpha = principled.alpha
    diffuse_tex = principled.base_color_texture
    if diffuse_tex and diffuse_tex.image:
        result.diffuse_tex = diffuse_tex.image.name

    normalmap_tex = principled.normalmap_texture
    if normalmap_tex and normalmap_tex.image:
        result.normalmap_tex = normalmap_tex.image.name
        result.bump_scale = principled.normalmap_strength
    return result
Exemple #11
0
    def test_duplicate_shader_material_roundtrip(self):
        mesh = get_mesh(shader_mats=True)
        mesh.shader_materials = [get_shader_material(), get_shader_material()]

        materials = []
        for mat in mesh.shader_materials:
            (material,
             _) = create_material_from_shader_material(self, 'meshName', mat)
            materials.append(material)

        self.assertEqual(1, len(bpy.data.materials))
        self.assertTrue('meshName.NormalMapped.fx' in bpy.data.materials)

        for i, expected in enumerate(mesh.shader_materials):
            principled = node_shader_utils.PrincipledBSDFWrapper(
                materials[i], is_readonly=True)
            actual = retrieve_shader_material(self, materials[i], principled)
            compare_shader_materials(self, expected, actual)
Exemple #12
0
def create_dazzle(context, dazzle, coll):
    # Todo: proper dimensions for cone
    (dazzle_mesh, dazzle_cone) = create_cone(dazzle.name())
    dazzle_cone.data.object_type = 'DAZZLE'
    dazzle_cone.data.dazzle_type = dazzle.type_name
    link_object_to_active_scene(dazzle_cone, coll)

    material = bpy.data.materials.new(dazzle.name())
    material.use_nodes = True
    material.blend_method = 'BLEND'
    material.show_transparent_back = False

    principled = node_shader_utils.PrincipledBSDFWrapper(material,
                                                         is_readonly=False)
    principled.base_color = (255, 255, 255)
    principled.base_color_texture.image = find_texture(context,
                                                       'SunDazzle.tga')
    dazzle_mesh.materials.append(material)
Exemple #13
0
def load_b3d(filepath,
             context,
             IMPORT_CONSTRAIN_BOUNDS=10.0,
             IMAGE_SEARCH=True,
             APPLY_MATRIX=True,
             global_matrix=None):
    global ctx
    ctx = context
    data = B3DTree().parse(filepath)

    global images, materials
    images = {}
    materials = {}

    # load images
    dirname = os.path.dirname(filepath)
    for i, texture in enumerate(data['textures'] if 'textures' in data else []):
        texture_name = os.path.basename(texture['name'])
        for mat in data.materials:
            if mat.tids[0]==i:
                images[i] = load_image(texture_name, dirname, check_existing=True,
                    place_holder=False, recursive=IMAGE_SEARCH)

    # create materials
    for i, mat in enumerate(data.materials if 'materials' in data else []):
        name = mat.name
        material = bpy.data.materials.new(name)
        material_wrap = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=False)
        # material.diffuse_color = mat.rgba[:]
        material_wrap.base_color = mat.rgba[:-1]
        # texture = bpy.data.textures.new(name=name, type='IMAGE')
        tid = mat.tids[0]
        if tid in images:
            material_wrap.base_color_texture.image = images[tid]
            material_wrap.base_color_texture.texcoords = 'UV'
        materials[i] = material

    global armatures, bonesdata, weighting, bones_ids, bones_node
    walk(data)
    if data.frames:
        make_skeleton(data)
def create_principled_bsdf(self,
                           material,
                           base_color=None,
                           alpha=0,
                           diffuse_tex=None,
                           normal_tex=None,
                           bump_scale=0):
    principled = node_shader_utils.PrincipledBSDFWrapper(material,
                                                         is_readonly=False)
    if base_color is not None:
        principled.base_color = base_color
    if alpha > 0:
        principled.alpha = alpha
    if diffuse_tex is not None:
        tex = load_texture(self, diffuse_tex)
        if tex is not None:
            principled.base_color_texture.image = tex
            #principled.alpha_texture.image = tex
    if normal_tex is not None:
        tex = load_texture(self, normal_tex)
        if tex is not None:
            principled.normalmap_texture.image = tex
            principled.normalmap_strength = bump_scale
    return principled
def blender_to_skm(mesh, rig, WRITE_MDF):
    skm_data = SkmFile()

    contextMaterial = None
    context_mat_wrap = None
    contextMatrix_rot = None

    contextObName = "ToEE Model"
    rigObName = "ToEE Rig"
    armatureName = "ToEE Model Skeleton"

    TEXTURE_DICT = {}
    MATDICT = {}
    WRAPDICT = {}
    copy_set = set()  # set of files to copy (texture images...)

    def mesh_to_skm_mesh(
        skm_data
    ):  # myContextMesh_vertls, myContextMesh_facels, myContextMeshMaterials):
        '''
        Creates Mesh Object from vertex/face/material data
        '''
        bmesh = bpy.data.meshes['ToEE Model']

        vertex_count = len(bmesh.vertices)
        face_count = len(bmesh.polygons)

        print("%d vertices, %d faces" % (vertex_count, face_count))

        # Create vertices
        for vtx in bmesh.vertices:
            skm_vtx = SkmVertex()
            skm_vtx.pos = vtx.co.to_tuple() + (0.0, )
            skm_vtx.normal = vtx.normal.to_tuple() + (0.0, )
            skm_data.vertex_data.append(skm_vtx)
        assert len(skm_data.vertex_data) == vertex_count

        # Create faces (Triangles). Note: face should be triangles only!
        for p in bmesh.polygons:
            loop_start = p.loop_start
            loop_total = p.loop_total
            assert loop_total == 3, "Faces must be triangles!"
            face = bmesh.loops[loop_start + 0].vertex_index, bmesh.loops[
                loop_start + 1].vertex_index, bmesh.loops[loop_start +
                                                          2].vertex_index
            skm_face = SkmFace()
            skm_face.vertex_ids = face
            skm_data.face_data.append(skm_face)
        assert len(skm_data.face_data) == face_count

        # Get UV coordinates for each polygon's vertices
        print("Setting UVs")
        uvl = bmesh.uv_layers[0].data[:]
        for fidx, fa in enumerate(skm_data.face_data):
            fa.material_id = bmesh.polygons[fidx].material_index

        for fidx, pl in enumerate(bmesh.polygons):
            face = skm_data.face_data[fidx]
            v1, v2, v3 = face.vertex_ids

            skm_data.vertex_data[v1].uv = uvl[pl.loop_start + 0].uv
            skm_data.vertex_data[v2].uv = uvl[pl.loop_start + 1].uv
            skm_data.vertex_data[v3].uv = uvl[pl.loop_start + 2].uv

    def rig_to_skm_bones(skm_data):
        '''
        Converts rig/armature objects to SKM Bones
        '''
        # Bones
        print("Getting bones")
        obj = bpy.data.objects[contextObName]
        barm = bpy.data.armatures[armatureName]
        rig = bpy.data.objects[rigObName]

        bpy.context.view_layer.objects.active = rig
        rig.select_set(True)
        bpy.ops.object.mode_set(
            mode='EDIT')  # set to Edit Mode so bones can be accessed

        bone_ids = {}

        for bone_id, bone in enumerate(barm.edit_bones):
            bone_name = bone.name
            bone_ids[bone_name] = bone_id

            skm_bone = SkmBone(Name=bone_name)

            if bone.parent is None:
                skm_bone.parent_id = -1
            else:
                skm_bone.parent_id = bone_ids[bone.parent.name]

            world = bone.matrix
            wi = world.inverted_safe()
            skm_bone.world_inverse = matrix4_to_3x4_array(wi)

            skm_data.bone_data.append(skm_bone)

        # Exit edit mode
        if bpy.ops.object.mode_set.poll():
            bpy.ops.object.mode_set(mode='OBJECT')

        for vidx, vtx in enumerate(obj.data.vertices):
            for i, vg in enumerate(vtx.groups):
                bone_id = vg.group
                bone_wt = vg.weight
                skm_data.vertex_data[vidx].attachment_bones.append(bone_id)
                skm_data.vertex_data[vidx].attachment_weights.append(bone_wt)
            if skm_data.vertex_data[vidx].attachment_count > 6:
                raise Exception(
                    f"Too many bone attachments for vertex {vidx}! Max is 6")

        return

    def material_to_skm_mat(mat_wrap, mdf_file_path):
        skm_mat = SkmMaterial(mdf_file_path)
        return skm_mat

    ## Create materials
    progress.enter_substeps(3, "Processing data...")
    progress.step("Processing Materials and images...")
    for mm in bpy.data.materials:  #skm_data.material_data:

        material_name = mm.name
        if not material_name.lower().endswith('mdf'):
            print('Skipping material whose name doesn\'t end with .mdf: %r' %
                  material_name)
            continue

        assert mm.use_nodes, "export_ska assumes use_nodes = True!"
        contextMaterial = mm

        mat_wrap = node_shader_utils.PrincipledBSDFWrapper(contextMaterial,
                                                           is_readonly=False)
        assert mat_wrap.use_nodes == True, "huh? no use_nodes in wrapper?"
        context_mat_wrap = mat_wrap

        print("Converting material to SKM format: %s" % material_name)

        skm_mat = material_to_skm_mat(mat_wrap, material_name)
        if WRITE_MDF:
            mat_to_mdf_file(mat_wrap, skm_mat.id)

        MATDICT[material_name] = contextMaterial
        WRAPDICT[contextMaterial] = context_mat_wrap

        skm_data.material_data.append(skm_mat)

    # Convert Mesh object
    progress.step("Processing Mesh...")
    mesh_to_skm_mesh(skm_data)

    # Create Rig
    progress.step("Processing Rig...")
    rig_to_skm_bones(skm_data)

    # copy all collected files.
    io_utils.path_reference_copy(copy_set)

    progress.leave_substeps("Finished SKM conversion.")
    return skm_data
def retrieve_meshes(context,
                    hierarchy,
                    rig,
                    container_name,
                    force_vertex_materials=False):
    mesh_structs = []
    used_textures = []

    naming_error = False
    bone_names = [bone.name
                  for bone in rig.pose.bones] if rig is not None else []

    switch_to_pose(rig, 'REST')

    depsgraph = bpy.context.evaluated_depsgraph_get()

    for mesh_object in get_objects('MESH'):
        if mesh_object.data.object_type != 'MESH':
            continue

        if mesh_object.mode != 'OBJECT':
            bpy.ops.object.mode_set(mode='OBJECT')

        mesh_struct = Mesh()
        mesh_struct.header = MeshHeader(mesh_name=mesh_object.name,
                                        container_name=container_name)

        header = mesh_struct.header
        header.sort_level = mesh_object.data.sort_level
        mesh_struct.user_text = mesh_object.data.userText

        if mesh_object.hide_get():
            header.attrs |= GEOMETRY_TYPE_HIDDEN

        if mesh_object.data.casts_shadow:
            header.attrs |= GEOMETRY_TYPE_CAST_SHADOW

        if mesh_object.data.two_sided:
            header.attrs |= GEOMETRY_TYPE_TWO_SIDED

        mesh_object = mesh_object.evaluated_get(depsgraph)
        mesh = mesh_object.data
        b_mesh = prepare_bmesh(context, mesh)

        if len(mesh.vertices) == 0:
            context.warning(
                f'mesh \'{mesh.name}\' did not have a single vertex!')
            continue

        center, radius = calculate_mesh_sphere(mesh)
        header.sph_center = center
        header.sph_radius = radius

        if mesh.uv_layers:
            mesh.calc_tangents()

        header.vert_count = len(mesh.vertices)

        loop_dict = dict()
        for loop in mesh.loops:
            loop_dict[loop.vertex_index] = loop

        _, _, scale = mesh_object.matrix_local.decompose()

        is_skinned = False
        for vertex in mesh.vertices:
            if vertex.groups:
                is_skinned = True

        unskinned_vertices_error = False
        overskinned_vertices_error = False

        for i, vertex in enumerate(mesh.vertices):
            mesh_struct.shade_ids.append(i)
            matrix = Matrix.Identity(4)

            if vertex.groups:
                vert_inf = VertexInfluence()
                vert_inf.bone_idx = find_bone_index(hierarchy, mesh_object,
                                                    vertex.groups[0].group)
                vert_inf.bone_inf = vertex.groups[0].weight

                if len(vertex.groups) > 1:
                    mesh_struct.multi_bone_skinned = True
                    vert_inf.xtra_idx = find_bone_index(
                        hierarchy, mesh_object, vertex.groups[1].group)
                    vert_inf.xtra_inf = vertex.groups[1].weight

                if vert_inf.bone_inf < 0.01 and vert_inf.xtra_inf < 0.01:
                    context.warning(
                        f'mesh \'{mesh_object.name}\' vertex {i} both bone weights where 0!'
                    )
                    vert_inf.bone_inf = 1.0

                if abs(vert_inf.bone_inf + vert_inf.xtra_inf - 1.0) > 0.1:
                    context.warning(
                        f'mesh \'{mesh_object.name}\' vertex {i} both bone weights did not add up to 100%! ({vert_inf.bone_inf:.{2}f}, {vert_inf.xtra_inf:.{2}f})'
                    )
                    vert_inf.bone_inf = 1.0 - vert_inf.xtra_inf

                mesh_struct.vert_infs.append(vert_inf)

                if vert_inf.bone_idx > 0:
                    matrix = matrix @ rig.data.bones[hierarchy.pivots[
                        vert_inf.bone_idx].name].matrix_local.inverted()
                else:
                    matrix = matrix @ rig.matrix_local.inverted()

                if len(vertex.groups) > 2:
                    overskinned_vertices_error = True
                    context.error(
                        f'mesh \'{mesh_object.name}\' vertex {i} is influenced by more than 2 bones ({len(vertex.groups)})!'
                    )

            elif is_skinned:
                unskinned_vertices_error = True
                context.error(
                    f'skinned mesh \'{mesh_object.name}\' vertex {i} is not rigged to any bone!'
                )

            vertex.co.x *= scale.x
            vertex.co.y *= scale.y
            vertex.co.z *= scale.z
            mesh_struct.verts.append(matrix @ vertex.co)

            _, rotation, _ = matrix.decompose()

            if i in loop_dict:
                loop = loop_dict[i]
                # do NOT use loop.normal here! that might result in weird shading issues
                mesh_struct.normals.append(rotation @ vertex.normal)

                if mesh.uv_layers:
                    # in order to adapt to 3ds max orientation
                    mesh_struct.tangents.append(
                        (rotation @ loop.bitangent) * -1)
                    mesh_struct.bitangents.append((rotation @ loop.tangent))
            else:
                context.warning(
                    f'mesh \'{mesh_object.name}\' vertex {i} is not connected to any face!'
                )
                mesh_struct.normals.append(rotation @ vertex.normal)
                if mesh.uv_layers:
                    # only dummys
                    mesh_struct.tangents.append(
                        (rotation @ vertex.normal) * -1)
                    mesh_struct.bitangents.append((rotation @ vertex.normal))

        if unskinned_vertices_error or overskinned_vertices_error:
            return ([], [])

        header.min_corner = Vector(
            (mesh_object.bound_box[0][0], mesh_object.bound_box[0][1],
             mesh_object.bound_box[0][2]))
        header.max_corner = Vector(
            (mesh_object.bound_box[6][0], mesh_object.bound_box[6][1],
             mesh_object.bound_box[6][2]))

        for poly in mesh.polygons:
            triangle = Triangle(vert_ids=list(poly.vertices),
                                normal=Vector(poly.normal))

            vec1 = mesh.vertices[poly.vertices[0]].co
            vec2 = mesh.vertices[poly.vertices[1]].co
            vec3 = mesh.vertices[poly.vertices[2]].co
            tri_pos = (vec1 + vec2 + vec3) / 3.0
            triangle.distance = tri_pos.length
            mesh_struct.triangles.append(triangle)

        if context.file_format == 'W3X' and len(mesh_object.face_maps) > 0:
            context.warning(
                'triangle surface types (mesh face maps) are not supported in W3X file format!'
            )
        else:
            face_map_names = [map.name for map in mesh_object.face_maps]
            Triangle.validate_face_map_names(context, face_map_names)

            for map in mesh.face_maps:
                for i, val in enumerate(map.data):
                    mesh_struct.triangles[i].set_surface_type(
                        face_map_names[val.value])

        header.face_count = len(mesh_struct.triangles)

        center, radius = calculate_mesh_sphere(mesh)
        header.sphCenter = center
        header.sphRadius = radius

        tx_stages = []
        for i, uv_layer in enumerate(mesh.uv_layers):
            stage = TextureStage(tx_ids=[[i]],
                                 tx_coords=[[Vector(
                                     (0.0, 0.0))] * len(mesh_struct.verts)])

            for j, face in enumerate(b_mesh.faces):
                for loop in face.loops:
                    vert_index = mesh_struct.triangles[j].vert_ids[loop.index %
                                                                   3]
                    stage.tx_coords[0][vert_index] = uv_layer.data[
                        loop.index].uv.copy()
            tx_stages.append(stage)

        b_mesh.free()

        for i, material in enumerate(mesh.materials):
            mat_pass = MaterialPass()

            if material is None:
                context.warning(
                    f'mesh \'{mesh_object.name}\' uses a invalid/empty material!'
                )
                continue

            principled = node_shader_utils.PrincipledBSDFWrapper(
                material, is_readonly=True)

            used_textures = get_used_textures(material, principled,
                                              used_textures)

            if context.file_format == 'W3X' or (
                    material.material_type == 'SHADER_MATERIAL'
                    and not force_vertex_materials):
                mat_pass.shader_material_ids = [i]
                if i < len(tx_stages):
                    mat_pass.tx_coords = tx_stages[i].tx_coords[0]
                mesh_struct.shader_materials.append(
                    retrieve_shader_material(context, material, principled))

            else:
                shader = retrieve_shader(material)
                mesh_struct.shaders.append(shader)
                mat_pass.shader_ids = [i]
                mat_pass.vertex_material_ids = [i]

                mesh_struct.vert_materials.append(
                    retrieve_vertex_material(material, principled))

                base_col_tex = principled.base_color_texture
                if base_col_tex is not None and base_col_tex.image is not None:
                    info = TextureInfo()
                    img = base_col_tex.image
                    filepath = os.path.basename(img.filepath)
                    if filepath == '':
                        filepath = img.name
                    tex = Texture(id=img.name,
                                  file=filepath,
                                  texture_info=info)
                    mesh_struct.textures.append(tex)
                    shader.texturing = 1

                    if i < len(tx_stages):
                        mat_pass.tx_stages.append(tx_stages[i])

            mesh_struct.material_passes.append(mat_pass)

        for layer in mesh.vertex_colors:
            if '_' in layer.name:
                index = int(layer.name.split('_')[-1])
            else:
                index = 0
            if 'DCG' in layer.name:
                target = mesh_struct.material_passes[index].dcg
            elif 'DIG' in layer.name:
                target = mesh_struct.material_passes[index].dig
            elif 'SCG' in layer.name:
                target = mesh_struct.material_passes[index].scg
            else:
                context.warning(
                    f'vertex color layer name \'{layer.name}\' is not one of [DCG, DIG, SCG]'
                )
                continue

            target = [RGBA] * len(mesh.vertices)

            for i, loop in enumerate(mesh.loops):
                target[loop.vertex_index] = RGBA(layer.data[i].color)

        header.vert_channel_flags = VERTEX_CHANNEL_LOCATION | VERTEX_CHANNEL_NORMAL

        if mesh_struct.vert_infs:
            header.attrs |= GEOMETRY_TYPE_SKIN
            header.vert_channel_flags |= VERTEX_CHANNEL_BONE_ID

            if len(mesh_object.constraints) > 0:
                context.warning(
                    f'mesh \'{mesh_object.name }\' is rigged and thus does not support any constraints!'
                )

        else:
            if len(mesh_object.constraints) > 1:
                context.warning(
                    f'mesh \'{mesh_object.name}\' has multiple constraints applied, only \'Copy Rotation\' OR \'Damped Track\' are supported!'
                )
            for constraint in mesh_object.constraints:
                if constraint.name == 'Copy Rotation':
                    header.attrs |= GEOMETRY_TYPE_CAMERA_ORIENTED
                    break
                if constraint.name == 'Damped Track':
                    header.attrs |= GEOMETRY_TYPE_CAMERA_ALIGNED
                    break
                context.warning(
                    f'mesh \'{mesh_object.name}\' constraint \'{constraint.name}\' is not supported!'
                )

        if mesh_object.name in bone_names:
            if not (mesh_struct.is_skin() or mesh_object.parent_type == 'BONE'
                    and mesh_object.parent_bone == mesh_object.name):
                naming_error = True
                context.error(
                    f'mesh \'{mesh_object.name}\' has same name as bone \'{mesh_object.name}\' but is not configured properly!'
                )
                context.info(
                    'EITHER apply an armature modifier to it, create a vertex group with the same name as the mesh and do the weight painting OR set the armature as parent object and the identically named bone as parent bone.'
                )
                continue

        if mesh_struct.shader_materials:
            header.vert_channel_flags |= VERTEX_CHANNEL_TANGENT | VERTEX_CHANNEL_BITANGENT
        else:
            mesh_struct.tangents = []
            mesh_struct.bitangents = []

        mesh_struct.mat_info = MaterialInfo(
            pass_count=len(mesh_struct.material_passes),
            vert_matl_count=len(mesh_struct.vert_materials),
            shader_count=len(mesh_struct.shaders),
            texture_count=len(mesh_struct.textures))

        mesh_struct.header.matl_count = max(len(mesh_struct.vert_materials),
                                            len(mesh_struct.shader_materials))
        mesh_structs.append(mesh_struct)

    switch_to_pose(rig, 'POSE')

    if naming_error:
        return [], []

    return mesh_structs, used_textures
Exemple #17
0
    def generate_pass(self, mat, pass_name=""):
        usermat = texnodes = None
        if mat.use_ogre_parent_material:
            usermat = get_ogre_user_material(mat.ogre_parent_material)
            texnodes = shader.get_texture_subnodes(self.material, mat)

        if usermat:
            self.w.iword('pass %s : %s/PASS0' % (pass_name, usermat.name))
        else:
            self.w.iword('pass')
            if pass_name: self.w.word(pass_name)

        with self.w.embed():
            # Texture wrappers
            textures = {}
            mat_wrapper = node_shader_utils.PrincipledBSDFWrapper(mat)
            for tex_key in self.TEXTURE_KEYS:
                texture = getattr(mat_wrapper, tex_key, None)
                if texture and texture.image:
                    textures[tex_key] = texture
                    # adds image to the list for later copy
                    self.images.add(texture.image)

            color = mat_wrapper.base_color
            alpha = 1.0
            if mat.blend_method != "OPAQUE":
                alpha = mat_wrapper.alpha
                self.w.iword('scene_blend alpha_blend').nl()
                if mat.show_transparent_back:
                    self.w.iword('cull_hardware none').nl()
                    self.w.iword('depth_write off').nl()

            # arbitrary bad translation from PBR to Blinn Phong
            # derive proportions from metallic
            bf = 1.0 - mat_wrapper.metallic
            mf = max(0.04, mat_wrapper.metallic)
            # derive specular color
            sc = mathutils.Color(
                color[:3]) * mf + (1.0 - mf) * mathutils.Color(
                    (1, 1, 1)) * (1.0 - mat_wrapper.roughness)
            si = (1.0 - mat_wrapper.roughness) * 128

            self.w.iword('diffuse').round(color[0] * bf).round(
                color[1] * bf).round(color[2] * bf).round(alpha).nl()
            self.w.iword('specular').round(sc[0]).round(sc[1]).round(
                sc[2]).round(alpha).round(si, 3).nl()

            for name in dir(
                    mat):  #mat.items() - items returns custom props not pyRNA:
                if name.startswith('ogre_') and name != 'ogre_parent_material':
                    var = getattr(mat, name)
                    op = name.replace('ogre_', '')
                    val = var
                    if type(var) == bool:
                        if var: val = 'on'
                        else: val = 'off'
                    self.w.iword(op).word(val).nl()
            self.w.nl()

            if texnodes and usermat.texture_units:
                for i, name in enumerate(usermat.texture_units_order):
                    if i < len(texnodes):
                        node = texnodes[i]
                        if node.texture:
                            geo = shader.get_connected_input_nodes(
                                self.material, node)[0]
                            # self.generate_texture_unit( node.texture, name=name, uv_layer=geo.uv_layer )
                            raise NotImplementedError(
                                "TODO: slots dont exist anymore - use image")
            elif textures:
                for key, texture in textures.items():
                    self.generate_texture_unit(key, texture)
def create_material_from_shader_material(context, name, shader_mat):
    name = name + '.' + shader_mat.header.type_name
    if name in bpy.data.materials:
        material = bpy.data.materials[name]
        principled = node_shader_utils.PrincipledBSDFWrapper(material,
                                                             is_readonly=False)
        return material, principled

    material = bpy.data.materials.new(name)
    material.material_type = 'SHADER_MATERIAL'
    material.use_nodes = True
    material.blend_method = 'BLEND'
    material.show_transparent_back = False

    material.technique = shader_mat.header.technique

    principled = node_shader_utils.PrincipledBSDFWrapper(material,
                                                         is_readonly=False)

    for prop in shader_mat.properties:
        if prop.name == 'DiffuseTexture' and prop.value != '':
            principled.base_color_texture.image = find_texture(
                context, prop.value)
        elif prop.name == 'NormalMap' and prop.value != '':
            principled.normalmap_texture.image = find_texture(
                context, prop.value)
        elif prop.name == 'BumpScale':
            principled.normalmap_strength = prop.value
        elif prop.name == 'SpecMap' and prop.value != '':
            principled.specular_texture.image = find_texture(
                context, prop.value)
        elif prop.name == 'SpecularExponent' or prop.name == 'Shininess':
            material.specular_intensity = prop.value / 200.0
        elif prop.name == 'DiffuseColor' or prop.name == 'ColorDiffuse':
            material.diffuse_color = prop.to_rgba()
        elif prop.name == 'SpecularColor' or prop.name == 'ColorSpecular':
            material.specular = prop.to_rgb()
        elif prop.name == 'CullingEnable':
            material.use_backface_culling = prop.value
        elif prop.name == 'Texture_0':
            principled.base_color_texture.image = find_texture(
                context, prop.value)

        # all props below have no effect on shading -> custom properties for roundtrip purpose
        elif prop.name == 'AmbientColor' or prop.name == 'ColorAmbient':
            material.ambient = prop.to_rgba()
        elif prop.name == 'EmissiveColor' or prop.name == 'ColorEmissive':
            principled.emission_color = prop.to_rgb()
        elif prop.name == 'Opacity':
            principled.alpha = prop.value
        elif prop.name == 'AlphaTestEnable':
            material.alpha_test = prop.value
        elif prop.name == 'BlendMode':  # is blend_method ?
            material.blend_mode = prop.value
        elif prop.name == 'BumpUVScale':
            material.bump_uv_scale = prop.value.xy
        elif prop.name == 'EdgeFadeOut':
            material.edge_fade_out = prop.value
        elif prop.name == 'DepthWriteEnable':
            material.depth_write = prop.value
        elif prop.name == 'Sampler_ClampU_ClampV_NoMip_0':
            material.sampler_clamp_uv_no_mip_0 = prop.value
        elif prop.name == 'Sampler_ClampU_ClampV_NoMip_1':
            material.sampler_clamp_uv_no_mip_1 = prop.value
        elif prop.name == 'NumTextures':
            material.num_textures = prop.value  # is 1 if texture_0 and texture_1 are set
        elif prop.name == 'Texture_1':  # second diffuse texture
            material.texture_1 = prop.value
        elif prop.name == 'SecondaryTextureBlendMode':
            material.secondary_texture_blend_mode = prop.value
        elif prop.name == 'TexCoordMapper_0':
            material.tex_coord_mapper_0 = prop.value
        elif prop.name == 'TexCoordMapper_1':
            material.tex_coord_mapper_1 = prop.value
        elif prop.name == 'TexCoordTransform_0':
            material.tex_coord_transform_0 = prop.value
        elif prop.name == 'TexCoordTransform_1':
            material.tex_coord_transform_1 = prop.value
        elif prop.name == 'EnvironmentTexture':
            material.environment_texture = prop.value
        elif prop.name == 'EnvMult':
            material.environment_mult = prop.value
        elif prop.name == 'RecolorTexture':
            material.recolor_texture = prop.value
        elif prop.name == 'RecolorMultiplier':
            material.recolor_mult = prop.value
        elif prop.name == 'UseRecolorColors':
            material.use_recolor = prop.value
        elif prop.name == 'HouseColorPulse':
            material.house_color_pulse = prop.value
        elif prop.name == 'ScrollingMaskTexture':
            material.scrolling_mask_texture = prop.value
        elif prop.name == 'TexCoordTransformAngle_0':
            material.tex_coord_transform_angle = prop.value
        elif prop.name == 'TexCoordTransformU_0':
            material.tex_coord_transform_u_0 = prop.value
        elif prop.name == 'TexCoordTransformV_0':
            material.tex_coord_transform_v_0 = prop.value
        elif prop.name == 'TexCoordTransformU_1':
            material.tex_coord_transform_u_1 = prop.value
        elif prop.name == 'TexCoordTransformV_1':
            material.tex_coord_transform_v_1 = prop.value
        elif prop.name == 'TexCoordTransformU_2':
            material.tex_coord_transform_u_2 = prop.value
        elif prop.name == 'TexCoordTransformV_2':
            material.tex_coord_transform_v_2 = prop.value
        elif prop.name == 'TextureAnimation_FPS_NumPerRow_LastFrame_FrameOffset_0':
            material.tex_ani_fps_NPR_lastFrame_frameOffset_0 = prop.value
        elif prop.name == 'IonHullTexture':
            material.ion_hull_texture = prop.value
        elif prop.name == 'MultiTextureEnable':
            material.multi_texture_enable = prop.value
        else:
            context.error('shader property not implemented: ' + prop.name)

    return material, principled
Exemple #19
0
def import_skn(context, file, directory):
    skn_type = read_string(file, 256)

    # todo: check version
    if 'Eternity Engine Skin File' not in skn_type:
        context.window_manager.popup_menu(invalid_skn_type,
                                          title='Warning',
                                          icon='ERROR')
        return None

    skn_data = {'materials': [], 'diffuse_textures': []}

    # todo: check with msh name
    msh_name = read_string(file, 256)

    # todo: what is it (maybe version)
    file.seek(4, os.SEEK_CUR)

    materials_num = read_int(file)

    # todo
    file.seek(4, os.SEEK_CUR)
    file.seek(4, os.SEEK_CUR)

    file.seek(0x400)

    for _ in range(materials_num):
        mat_name = read_string(file, 256)

        mat = bpy.data.materials.get(mat_name)
        mat_wrap = None
        if not mat:
            mat = bpy.data.materials.new(name=mat_name)
            mat_wrap = node_shader_utils.PrincipledBSDFWrapper(
                mat, is_readonly=False)

        # todo: other material types
        mat_type = read_string(file, 256)

        file.seek(0x200, os.SEEK_CUR)

        prop_num = read_int(file)
        for _ in range(prop_num):
            prop_section_name = read_string(file, read_int(file))
            prop = read_int(file)

            # todo
            if prop == 1:
                read_float(file)

            # todo
            elif prop == 2:
                read_float(file, 4)

            # todo: test
            elif prop == 3:
                prop_name = read_string(file, read_int(file))

                # new material
                if mat_wrap:
                    tex = bpy.data.textures.get(prop_name)
                    if not tex:
                        tex = bpy.data.textures.new(prop_name, type='IMAGE')
                        image = load_image(prop_name, directory)
                    else:
                        image = bpy.data.images.get(prop_name)

                    if 'Diffuse' in prop_section_name:
                        if image:
                            tex.image = image

                            nodetex = mat_wrap.base_color_texture
                            nodetex.image = image
                            nodetex.texcoords = 'UV'

                            if image.depth in {32, 128}:
                                mat.blend_method = 'HASHED'
                                add_transparent_node(mat.node_tree)

                        skn_data['diffuse_textures'].append(tex)

        skn_data['materials'].append(mat)

    return skn_data
def export_bm(context, bmx_filepath, prefs_fncg, opts_exportMode, opts_exportTarget):
    # ============================================ alloc a temp folder
    utils_tempFolderObj = tempfile.TemporaryDirectory()
    utils_tempFolder = utils_tempFolderObj.name
    utils_tempTextureFolder = os.path.join(utils_tempFolder, "Texture")
    os.makedirs(utils_tempTextureFolder)
    
    # ============================================ 
    # find export target. 
    # do not need check them validation in there. 
    # just collect them.
    if opts_exportMode== "COLLECTION":
        objectList = opts_exportTarget.objects
    else:
        objectList = [opts_exportTarget, ]

    # try get fncg collection
    # fncg stands with forced non-component group
    try:
        object_fncgCollection = bpy.data.collections[prefs_fncg]
    except:
        object_fncgCollection = None
   
    # ============================================ export
    with open(os.path.join(utils_tempFolder, "index.bm"), "wb") as finfo:
        UTILS_file_io.write_uint32(finfo, UTILS_constants.bmfile_currentVersion)
        
        # ====================== export object
        meshSet = set()
        meshList = []
        meshCount = 0        
        with open(os.path.join(utils_tempFolder, "object.bm"), "wb") as fobject:
            for obj in objectList:
                # only export mesh object
                if obj.type != 'MESH':
                    continue

                # clean no mesh object
                object_blenderMesh = obj.data
                if object_blenderMesh is None:
                    continue

                # check component
                if (object_fncgCollection is not None) and (obj.name in object_fncgCollection.objects):
                    # it should be set as normal object forcely
                    object_isComponent = False
                else:
                    # check isComponent normally
                    object_isComponent = UTILS_functions.is_component(obj.name)

                # triangle first and then group
                if not object_isComponent:
                    if object_blenderMesh not in meshSet:
                        _mesh_triangulate(object_blenderMesh)
                        meshSet.add(object_blenderMesh)
                        meshList.append(object_blenderMesh)
                        object_meshIndex = meshCount
                        meshCount += 1
                    else:
                        object_meshIndex = meshList.index(object_blenderMesh)
                else:
                    object_meshIndex = UTILS_functions.get_component_id(obj.name)

                # get visibility
                object_isHidden = not obj.visible_get()

                # try get grouping data
                object_groupList = UTILS_virtools_prop.get_virtools_group_data(obj)

                # =======================
                # write to files
                # write finfo first
                UTILS_file_io.write_string(finfo, obj.name)
                UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.OBJECT)
                UTILS_file_io.write_uint64(finfo, fobject.tell())

                # write fobject
                UTILS_file_io.write_bool(fobject, object_isComponent)
                UTILS_file_io.write_bool(fobject, object_isHidden)
                UTILS_file_io.write_world_matrix(fobject, obj.matrix_world)
                UTILS_file_io.write_uint32(fobject, len(object_groupList))
                for item in object_groupList:
                    UTILS_file_io.write_string(fobject, item)
                UTILS_file_io.write_uint32(fobject, object_meshIndex)

        # ====================== export mesh
        materialSet = set()
        materialList = []
        with open(os.path.join(utils_tempFolder, "mesh.bm"), "wb") as fmesh:
            for mesh in meshList:
                # split normals
                mesh.calc_normals_split()

                # write finfo first
                UTILS_file_io.write_string(finfo, mesh.name)
                UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.MESH)
                UTILS_file_io.write_uint64(finfo, fmesh.tell())

                # write fmesh
                # vertices
                mesh_vecList = mesh.vertices[:]
                UTILS_file_io.write_uint32(fmesh, len(mesh_vecList))
                for vec in mesh_vecList:
                    #swap yz
                    UTILS_file_io.write_3vector(fmesh,vec.co[0],vec.co[2],vec.co[1])

                # uv
                mesh_faceIndexPairs = [(face, index) for index, face in enumerate(mesh.polygons)]
                UTILS_file_io.write_uint32(fmesh, len(mesh_faceIndexPairs) * 3)
                if mesh.uv_layers.active is not None:
                    uv_layer = mesh.uv_layers.active.data[:]
                    for f, f_index in mesh_faceIndexPairs:
                        # it should be triangle face, otherwise throw a error
                        if (f.loop_total != 3):
                            raise Exception("Not a triangle", f.poly.loop_total)

                        for loop_index in range(f.loop_start, f.loop_start + f.loop_total):
                            uv = uv_layer[loop_index].uv
                            # reverse v
                            UTILS_file_io.write_2vector(fmesh, uv[0], -uv[1])
                else:
                    # no uv data. write garbage
                    for i in range(len(mesh_faceIndexPairs) * 3):
                        UTILS_file_io.write_2vector(fmesh, 0.0, 0.0)

                # normals
                UTILS_file_io.write_uint32(fmesh, len(mesh_faceIndexPairs) * 3)
                for f, f_index in mesh_faceIndexPairs:
                    # no need to check triangle again
                    for loop_index in range(f.loop_start, f.loop_start + f.loop_total):
                        nml = mesh.loops[loop_index].normal
                        # swap yz
                        UTILS_file_io.write_3vector(fmesh, nml[0], nml[2], nml[1])

                # face
                # get material first
                mesh_usedBlenderMtl = mesh.materials[:]
                mesh_noMaterial = len(mesh_usedBlenderMtl) == 0
                for mat in mesh_usedBlenderMtl:
                    if mat not in materialSet:
                        materialSet.add(mat)
                        materialList.append(mat)

                UTILS_file_io.write_uint32(fmesh, len(mesh_faceIndexPairs))
                mesh_vtIndex = []
                mesh_vnIndex = []
                mesh_vIndex = []
                for f, f_index in mesh_faceIndexPairs:
                    # confirm material use
                    if mesh_noMaterial:
                        mesh_materialIndex = 0
                    else:
                        mesh_materialIndex = materialList.index(mesh_usedBlenderMtl[f.material_index])

                    # export face
                    mesh_vtIndex.clear()
                    mesh_vnIndex.clear()
                    mesh_vIndex.clear()

                    counter = 0
                    for loop_index in range(f.loop_start, f.loop_start + f.loop_total):
                        mesh_vIndex.append(mesh.loops[loop_index].vertex_index)
                        mesh_vnIndex.append(f_index * 3 + counter)
                        mesh_vtIndex.append(f_index * 3 + counter)
                        counter += 1
                    # reverse vertices sort
                    UTILS_file_io.write_face(fmesh,
                    mesh_vIndex[2], mesh_vtIndex[2], mesh_vnIndex[2],
                    mesh_vIndex[1], mesh_vtIndex[1], mesh_vnIndex[1],
                    mesh_vIndex[0], mesh_vtIndex[0], mesh_vnIndex[0])

                    # set used material
                    UTILS_file_io.write_bool(fmesh, not mesh_noMaterial)
                    UTILS_file_io.write_uint32(fmesh, mesh_materialIndex)

                # free splited normals
                mesh.free_normals_split()

        # ====================== export material
        textureSet = set()
        textureList = []
        textureCount = 0        
        with open(os.path.join(utils_tempFolder, "material.bm"), "wb") as fmaterial:
            for material in materialList:
                # write finfo first
                UTILS_file_io.write_string(finfo, material.name)
                UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.MATERIAL)
                UTILS_file_io.write_uint64(finfo, fmaterial.tell())

                # try get original written data
                (material_colAmbient, material_colDiffuse, material_colSpecular, material_colEmissive, material_specularPower,
                material_alphaTest, material_alphaBlend, material_zBuffer, material_twoSided,
                material_texture) = UTILS_virtools_prop.get_virtools_material_data(material)

                # only try get from Principled BSDF when we couldn't get from virtools_material props
                if material_texture is None:
                    # get node
                    mat_wrap = node_shader_utils.PrincipledBSDFWrapper(material)
                    # check existence of Principled BSDF
                    if mat_wrap:
                        # we trying get texture data from Principled BSDF
                        # because bpy.types.Material.virtools_material now can provide
                        # Virtools material data stablely, so i annotate following code
                        # only keep texture data
                        '''
                        use_mirror = mat_wrap.metallic != 0.0
                        if use_mirror:
                            material_colAmbient = _set_value_when_none(material_colAmbient, (mat_wrap.metallic, mat_wrap.metallic, mat_wrap.metallic))
                        else:
                            material_colAmbient = _set_value_when_none(material_colAmbient, (1.0, 1.0, 1.0))
                        material_colDiffuse = _set_value_when_none(material_colDiffuse, (mat_wrap.base_color[0], mat_wrap.base_color[1], mat_wrap.base_color[2]))
                        material_colSpecular = _set_value_when_none(material_colSpecular, (mat_wrap.specular, mat_wrap.specular, mat_wrap.specular))
                        material_colEmissive = _set_value_when_none(material_colEmissive, mat_wrap.emission_color[:3])
                        material_specularPower = _set_value_when_none(material_specularPower, 0.0)
                        '''

                        # confirm texture
                        tex_wrap = getattr(mat_wrap, "base_color_texture", None)
                        if tex_wrap:
                            image = tex_wrap.image
                            if image:
                                material_texture = image
                                

                # check texture index
                if material_texture is None:
                    material_useTexture = False
                    material_textureIndex = 0
                else:
                    # add into texture list
                    if material_texture not in textureSet:
                        textureSet.add(material_texture)
                        textureList.append(material_texture)
                        textureIndex = textureCount
                        textureCount += 1
                    else:
                        textureIndex = textureList.index(material_texture)

                    material_useTexture = True
                    material_textureIndex = textureIndex

                UTILS_file_io.write_color(fmaterial, material_colAmbient)
                UTILS_file_io.write_color(fmaterial, material_colDiffuse)
                UTILS_file_io.write_color(fmaterial, material_colSpecular)
                UTILS_file_io.write_color(fmaterial, material_colEmissive)
                UTILS_file_io.write_float(fmaterial, material_specularPower)
                UTILS_file_io.write_bool(fmaterial, material_alphaTest)
                UTILS_file_io.write_bool(fmaterial, material_alphaBlend)
                UTILS_file_io.write_bool(fmaterial, material_zBuffer)
                UTILS_file_io.write_bool(fmaterial, material_twoSided)
                UTILS_file_io.write_bool(fmaterial, material_useTexture)
                UTILS_file_io.write_uint32(fmaterial, material_textureIndex)
            

        # ====================== export texture
        texture_blenderFilePath = os.path.dirname(bpy.data.filepath)
        texture_existedTextureFilepath = set()        
        with open(os.path.join(utils_tempFolder, "texture.bm"), "wb") as ftexture:
            for texture in textureList:
                # write finfo first
                UTILS_file_io.write_string(finfo, texture.name)
                UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.TEXTURE)
                UTILS_file_io.write_uint64(finfo, ftexture.tell())

                # confirm whether it is internal texture
                # get absolute texture path
                texture_filepath = io_utils.path_reference(texture.filepath, texture_blenderFilePath, utils_tempTextureFolder,
                                                            'ABSOLUTE', "", None, texture.library)
                # get file name and write it
                texture_filename = os.path.basename(texture_filepath)
                UTILS_file_io.write_string(ftexture, texture_filename)

                if (_is_external_texture(texture_filename)):
                    # write directly, use Ballance texture
                    UTILS_file_io.write_bool(ftexture, True)
                else:
                    # copy internal texture, if this file is copied, do not copy it again
                    UTILS_file_io.write_bool(ftexture, False)
                    if texture_filename not in texture_existedTextureFilepath:
                        shutil.copy(texture_filepath, os.path.join(utils_tempTextureFolder, texture_filename))
                        texture_existedTextureFilepath.add(texture_filename)


    # ============================================ 
    # save zip and clean up folder
    UTILS_zip_helper.compress(utils_tempFolder, bmx_filepath)
    utils_tempFolderObj.cleanup()
Exemple #21
0
def importMaterials(MATName, image_transparency, texture_ext):
    with open(MATName, 'rb') as mt:
        mt.seek(0x10, 0)
        MATCheck = struct.unpack('<L', mt.read(4))[0]
        if (MATCheck == 0x4D41544C):
            MATVerA = struct.unpack('<H', mt.read(2))[0]
            MATVerB = struct.unpack('<H', mt.read(2))[0]
            MATHeadOff = mt.tell() + struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
            MATCount = struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
            mt.seek(MATHeadOff, 0)
            for m in range(MATCount):
                pe = MaterialData()
                MATNameOff = mt.tell() + struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
                MATParamGrpOff = mt.tell() + struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
                MATParamGrpCount = struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
                MATShdrNameOff = mt.tell() + struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
                MATRet = mt.tell()
                mt.seek(MATNameOff, 0)
                pe.materialName = readVarLenString(mt)
                print("Textures for " + pe.materialName + ":")
                mt.seek(MATParamGrpOff, 0)
                for p in range(MATParamGrpCount):
                    MatParamID = struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
                    MatParamOff = mt.tell() + struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
                    MatParamType = struct.unpack('<L', mt.read(4))[0]; mt.seek(0x04, 1)
                    MatParamRet = mt.tell()
                    if (MatParamType == 0x0B):
                        mt.seek(MatParamOff + 0x08, 0)
                        TexName = str.lower(readVarLenString(mt))
                        print("(" + hex(MatParamID) + ") for " + TexName)
                        if (MatParamID == 0x5C):
                            pe.color1Name = TexName
                        elif (MatParamID == 0x5D):
                            pe.color2Name = TexName
                        elif (MatParamID == 0x5F):
                            pe.bakeName = TexName
                        elif (MatParamID == 0x60):
                            pe.normalName = TexName
                        elif (MatParamID == 0x61):
                            pe.emissive1Name = TexName
                            if (pe.color1Name == ""):
                                pe.color1Name = TexName
                        elif (MatParamID == 0x62):
                            pe.prmName = TexName
                        elif (MatParamID == 0x63):
                            pe.envName = TexName
                        elif (MatParamID == 0x65):
                            pe.bakeName = TexName
                        elif (MatParamID == 0x66):
                            pe.color1Name = TexName
                        elif (MatParamID == 0x67):
                            pe.color2Name = TexName
                        elif (MatParamID == 0x6A):
                            pe.emissive2Name = TexName
                            if (pe.color2Name == ""):
                                pe.color2Name = TexName
                        elif (MatParamID == 0x133):
                            print("noise_for_warp")
                        else:
                            print("Unknown type (" + hex(MatParamID) + ") for " + TexName)

                        mt.seek(MatParamRet, 0)

                print("-----")
                Materials_array.append(pe)
                mt.seek(MATRet, 0)

            for m in range(MATCount):
                # Check and reuse existing same-name material, or create it if it doesn't already exist
                if (bpy.data.materials.find(Materials_array[m].materialName) > 0):
                    mat = bpy.data.materials[Materials_array[m].materialName]
                else:
                    mat = bpy.data.materials.new(Materials_array[m].materialName)
                mat.use_fake_user = True
                # Check and reuse existing same-name primary texture slot, or create it if it doesn't already exist
                if (Materials_array[m].color1Name != ""):
                    img = image_utils.load_image(Materials_array[m].color1Name + texture_ext, dirPath, place_holder=True, check_existing=True, force_reload=True)
                    img.alpha_mode = image_transparency
                    ma_wrap = node_shader_utils.PrincipledBSDFWrapper(mat, is_readonly=False)

                    ma_wrap.base_color_texture.image = img
                    ma_wrap.base_color_texture.texcoords = 'UV'

                # Check and reuse existing same-name primary texture slot, or create it if it doesn't already exist
                # if (Materials_array[m].color2Name != ""):
                #     if (bpy.data.textures.find(Materials_array[m].color2Name) > 0):
                #         altTex = bpy.data.textures[Materials_array[m].color2Name]
                #     else:
                #         altTex = bpy.data.textures.new(Materials_array[m].color2Name, type='IMAGE')

                #     altImg = image_utils.load_image(Materials_array[m].color2Name + texture_ext, dirPath, place_holder=True, check_existing=True, force_reload=True)
                #     altImg.alpha_mode = image_transparency
                #     altTex.image = altImg

                #     if (altTex.name not in mat.texture_slots):
                #         altSlot = mat.texture_slots.add()
                #         altSlot.texture = altTex
                #         altSlot.texture_coords = 'UV'

        print(Materials_array)
Exemple #22
0
def write_level(filepath, context):
    scene = context.scene

    # collect meshes

    level_meshes = []

    for obj in scene.objects:
        if obj.type != 'MESH':
            continue
        mesh = obj.to_mesh()
        mesh.transform(obj.matrix_world)

        print(obj.matrix_world)

        mesh_vertices = mesh.vertices[:]
        mesh_polygons = mesh.polygons[:]
        materials = mesh.materials[:]

        uv_layer = None
        if len(mesh.uv_layers) > 0:
            uv_layer = mesh.uv_layers.active.data

        # one mesh per material
        for mat_index, mat in enumerate(materials):
            vertex_dict = {}
            vertices = []
            faces = []

            polygons = [
                p for p in mesh_polygons if p.material_index == mat_index
            ]
            for poly in polygons:
                if uv_layer is not None:
                    texcoords = [
                        uv_layer[i].uv
                        for i in range(poly.loop_start, poly.loop_start +
                                       poly.loop_total)
                    ]
                else:
                    texcoords = [[0, 0] * len(poly.vertices)]
                face = []
                for i in range(len(poly.vertices)):
                    vertex = mesh_vertices[poly.vertices[i]]
                    position = vertex.co
                    normal = vertex.normal
                    texcoord = texcoords[i]
                    key = vec3_to_key(position), vec3_to_key(
                        normal), vec2_to_key(texcoord)
                    vertex_index = vertex_dict.get(key)
                    if vertex_index is None:
                        vertex_index = vertex_dict[key] = len(vertices)
                        vertices.append((position, normal, texcoord))
                    face.append(vertex_index)
                faces.append(face)

            mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat)
            base_color_texture = mat_wrap.base_color_texture.image.filepath
            material = Material(
                name=mat.name,
                base_color_texture=os.path.basename(base_color_texture))

            level_meshes.append(
                LevelMesh(material=material, vertices=vertices, faces=faces))

        obj.to_mesh_clear()

    # dump meshes

    print('Exporting %d meshes' % (len(level_meshes)))

    with open(filepath, 'wb') as outfile:
        write_int32(outfile, len(level_meshes))
        for mesh in level_meshes:
            print('Exporting submesh (material: `%s`, verts: %d, faces: %d)' %
                  (mesh.material.name, len(mesh.vertices), len(mesh.faces)))

            # write material
            write_string(outfile, mesh.material.name)
            write_string(outfile, mesh.material.base_color_texture)

            # write vertices
            write_int32(outfile, len(mesh.vertices))
            for vertex in mesh.vertices:
                write_vec3(outfile, vertex[0])  # position
                write_vec3(outfile, vertex[1])  # normal
                write_vec2(outfile, vertex[2])  # texcoord

            # write faces
            write_int32(outfile, len(mesh.faces))
            for face in mesh.faces:
                write_int8(outfile, len(face))
                for vert_index in face:
                    write_int32(outfile, vert_index)
Exemple #23
0
        def write_mesh(mesh):
            mesh_vertices = mesh.vertices[:]
            mesh_polygons = mesh.polygons[:]
            materials = mesh.materials[:]

            uv_layer = None
            if len(mesh.uv_layers) > 0:
                uv_layer = mesh.uv_layers.active.data

            # write meshes (one per material)
            write_int32(outfile, len(materials))
            for mat_index, mat in enumerate(materials):
                # collect vertices/triangles

                polygons = [
                    p for p in mesh_polygons if p.material_index == mat_index
                ]
                vertex_dict = {}
                vertices = []
                triangles = []

                for poly in polygons:
                    if uv_layer is not None:
                        texcoords = [
                            uv_layer[i].uv
                            for i in range(poly.loop_start, poly.loop_start +
                                           poly.loop_total)
                        ]
                    else:
                        texcoords = [[0, 0] * len(poly.vertices)]

                    def vec3_to_key(v):
                        return round(v[0], 6), round(v[1], 6), round(v[2], 6)

                    def vec2_to_key(v):
                        return round(v[0], 6), round(v[1], 6)

                    def vertex_index(i):
                        vertex = mesh_vertices[poly.vertices[i]]
                        position = vertex.co
                        normal = vertex.normal
                        texcoord = texcoords[i]
                        key = vec3_to_key(position), vec3_to_key(
                            normal), vec2_to_key(texcoord)
                        vertex_index = vertex_dict.get(key)
                        if vertex_index is None:
                            vertex_index = vertex_dict[key] = len(vertices)
                            vertices.append((position, normal, texcoord))
                        return vertex_index

                    for i in range(1, len(poly.vertices) - 1):
                        triangles.append((vertex_index(0), vertex_index(i),
                                          vertex_index(i + 1)))

                print(
                    'Exporting submesh (material: `%s`, vertices: %d, triangles: %d)'
                    % (mat.name, len(vertices), len(triangles)))

                # write material
                write_string(outfile, mat.name)
                mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat)
                base_color_texture = mat_wrap.base_color_texture.image.filepath
                write_string(outfile, os.path.basename(base_color_texture))

                # write vertices
                write_int32(outfile, len(vertices))
                for vertex in vertices:
                    write_vec3(outfile, vertex[0])  # position
                    write_vec3(outfile, vertex[1])  # normal
                    write_vec2(outfile, vertex[2])  # texcoord

                # write triangles
                write_int32(outfile, len(triangles))
                for tri in triangles:
                    write_int32(outfile, tri[0])
                    write_int32(outfile, tri[1])
                    write_int32(outfile, tri[2])
def create_material_from_RSE_specification(
        materialSpecification: RSEMaterialDefinition, texturePaths: List[str]):
    """Creates a material from an RSE specification.
    This does ignore some values that don't map well to PBR and don't influence model behaviour much.
    Materials will be more finely tuned in the game engine.

    materialSpecification is an RSEMaterialDefinition as read by RSEModelReader

    gameDataPath is meant to be the Data folder within the games installation
        directory, as that directory structure is used when loading textures"""

    #Create new material
    newMaterial = bpy.data.materials.new(
        name=materialSpecification.material_name.string)
    newMaterialBSDFWrap = node_shader_utils.PrincipledBSDFWrapper(
        newMaterial, is_readonly=False)

    textureName = materialSpecification.texture_name.string
    texToLoad = None

    #Search for texture to load
    for path in texturePaths:
        texToLoad = find_texture(textureName, path)
        #if a texture was found, don't continue searching
        if texToLoad is not None:
            texToLoad = texToLoad + ".PNG"
            break

    if texToLoad is None:
        log.error("Failed to find texture: %s", textureName)
    else:
        log.debug("Final texture to load: %s", texToLoad)

    #TODO: Refactor texture loading, expand to support image sequences
    if texToLoad is not None:
        # Texture loading code adapted from https://stackoverflow.com/q/19076062
        # Load the image
        texImage = bpy.data.images.load(texToLoad)
        # Create texture from image
        # Add texture slot for color texture
        #textureSlot = newMaterial.texture_paint_slots.add()

        newMaterialBSDFWrap.base_color_texture.use_alpha = True
        #textureSlot.use_map_alpha = True
        #textureSlot.alpha_factor = materialSpecification.opacity
        newMaterialBSDFWrap.base_color_texture.image = texImage
        newMaterialBSDFWrap.base_color_texture.texcoords = 'UV'

    materialBlendMode = "opaque"
    if materialSpecification.CXPMaterialProperties is not None:
        materialBlendMode = materialSpecification.CXPMaterialProperties.blendMode

    if materialBlendMode != "opaque":
        #TODO: Enable proper translucency in blender 2.8
        #TODO: Toggle shadows in blender 2.8
        #newMaterial.use_transparency = True
        #Blenders material transparency method is different to how masked alpha would work in a game engine,
        # this still provides alpha blending, but if you use Z method the transparent part of the surface
        # still has specular properties. In this instance, MASK provides expected results
        #On further reflection, this might actually be desired. Left the comments here and other parameters which can be tweaked as more areas are tested. This also has the benefit of allowing transparency to work in Rendered mode.
        #newMaterial.transparency_method = 'MASK'
        if materialBlendMode == "colorkey":
            #TODO: Setup a node in material to mask based on the colorkey color
            newMaterial.blend_method = 'CLIP'
        else:
            newMaterial.blend_method = 'BLEND'
        #newMaterial.specular_alpha = 0.0

        #disable shadowing on translucent materials, as unexpected results occur otherwise
        #TODO: Reenable the options for toggling shadows when API is better documented
        #newMaterialBSDFWrap.use_cast_shadows = False
        #newMaterialBSDFWrap.use_shadows = False

        if texToLoad is not None:
            newMaterialBSDFWrap.transmission = 0.0
        else:
            #TODO: Check that opacity is not used when alphaMethod == 1 or SAM_Opaque
            newMaterialBSDFWrap.transmission = materialSpecification.opacity

    # TODO: work out if materialSpecification.ambient should be averaged and applied
    # to newMaterial.ambient, or if it's for the lighting model that might be
    # specified in materialSpecification.unknown2
    newMaterial.diffuse_color = materialSpecification.diffuseColorFloat[
        0:3]  # change color
    newMaterial.specular_color = materialSpecification.specularColorFloat[0:3]

    newMaterialBSDFWrap.specular = materialSpecification.specularLevel
    newMaterialBSDFWrap.roughness = 1 - materialSpecification.specularLevel
    #newMaterial.use_vertex_color_light = True

    return newMaterial
def skm_to_blender(skm_data, importedObjects, IMAGE_SEARCH):
    from bpy_extras.image_utils import load_image

    contextObName = None
    contextMaterial = None
    context_mat_wrap = None
    contextMatrix_rot = None  # Blender.mathutils.Matrix(); contextMatrix.identity()
    # contextMatrix_tx = None # Blender.mathutils.Matrix(); contextMatrix.identity()

    TEXTURE_DICT = {}
    MATDICT = {}
    WRAPDICT = {}

    # mdf_resolve
    # read_texture
    # bpy_extras.image_utils.load_image
    # load_material_image

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

        u_scale, v_scale, u_offset, v_offset = 1.0, 1.0, 0.0, 0.0
        mirror = False
        extension = 'wrap'  # 'mirror', 'decal'

        img = TEXTURE_DICT[contextMaterial.name] = load_image(
            texture_path, ToEE_data_dir)

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

    def mdf_resolve(mdf_filename):
        mdf_fullpath = os.path.join(ToEE_data_dir, mdf_filename)
        if not os.path.exists(mdf_fullpath):
            print("MDF %s not found" % mdf_fullpath)
            return

        with open(mdf_fullpath, 'rb') as mdf_file:
            mdf_raw = mdf_file.read()

        mdf_data = MdfFile()
        mdf_data.from_raw_data(mdf_raw)

        print("Registering texture: %s" % mdf_data.texture_filepath)
        read_texture(
            mdf_data.texture_filepath, "Diffuse", "COLOR"
        )  # "Specular / SPECULARITY", "Opacity / ALPHA", "Bump / NORMAL"
        return

    def putContextMesh(
        skm_data
    ):  # myContextMesh_vertls, myContextMesh_facels, myContextMeshMaterials):
        '''
        Creates Mesh Object from vertex/face/material data
        '''
        # Create new mesh
        bmesh = bpy.data.meshes.new(contextObName)

        vertex_count = len(skm_data.vertex_data)
        face_count = len(skm_data.face_data)
        print("------------ FLAT ----------------")
        print("%d vertices, %d faces" % (vertex_count, face_count))

        # Create vertices
        bmesh.vertices.add(vertex_count)
        flattened_vtx_pos = [
            t for vtx in skm_data.vertex_data for t in vtx.pos[0:3]
        ]
        bmesh.vertices.foreach_set("co", flattened_vtx_pos)

        # Create faces (Triangles) - make face_count Polygons, each loop defined by 3 vertices
        bmesh.polygons.add(face_count)
        bmesh.loops.add(face_count * 3)
        bmesh.polygons.foreach_set("loop_start", range(0, face_count * 3, 3))
        bmesh.polygons.foreach_set("loop_total", (3, ) * face_count)
        flattened_face_vtx_map = [
            t for fa in skm_data.face_data for t in fa.vertex_ids
        ]
        bmesh.loops.foreach_set("vertex_index", flattened_face_vtx_map)

        # Apply Materials
        for mm in skm_data.material_data:
            mat_name = mm.id.name
            bmat = MATDICT.get(mm.id.name)
            if bmat:
                img = TEXTURE_DICT.get(bmat.name)
            else:
                print(" WARNING! Material %s not defined!" % mat_name)
                bmat = MATDICT[mat_name] = bpy.data.materials.new(mat_name)
                img = None
            bmesh.materials.append(bmat)

        # Get UV coordinates for each polygon's vertices
        print("Setting UVs")
        bmesh.uv_layers.new(do_init=False)
        uv_faces = bmesh.uv_layers.active.data[:]
        if uv_faces:
            for fidx, fa in enumerate(skm_data.face_data):
                bmesh.polygons[fidx].material_index = fa.material_id
                # bmat = bmesh.materials[fa.material_id]
                # img = TEXTURE_DICT.get(bmat.name)
                # uv_faces[fidx].image = img
            uvl = bmesh.uv_layers.active.data[:]
            for fidx, pl in enumerate(bmesh.polygons):
                face = skm_data.face_data[fidx]
                v1, v2, v3 = face.vertex_ids

                uvl[pl.loop_start + 0].uv = skm_data.vertex_data[v1].uv
                uvl[pl.loop_start + 1].uv = skm_data.vertex_data[v2].uv
                uvl[pl.loop_start + 2].uv = skm_data.vertex_data[v3].uv

        # Finish up
        bmesh.validate()
        bmesh.update()

        # Create new object from mesh
        ob = bpy.data.objects.new(contextObName, bmesh)
        object_dictionary[contextObName] = ob
        importedObjects.append(ob)

        collection = SCN.collection
        collection.objects.link(ob)
        ob.select_set(True)

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

    def putRig(skm_data):
        '''
        Creates rig object for Mesh Object, and parents it (Armature type parenting, so it deforms it via bones)
        '''
        # Bones
        print("Getting bones")
        obj = object_dictionary[contextObName]
        barm = bpy.data.armatures.new(armatureName)
        rig = bpy.data.objects.new(rigObName, barm)
        SCN.collection.objects.link(rig)
        bpy.context.view_layer.objects.active = rig
        rig.select_set(True)
        bpy.ops.object.mode_set(
            mode='EDIT')  # set to Edit Mode so bones can be added
        bone_dump = open(os.path.join(ToEE_data_dir, "bone_dump.txt"), 'w')

        fh = open("D:/bones.txt", "wt")

        vertex_groups = dict()

        for bone_id, bd in enumerate(skm_data.bone_data):
            bone_name = str(bd.name)
            bone = barm.edit_bones.new(bone_name)  # type: bpy.types.EditBone
            bone.select = True

            wi = mathutils.Matrix(bd.world_inverse_matrix)
            world = wi.inverted_safe()
            if bd.parent_id != -1:
                bone.parent = barm.edit_bones[bd.parent_id]

            bone.head = Vector([0, 0, 0])
            bone.tail = Vector([0, 0, 5])
            bone.matrix = world

            print(
                "****************************************************************************",
                file=fh)
            print(bone_name, file=fh)
            print("BONE MATRIX:", file=fh)
            print(bone.matrix, file=fh)
            print("WORLD INVERSE:", file=fh)
            print(world, file=fh)
            print(
                "****************************************************************************",
                file=fh)

            vg = obj.vertex_groups.new(
                name=bone_name)  # Create matching vertex groups
            vertex_groups[bone_id] = vg

        fh.close()
        bone_dump.close()
        bpy.ops.object.mode_set(mode='OBJECT')  # do an implicit update
        # parent obj with rig, using Armaturre type parenting so Bones will deform vertices
        obj.parent = rig
        obj.parent_type = 'ARMATURE'

        print("********************************************************")
        print("BONE WEIGHTS")
        print("********************************************************")

        # Set Vertex bone weights
        for vidx, vtx in enumerate(skm_data.vertex_data):
            attachment_count = len(vtx.attachment_bones)
            for i in range(0, attachment_count):
                bone_id = vtx.attachment_bones[i]
                bone_wt = vtx.attachment_weights[i]
                vertex_groups[bone_id].add((vidx, ), bone_wt, 'ADD')

        # object_dictionary[rigObName] = obj
        # rig_dictionary[contextObName] = obj
        importedObjects.append(obj)

    def dump_bones():
        bone_dump = open(os.path.join(ToEE_data_dir, 'bone_dump_skm.txt'), 'w')
        for skm_bone_id, bd in enumerate(skm_data.bone_data):
            bone_dump.write("\n\n*******  %d %s  ********** " %
                            (skm_bone_id, str(bd.name)) + " Parent: (%d)" %
                            (bd.parent_id))
            bone_dump.write("\n")
            bone_dump.write("WorldInverse matrix: " + str(bd.world_inverse))
            bone_dump.write("\n")
        bone_dump.close()

    contextObName = "ToEE Model"
    rigObName = "ToEE Rig"
    armatureName = "ToEE Model Skeleton"

    ## Create materials
    progress.step("Loading materials and images...")
    # create_materials(skm_data)
    for mm in skm_data.material_data:
        mdf_path = mm.id.name  # path relative to data_dir (that's how ToEE rolls)
        material_name = mdf_path

        contextMaterial = bpy.data.materials.new(
            material_name)  # material_name.rstrip()
        contextMaterial.use_nodes = True

        context_mat_wrap = node_shader_utils.PrincipledBSDFWrapper(
            contextMaterial, is_readonly=False)
        context_mat_wrap.use_nodes = True

        print("Registering material: %s" % material_name)
        MATDICT[material_name] = contextMaterial
        WRAPDICT[contextMaterial] = context_mat_wrap

        mdf_resolve(mdf_path)

    # Create Mesh object
    progress.step("Creating Mesh...")
    putContextMesh(skm_data)

    # Create Rig
    progress.step("Creating Rig...")
    putRig(skm_data)

    dump_bones()
    return
Exemple #26
0
def write_mtl(scene, filepath, path_mode, copy_set, mtl_dict):
    world = scene.world
    world_amb = Color((0.8, 0.8, 0.8))

    source_dir = os.path.dirname(bpy.data.filepath)
    dest_dir = os.path.dirname(filepath)

    with open(filepath, "w", encoding="utf8", newline="\n") as f:
        fw = f.write

        fw('# Blender MTL File: %r\n' % (os.path.basename(bpy.data.filepath) or "None"))
        fw('# Material Count: %i\n' % len(mtl_dict))

        mtl_dict_values = list(mtl_dict.values())
        mtl_dict_values.sort(key=lambda m: m[0])

        # Write material/image combinations we have used.
        # Using mtl_dict.values() directly gives un-predictable order.
        for mtl_mat_name, mat in mtl_dict_values:
            # Get the Blender data for the material and the image.
            # Having an image named None will make a bug, dont do it :)

            fw('\nnewmtl %s\n' % mtl_mat_name)  # Define a new material: matname_imgname

            mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat) if mat else None

            if mat_wrap:
                use_mirror = mat_wrap.metallic != 0.0
                use_transparency = mat_wrap.alpha != 1.0

                # XXX Totally empirical conversion, trying to adapt it
                #     (from 1.0 - 0.0 Principled BSDF range to 0.0 - 900.0 OBJ specular exponent range)...
                spec = (1.0 - mat_wrap.roughness) * 30
                spec *= spec
                fw('Ns %.6f\n' % spec)

                # Ambient
                if use_mirror:
                    fw('Ka %.6f %.6f %.6f\n' % (mat_wrap.metallic, mat_wrap.metallic, mat_wrap.metallic))
                else:
                    fw('Ka %.6f %.6f %.6f\n' % (1.0, 1.0, 1.0))
                fw('Kd %.6f %.6f %.6f\n' % mat_wrap.base_color[:3])  # Diffuse
                # XXX TODO Find a way to handle tint and diffuse color, in a consistent way with import...
                fw('Ks %.6f %.6f %.6f\n' % (mat_wrap.specular, mat_wrap.specular, mat_wrap.specular))  # Specular
                # Emission, not in original MTL standard but seems pretty common, see T45766.
                fw('Ke %.6f %.6f %.6f\n' % mat_wrap.emission_color[:3])
                fw('Ni %.6f\n' % mat_wrap.ior)  # Refraction index
                fw('d %.6f\n' % mat_wrap.alpha)  # Alpha (obj uses 'd' for dissolve)

                # See http://en.wikipedia.org/wiki/Wavefront_.obj_file for whole list of values...
                # Note that mapping is rather fuzzy sometimes, trying to do our best here.
                if mat_wrap.specular == 0:
                    fw('illum 1\n')  # no specular.
                elif use_mirror:
                    if use_transparency:
                        fw('illum 6\n')  # Reflection, Transparency, Ray trace
                    else:
                        fw('illum 3\n')  # Reflection and Ray trace
                elif use_transparency:
                    fw('illum 9\n')  # 'Glass' transparency and no Ray trace reflection... fuzzy matching, but...
                else:
                    fw('illum 2\n')  # light normally

                #### And now, the image textures...
                image_map = {
                        "map_Kd": "base_color_texture",
                        "map_Ka": None,  # ambient...
                        "map_Ks": "specular_texture",
                        "map_Ns": "roughness_texture",
                        "map_d": "alpha_texture",
                        "map_Tr": None,  # transmission roughness?
                        "map_Bump": "normalmap_texture",
                        "disp": None,  # displacement...
                        "refl": "metallic_texture",
                        "map_Ke": "emission_color_texture",
                        }

                for key, mat_wrap_key in sorted(image_map.items()):
                    if mat_wrap_key is None:
                        continue
                    tex_wrap = getattr(mat_wrap, mat_wrap_key, None)
                    if tex_wrap is None:
                        continue
                    image = tex_wrap.image
                    if image is None:
                        continue

                    filepath = io_utils.path_reference(image.filepath, source_dir, dest_dir,
                                                       path_mode, "", copy_set, image.library)
                    options = []
                    if key == "map_Bump":
                        if mat_wrap.normalmap_strength != 1.0:
                            options.append('-bm %.6f' % mat_wrap.normalmap_strength)
                    if tex_wrap.translation != Vector((0.0, 0.0, 0.0)):
                        options.append('-o %.6f %.6f %.6f' % tex_wrap.translation[:])
                    if tex_wrap.scale != Vector((1.0, 1.0, 1.0)):
                        options.append('-s %.6f %.6f %.6f' % tex_wrap.scale[:])
                    if options:
                        fw('%s %s %s\n' % (key, " ".join(options), repr(filepath)[1:-1]))
                    else:
                        fw('%s %s\n' % (key, repr(filepath)[1:-1]))

            else:
                # Write a dummy material here?
                fw('Ns 500\n')
                fw('Ka 0.8 0.8 0.8\n')
                fw('Kd 0.8 0.8 0.8\n')
                fw('Ks 0.8 0.8 0.8\n')
                fw('d 1\n')  # No alpha
                fw('illum 2\n')  # light normally
Exemple #27
0
    def __init__(self, model, blender_index, index):
        self.blender_index = blender_index
        self.index = index
        material = bpy.data.materials[blender_index]
        self.name = material.name

        self.type = material.nns_mat_type

        self.light0 = 'on' if material.nns_light0 else 'off'
        self.light1 = 'on' if material.nns_light1 else 'off'
        self.light2 = 'on' if material.nns_light2 else 'off'
        self.light3 = 'on' if material.nns_light3 else 'off'
        self.shininess_table_flag = 'on' if material.nns_use_srst else 'off'
        self.fog_flag = 'on' if material.nns_fog else 'off'
        self.wire_mode = 'on' if material.nns_wireframe else 'off'
        self.depth_test_decal = 'on' if material.nns_depth_test else 'off'
        self.translucent_update_depth = (
            'on' if material.nns_update_depth_buffer else 'off')
        self.render_1_pixel = 'on' if material.nns_render_1_pixel else 'off'
        self.far_clipping = 'on' if material.nns_far_clipping else 'off'
        self.polygon_id = material.nns_polygonid
        self.face = material.nns_display_face
        self.polygon_mode = material.nns_polygon_mode
        self.tex_gen_mode = material.nns_tex_gen_mode
        self.tex_gen_st_src = material.nns_tex_gen_st_src
        self.tex_tiling_u = material.nns_tex_tiling_u
        self.tex_tiling_v = material.nns_tex_tiling_v
        row0 = material.nns_tex_effect_mtx_0
        row1 = material.nns_tex_effect_mtx_1
        row2 = material.nns_tex_effect_mtx_2
        row3 = material.nns_tex_effect_mtx_3
        matrix = f'{row0[0]} {row0[1]} 0.0 0.0 ' \
                 f'{row1[0]} {row1[1]} 0.0 0.0 ' \
                 f'{row2[0]} {row2[1]} 1.0 0.0 ' \
                 f'{row3[0]} {row3[1]} 0.0 1.0'
        self.tex_effect_mtx = matrix
        self.tex_scale = f'{material.nns_tex_scale[0]} ' \
                         f'{material.nns_tex_scale[1]}'
        self.tex_rotate = str(material.nns_tex_rotate)
        self.tex_translate = f'{material.nns_tex_translate[0]} ' \
                             f'{material.nns_tex_translate[1]}'

        self.image_idx = -1
        self.palette_idx = -1

        if material.is_nns:
            self.alpha = material.nns_alpha
            self.diffuse = ' '.join(
                [str(int(round(lin2s(x) * 31))) for x in material.nns_diffuse])
            self.specular = ' '.join([
                str(int(round(lin2s(x) * 31))) for x in material.nns_specular
            ])
            self.ambient = ' '.join(
                [str(int(round(lin2s(x) * 31))) for x in material.nns_ambient])
            self.emission = ' '.join([
                str(int(round(lin2s(x) * 31))) for x in material.nns_emission
            ])
            if material.nns_image is not None \
                    and "tx" in material.nns_mat_type:
                filepath = material.nns_image.filepath
                path = os.path.realpath(bpy.path.abspath(filepath))
                _, extension = os.path.splitext(path)
                if extension == '.tga':
                    texture = model.find_texture(path)
                    self.image_idx = texture.index
                    self.palette_idx = texture.palette_idx
        else:
            # For now let's use PrincipledBSDF to get the color and image.
            wrap = node_shader_utils.PrincipledBSDFWrapper(material)
            self.alpha = int(wrap.alpha * 31)
            self.diffuse = ' '.join([
                str(int(round(lin2s(wrap.base_color[0]) * 31))),
                str(int(round(lin2s(wrap.base_color[1]) * 31))),
                str(int(round(lin2s(wrap.base_color[2]) * 31)))
            ])
            self.specular = ' '.join(
                [str(int(round(wrap.specular * 31))) for _ in range(3)])
            self.ambient = '31 31 31'
            self.emission = '0 0 0'

            tex_wrap = getattr(wrap, 'base_color_texture', None)
            if tex_wrap is not None and tex_wrap.image is not None:
                path = os.path.realpath(
                    bpy.path.abspath(tex_wrap.image.filepath,
                                     library=tex_wrap.image.library))
                _, extension = os.path.splitext(path)
                if extension == '.tga':
                    texture = model.find_texture(path)
                    self.image_idx = texture.index
                    self.palette_idx = texture.palette_idx