def bm_make_uv_layer(pim_version, bm, faces, uv_layer_name, uv_layer_data): """Add UV Layer to the BMesh object. :param pim_version: PIM version of the File from which data have been read :type pim_version: int :param bm: BMesh data to add UV Layer to :type bm: bmesh.types.BMesh :param faces: Faces as Vertex indices :type faces: list :param uv_layer_name: Name for the layer :type uv_layer_name: str :param uv_layer_data: UV Layer data :type uv_layer_data: list """ uv_lay = bm.loops.layers.uv.new(uv_layer_name) for face_i, face in enumerate(bm.faces): # f_v = shift_values(faces[face_i]) # NOTE: Needed for Blender versions prior 2.69 (Blender bug) f_v = faces[face_i] # NOTE: For Blender 2.69 and above # print(' face[%i]: %s / %s' % (face_i, str(face), str(f_v))) # print_values(" * f_verts", f_v, 10) for loop_i, loop in enumerate(face.loops): if pim_version < 6: loop[uv_lay].uv = _convert.change_to_scs_uv_coordinates( uv_layer_data[f_v[loop_i]]) else: loop[uv_lay].uv = _convert.change_to_scs_uv_coordinates( uv_layer_data[face_i][loop_i])
def bm_make_uv_layer(pim_version, bm, faces, uv_layer_name, uv_layer_data): """Add UV Layer to the BMesh object. :param pim_version: PIM version of the File from which data have been read :type pim_version: int :param bm: BMesh data to add UV Layer to :type bm: bmesh.types.BMesh :param faces: Faces as Vertex indices :type faces: list :param uv_layer_name: Name for the layer :type uv_layer_name: str :param uv_layer_data: UV Layer data :type uv_layer_data: list """ uv_lay = bm.loops.layers.uv.new(uv_layer_name) for face_i, face in enumerate(bm.faces): # f_v = shift_values(faces[face_i]) # NOTE: Needed for Blender versions prior 2.69 (Blender bug) f_v = faces[face_i] # NOTE: For Blender 2.69 and above # print(' face[%i]: %s / %s' % (face_i, str(face), str(f_v))) # print_values(" * f_verts", f_v, 10) for loop_i, loop in enumerate(face.loops): if pim_version < 6: loop[uv_lay].uv = _convert.change_to_scs_uv_coordinates(uv_layer_data[f_v[loop_i]]) else: loop[uv_lay].uv = _convert.change_to_scs_uv_coordinates(uv_layer_data[face_i][loop_i])
def _get_geometry_dict(root_object, obj, mesh, offset_matrix, material_dict, used_materials, bone_list, scs_globals): """ :param root_object: SCS Root Object :type root_object: bpy.types.Object :param obj: Actual Object data :type obj: bpy.types.Object :param mesh: Object's Mesh data :type mesh: bpy.types.Mesh :param offset_matrix: Matrix for specifying of pivot point :type offset_matrix: Matrix :param material_dict: Materials used in current Object :type material_dict: dict :param used_materials: All Materials used in 'SCS Game Object' :type used_materials: list :param bone_list: Bones for export :type bone_list: list :param scs_globals: SCS Tools Globals :type scs_globals: GlobalSCSProps :return: Piece dictionary, Skin list, Skin weight count, Skin clone count :rtype: list """ # Create Index => Material Dictionary... index_material_dict = _create_index_material_dict(material_dict) # Create Piece (Material) Dictionary... piece_dict = {} for material in material_dict: material_i = loc_material_i = material_dict[material][ 0] # Eliminates multiple Material assignment # Set correct Material index for Piece for used_mat_i, used_mat in enumerate(used_materials): if material == used_mat: material_i = used_mat_i # print(' "%s" = %s => %s' % (str(material), str(material_dict[material]), str(loc_material_i))) piece_dict[loc_material_i] = {} piece_dict[loc_material_i]['material_index'] = material_i piece_dict[loc_material_i]['hash_dict'] = {} piece_dict[loc_material_i]['verts'] = [] piece_dict[loc_material_i]['faces'] = [] # DATA LAYERS uv_layers = mesh.tessface_uv_textures vc_layers = mesh.tessface_vertex_colors vertex_groups = obj.vertex_groups # Make sure if everything is recalculated... mesh.calc_tessface() mesh.calc_normals() mesh.calc_normals_split() for tessface in mesh.tessfaces: material = index_material_dict[tessface.material_index] loc_material_i = material_dict[material][ 0] # Eliminates multiple Material assignment # print('tessface [%s]: %s' % (str(tessface.index).rjust(2, "0"), str(tessface.vertices))) # print(' "%s" = %s => %s' % (str(material), str(material_dict[material]), str(material_i))) face_verts = [] for facevert_i, facevert in enumerate(tessface.vertices): facevert_common_data = {} facevert_unique_data = {} # POSITION facevert_co = offset_matrix.inverted( ) * obj.matrix_world * mesh.vertices[facevert].co # print(' facevert [%s] - position: %s' % (str(facevert).rjust(2, "0"), str(facevert_co))) scs_position = (Matrix.Scale(scs_globals.export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * facevert_co) facevert_common_data['_POSITION'] = scs_position # NORMAL facevert_no = mesh.vertices[facevert].normal # print(' normal: %s' % str(facevert_no)) scs_normal = (_convert_utils.scs_to_blend_matrix().inverted() * offset_matrix.inverted() * obj.matrix_world * facevert_no) # normalize normal vector and set it facevert_common_data['_NORMAL'] = Vector(scs_normal).normalized() # VERTEX GROUPS - for every vertices we need weight for every existing vertex group # print(' vg : %s len(%i)' % (str(vertex_groups), len(vertex_groups))) vert_grp = {} unused_groups = vertex_groups.keys( ) # store all groups that are not yet used for vg_elem in mesh.vertices[facevert].groups: vert_grp[vertex_groups[vg_elem.group].name] = vg_elem.weight unused_groups.remove( vertex_groups[vg_elem.group].name) # remove it from unused for group_name in unused_groups: # for all unused groups that are left write weight 0 vert_grp[group_name] = 0.0 # print(' vert_grp: %s' % str(vert_grp)) facevert_common_data['_VG'] = vert_grp # VERTEX UV LAYERS # print(' uv: %s len(%i)' % (str(uv_layers), len(uv_layers))) uv_lyr = {} if scs_globals.active_uv_only: uv = uv_layers.active.data[tessface.index].uv[facevert_i][:] scs_uv = _convert_utils.change_to_scs_uv_coordinates(uv) uv_lyr[uv_layers.active.name] = Vector(scs_uv) else: for layer_i, layer in enumerate(uv_layers.keys()): uv = uv_layers[layer_i].data[ tessface.index].uv[facevert_i][:] # print(' uv%i: %r %s' % (layer_i, layer, str(uv))) scs_uv = _convert_utils.change_to_scs_uv_coordinates(uv) uv_lyr[layer] = Vector(scs_uv) # print(' uv_lyr: %s' % str(uv_lyr)) facevert_unique_data['_UV'] = uv_lyr # VERTEX COLOR LAYERS # NOTE: In current PIM version 5 there should be only one Color layer present, # but I'll leave the multilayer solution here just for the case it could # be used in the future. active_vc_only = True # print(' vc : %s len(%i)' % (str(vc_layers), len(vc_layers))) if vc_layers and scs_globals.export_vertex_color: vc_lyr = {} if active_vc_only: if facevert_i == 0: vc = vc_layers.active.data[tessface.index].color1[:] elif facevert_i == 1: vc = vc_layers.active.data[tessface.index].color2[:] elif facevert_i == 2: vc = vc_layers.active.data[tessface.index].color3[:] elif facevert_i == 3: vc = vc_layers.active.data[tessface.index].color4[:] if scs_globals.export_vertex_color_type == 'rgbda': vc = (vc[0], vc[1], vc[2], 1.0) # print(' vc%i: %r %s' % (layer_i, layer, str(vc))) vc_lyr[vc_layers.active.name] = Vector(vc) else: for layer_i, layer in enumerate(vc_layers.keys()): if facevert_i == 0: vc = vc_layers[layer_i].data[ tessface.index].color1[:] elif facevert_i == 1: vc = vc_layers[layer_i].data[ tessface.index].color2[:] elif facevert_i == 2: vc = vc_layers[layer_i].data[ tessface.index].color3[:] elif facevert_i == 3: vc = vc_layers[layer_i].data[ tessface.index].color4[:] if scs_globals.export_vertex_color_type == 'rgbda': vc = (vc[0], vc[1], vc[2], 1.0) # print(' vc%i: %r %s' % (layer_i, layer, str(vc))) vc_lyr[layer] = Vector(vc) # print(' vc_lyr: %s' % str(vc_lyr)) facevert_unique_data['_RGBA'] = vc_lyr # DATA EVALUATION # print(' *** (%s) *** (%s) ***' % (str(facevert).rjust(3, "0"), str(tessface.vertices[facevert_i]).rjust(3, "0"))) if facevert in piece_dict[loc_material_i]['hash_dict']: for vert in piece_dict[loc_material_i]['hash_dict'][facevert]: # print(' %s > UD: %s' % (str(facevert).rjust(3, "0"), str(facevert_unique_data))) vert_facevert_unique_data = piece_dict[loc_material_i][ 'verts'][vert][1] # print(' %s < UD: %s' % (str(facevert).rjust(3, "0"), str(vert_facevert_unique_data))) if facevert_unique_data == vert_facevert_unique_data: # print(' %s O MATCH!' % str(facevert).rjust(3, "0")) face_verts.append(vert) break else: # print(' %s - NOT in existing record...' % str(facevert).rjust(3, "0")) new_vert_index = len(piece_dict[loc_material_i]['verts']) piece_dict[loc_material_i]['hash_dict'][facevert].append( new_vert_index ) # Add the new vertex index to "hash_dict" record face_verts.append( new_vert_index) # Add the vertex to the actual face piece_dict[loc_material_i]['verts'].append( (facevert_common_data, facevert_unique_data )) # Create a new vertex to 'verts' else: # print(' %s | NOT a record... %s' % (str(facevert).rjust(3, "0"), str(facevert_common_data['_POSITION'][:]))) new_vert_index = len(piece_dict[loc_material_i]['verts']) piece_dict[loc_material_i]['hash_dict'][facevert] = [ new_vert_index ] # Create a new "hash_dict" record face_verts.append( new_vert_index) # Add vertex to the actual face piece_dict[loc_material_i]['verts'].append( (facevert_common_data, facevert_unique_data)) # Create a new vertex to 'verts' # FACES face_verts = face_verts[:: -1] # NOTE: Vertex order is swapped here to make the face normal flipped! Needs a check if it is right. if len(face_verts) == 4: # Simple triangulation... piece_dict[loc_material_i]['faces'].append(face_verts[:3]) piece_dict[loc_material_i]['faces'].append( (face_verts[2], face_verts[3], face_verts[0])) else: piece_dict[loc_material_i]['faces'].append(face_verts) # BONE NAME LIST skin_list = [] skin_weights_cnt = skin_clones_cnt = 0 if bone_list: # if _get_scs_globals().export_anim_file == 'anim': if root_object.scs_props.scs_root_animated == 'anim': bone_name_list = [] for bone_i, bone in enumerate(bone_list): bone_name_list.append(bone.name) # print('%s bone: %r' % (str(bone_i).rjust(3, "0"), str(bone.name))) # SKINNING DATA for vert in mesh.vertices: # SKIN VECTOR # position = Vector(mesh.vertices[vert_i].co) scs_position = ( Matrix.Scale(scs_globals.export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * obj.matrix_world * vert.co) # NOTE: Vertex position - when exported from Maya the value get scaled *10, but it is old & unused in game engine anyway. skin_vector = scs_position # print(' vertex: %s: %s' % (str(vert.index), str(piece_dict[material_i]['hash_dict'][vert.index]))) # SKIN WEIGHTS skin_weights = [] for vg_elem in vert.groups: group_name = vertex_groups[vg_elem.group].name if group_name in bone_name_list: # print(' group: %r - %s' % (group_name, str(group.weight))) bone_index = _get_vertex_group_index( bone_name_list, group_name) skin_weights.append((bone_index, vg_elem.weight)) skin_weights_cnt += 1 else: print( 'WARNING - Vertex Group %r is not a bone weight...' % group_name ) # TODO: Maybe handle this case? Useful? skin_clones = [] # SKIN CLONES if loc_material_i is not None: for v in piece_dict[loc_material_i]['hash_dict'][ vert.index]: skin_clones.append((0, v)) skin_clones_cnt += 1 else: print( 'ERROR - Material indices incorrect! (get_geometry_dict())' ) skin_list.append((skin_vector, skin_weights, skin_clones)) mesh.free_normals_split() # print(' ** piece_dict: %s' % str(piece_dict)) # print('') return piece_dict, skin_list, skin_weights_cnt, skin_clones_cnt
def _get_geometry_dict(root_object, obj, mesh, offset_matrix, material_dict, used_materials, bone_list, scs_globals): """ :param root_object: SCS Root Object :type root_object: bpy.types.Object :param obj: Actual Object data :type obj: bpy.types.Object :param mesh: Object's Mesh data :type mesh: bpy.types.Mesh :param offset_matrix: Matrix for specifying of pivot point :type offset_matrix: Matrix :param material_dict: Materials used in current Object :type material_dict: dict :param used_materials: All Materials used in 'SCS Game Object' :type used_materials: list :param bone_list: Bones for export :type bone_list: list :param scs_globals: SCS Tools Globals :type scs_globals: GlobalSCSProps :return: Piece dictionary, Skin list, Skin weight count, Skin clone count :rtype: list """ # Create Index => Material Dictionary... index_material_dict = _create_index_material_dict(material_dict) # Create Piece (Material) Dictionary... piece_dict = {} for material in material_dict: material_i = loc_material_i = material_dict[material][0] # Eliminates multiple Material assignment # Set correct Material index for Piece for used_mat_i, used_mat in enumerate(used_materials): if material == used_mat: material_i = used_mat_i # print(' "%s" = %s => %s' % (str(material), str(material_dict[material]), str(loc_material_i))) piece_dict[loc_material_i] = {} piece_dict[loc_material_i]['material_index'] = material_i piece_dict[loc_material_i]['hash_dict'] = {} piece_dict[loc_material_i]['verts'] = [] piece_dict[loc_material_i]['faces'] = [] # DATA LAYERS uv_layers = mesh.tessface_uv_textures vc_layers = mesh.tessface_vertex_colors vertex_groups = obj.vertex_groups # Make sure if everything is recalculated... mesh.calc_tessface() mesh.calc_normals() mesh.calc_normals_split() for tessface in mesh.tessfaces: material = index_material_dict[tessface.material_index] loc_material_i = material_dict[material][0] # Eliminates multiple Material assignment # print('tessface [%s]: %s' % (str(tessface.index).rjust(2, "0"), str(tessface.vertices))) # print(' "%s" = %s => %s' % (str(material), str(material_dict[material]), str(material_i))) face_verts = [] for facevert_i, facevert in enumerate(tessface.vertices): facevert_common_data = {} facevert_unique_data = {} # POSITION facevert_co = offset_matrix.inverted() * obj.matrix_world * mesh.vertices[facevert].co # print(' facevert [%s] - position: %s' % (str(facevert).rjust(2, "0"), str(facevert_co))) scs_position = (Matrix.Scale(scs_globals.export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * facevert_co) facevert_common_data['_POSITION'] = scs_position # NORMAL facevert_no = mesh.vertices[facevert].normal # print(' normal: %s' % str(facevert_no)) scs_normal = (_convert_utils.scs_to_blend_matrix().inverted() * offset_matrix.inverted() * obj.matrix_world * facevert_no) # normalize normal vector and set it facevert_common_data['_NORMAL'] = Vector(scs_normal).normalized() # VERTEX GROUPS - for every vertices we need weight for every existing vertex group # print(' vg : %s len(%i)' % (str(vertex_groups), len(vertex_groups))) vert_grp = {} unused_groups = vertex_groups.keys() # store all groups that are not yet used for vg_elem in mesh.vertices[facevert].groups: vert_grp[vertex_groups[vg_elem.group].name] = vg_elem.weight unused_groups.remove(vertex_groups[vg_elem.group].name) # remove it from unused for group_name in unused_groups: # for all unused groups that are left write weight 0 vert_grp[group_name] = 0.0 # print(' vert_grp: %s' % str(vert_grp)) facevert_common_data['_VG'] = vert_grp # VERTEX UV LAYERS # print(' uv: %s len(%i)' % (str(uv_layers), len(uv_layers))) uv_lyr = {} if scs_globals.active_uv_only: uv = uv_layers.active.data[tessface.index].uv[facevert_i][:] scs_uv = _convert_utils.change_to_scs_uv_coordinates(uv) uv_lyr[uv_layers.active.name] = Vector(scs_uv) else: for layer_i, layer in enumerate(uv_layers.keys()): uv = uv_layers[layer_i].data[tessface.index].uv[facevert_i][:] # print(' uv%i: %r %s' % (layer_i, layer, str(uv))) scs_uv = _convert_utils.change_to_scs_uv_coordinates(uv) uv_lyr[layer] = Vector(scs_uv) # print(' uv_lyr: %s' % str(uv_lyr)) facevert_unique_data['_UV'] = uv_lyr # VERTEX COLOR LAYERS # NOTE: In current PIM version 5 there should be only one Color layer present, # but I'll leave the multilayer solution here just for the case it could # be used in the future. active_vc_only = True # print(' vc : %s len(%i)' % (str(vc_layers), len(vc_layers))) if vc_layers and scs_globals.export_vertex_color: vc_lyr = {} if active_vc_only: if facevert_i == 0: vc = vc_layers.active.data[tessface.index].color1[:] elif facevert_i == 1: vc = vc_layers.active.data[tessface.index].color2[:] elif facevert_i == 2: vc = vc_layers.active.data[tessface.index].color3[:] elif facevert_i == 3: vc = vc_layers.active.data[tessface.index].color4[:] if scs_globals.export_vertex_color_type == 'rgbda': vc = (vc[0], vc[1], vc[2], 1.0) # print(' vc%i: %r %s' % (layer_i, layer, str(vc))) vc_lyr[vc_layers.active.name] = Vector(vc) else: for layer_i, layer in enumerate(vc_layers.keys()): if facevert_i == 0: vc = vc_layers[layer_i].data[tessface.index].color1[:] elif facevert_i == 1: vc = vc_layers[layer_i].data[tessface.index].color2[:] elif facevert_i == 2: vc = vc_layers[layer_i].data[tessface.index].color3[:] elif facevert_i == 3: vc = vc_layers[layer_i].data[tessface.index].color4[:] if scs_globals.export_vertex_color_type == 'rgbda': vc = (vc[0], vc[1], vc[2], 1.0) # print(' vc%i: %r %s' % (layer_i, layer, str(vc))) vc_lyr[layer] = Vector(vc) # print(' vc_lyr: %s' % str(vc_lyr)) facevert_unique_data['_RGBA'] = vc_lyr # DATA EVALUATION # print(' *** (%s) *** (%s) ***' % (str(facevert).rjust(3, "0"), str(tessface.vertices[facevert_i]).rjust(3, "0"))) if facevert in piece_dict[loc_material_i]['hash_dict']: for vert in piece_dict[loc_material_i]['hash_dict'][facevert]: # print(' %s > UD: %s' % (str(facevert).rjust(3, "0"), str(facevert_unique_data))) vert_facevert_unique_data = piece_dict[loc_material_i]['verts'][vert][1] # print(' %s < UD: %s' % (str(facevert).rjust(3, "0"), str(vert_facevert_unique_data))) if facevert_unique_data == vert_facevert_unique_data: # print(' %s O MATCH!' % str(facevert).rjust(3, "0")) face_verts.append(vert) break else: # print(' %s - NOT in existing record...' % str(facevert).rjust(3, "0")) new_vert_index = len(piece_dict[loc_material_i]['verts']) piece_dict[loc_material_i]['hash_dict'][facevert].append(new_vert_index) # Add the new vertex index to "hash_dict" record face_verts.append(new_vert_index) # Add the vertex to the actual face piece_dict[loc_material_i]['verts'].append((facevert_common_data, facevert_unique_data)) # Create a new vertex to 'verts' else: # print(' %s | NOT a record... %s' % (str(facevert).rjust(3, "0"), str(facevert_common_data['_POSITION'][:]))) new_vert_index = len(piece_dict[loc_material_i]['verts']) piece_dict[loc_material_i]['hash_dict'][facevert] = [new_vert_index] # Create a new "hash_dict" record face_verts.append(new_vert_index) # Add vertex to the actual face piece_dict[loc_material_i]['verts'].append((facevert_common_data, facevert_unique_data)) # Create a new vertex to 'verts' # FACES face_verts = face_verts[::-1] # NOTE: Vertex order is swapped here to make the face normal flipped! Needs a check if it is right. if len(face_verts) == 4: # Simple triangulation... piece_dict[loc_material_i]['faces'].append(face_verts[:3]) piece_dict[loc_material_i]['faces'].append((face_verts[2], face_verts[3], face_verts[0])) else: piece_dict[loc_material_i]['faces'].append(face_verts) # BONE NAME LIST skin_list = [] skin_weights_cnt = skin_clones_cnt = 0 if bone_list: # if _get_scs_globals().export_anim_file == 'anim': if root_object.scs_props.scs_root_animated == 'anim': bone_name_list = [] for bone_i, bone in enumerate(bone_list): bone_name_list.append(bone.name) # print('%s bone: %r' % (str(bone_i).rjust(3, "0"), str(bone.name))) # SKINNING DATA for vert in mesh.vertices: # SKIN VECTOR # position = Vector(mesh.vertices[vert_i].co) scs_position = (Matrix.Scale(scs_globals.export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * obj.matrix_world * vert.co) # NOTE: Vertex position - when exported from Maya the value get scaled *10, but it is old & unused in game engine anyway. skin_vector = scs_position # print(' vertex: %s: %s' % (str(vert.index), str(piece_dict[material_i]['hash_dict'][vert.index]))) # SKIN WEIGHTS skin_weights = [] for vg_elem in vert.groups: group_name = vertex_groups[vg_elem.group].name if group_name in bone_name_list: # print(' group: %r - %s' % (group_name, str(group.weight))) bone_index = _get_vertex_group_index(bone_name_list, group_name) skin_weights.append((bone_index, vg_elem.weight)) skin_weights_cnt += 1 else: print('WARNING - Vertex Group %r is not a bone weight...' % group_name) # TODO: Maybe handle this case? Useful? skin_clones = [] # SKIN CLONES if loc_material_i is not None: for v in piece_dict[loc_material_i]['hash_dict'][vert.index]: skin_clones.append((0, v)) skin_clones_cnt += 1 else: print('ERROR - Material indices incorrect! (get_geometry_dict())') skin_list.append((skin_vector, skin_weights, skin_clones)) mesh.free_normals_split() # print(' ** piece_dict: %s' % str(piece_dict)) # print('') return piece_dict, skin_list, skin_weights_cnt, skin_clones_cnt