def get_influences(self, bone_map, all_influences): """ :param bone_map: map of bone names to bones :returns influence collection """ # construct my own bone map # my_bone_map = [bone_map[name] for name in self.bones] weights = self.weights my_bone_map, matrices = self.__order_bones(bone_map) if len(self.bones) == 1 and np.allclose(weights, 1.0): # No influence needed influence = Influence() influence[my_bone_map[0].name] = Weight(my_bone_map[0], 1.0) influence = all_influences.create_or_find(influence) self.geometry.apply_matrix(matrices[0]) return InfluenceCollection({0: influence}) influences = {} indices = self.vertex_weight_indices vertex_weight_counts = self.vertex_weight_counts j = 0 # Now construct influences vertices = self.geometry.vertices for vertex_index in range(len(vertex_weight_counts)): weight_count = vertex_weight_counts[vertex_index] influence = Influence() for i in range(weight_count): bone = my_bone_map[indices[j, 0]] influence[bone.name] = Weight(bone, weights[indices[j, 1]]) j += 1 influences[vertex_index] = all_influences.create_or_find(influence) # apply_matrix(matrices[] vertices[vertex_index] return InfluenceCollection(influences)
def get_influences(self, bone_map, all_influences): """ :param bone_map: map of bone names to bones :returns influence collection """ # construct my own bone map # my_bone_map = [bone_map[name] for name in self.bones] weights = self.weights try: my_bone_map, matrices = self.__order_bones(bone_map) if len(self.bones) == 1 and np.allclose( weights, 1.0): # No influence needed influence = Influence() influence[my_bone_map[0].name] = Weight(my_bone_map[0], 1.0) influence = all_influences.create_or_find(influence) # if type(self.geometry) == list: # for x in self.geometry: # x.apply_matrix(matrices[0]) # else: # self.geometry.apply_matrix(matrices[0]) return InfluenceCollection({0: influence}) else: influences = {} indices = self.vertex_weight_indices vertex_weight_counts = self.vertex_weight_counts j = 0 # Now construct influences # vertices = self.geometry.vertices for vertex_index in range(len(vertex_weight_counts)): weight_count = vertex_weight_counts[vertex_index] influence = Influence() for i in range(weight_count): bone = my_bone_map[indices[j, 0]] influence[bone.name] = Weight(bone, weights[indices[j, 1]]) j += 1 influences[vertex_index] = all_influences.create_or_find( influence) # apply_matrix(matrices[] vertices[vertex_index] return InfluenceCollection(influences) except KeyError: # Bone wasn't found, use default influence influence = Influence() x = None for x in bone_map: break influence[x] = Weight(bone_map[x], 1.0) return InfluenceCollection( {0: all_influences.create_or_find(influence)})
def decode_polygon(polygon, influences=None): """ Decodes an mdl0 polygon :returns geometry """ # build the decoder_string decoder if influences is None: influences = polygon.parent.get_influences() pos_matrix_index = polygon.get_weight_index() vertex_index = polygon.get_vertex_index() vertices = polygon.get_vertex_group() normals = polygon.get_normal_group() normal_index = polygon.get_normal_index() colors = polygon.get_color_group() color_index = polygon.get_color0_index() texcoords = [] texcoord_index = polygon.get_uv_index(0) for i in range(polygon.count_uvs()): texcoords.append(polygon.get_uv_group(i)) face_point_indices, weights = decode_indices(polygon, polygon.encode_str) face_point_indices = np.array(face_point_indices, dtype=np.uint) face_point_indices[:, [0, 1]] = face_point_indices[:, [1, 0]] g_verts = PointCollection(vertices.get_decoded(), face_point_indices[:, :, vertex_index]) linked_bone = polygon.get_linked_bone() if pos_matrix_index >= 0: # apply influences to vertices influence_collection = decode_pos_mtx_indices( influences, weights, g_verts, face_point_indices[:, :, pos_matrix_index] // 3) else: influence = influences[linked_bone.weight_id] g_verts.apply_affine_matrix(np.array( linked_bone.get_transform_matrix()), apply=True) influence_collection = InfluenceCollection({0: influence}) from abmatt.converters.geometry import Geometry geometry = Geometry(polygon.name, polygon.get_material().name, g_verts, triangles=None, influences=influence_collection, linked_bone=linked_bone) # create the point collections if normals: geometry.normals = PointCollection( normals.get_decoded(), face_point_indices[:, :, normal_index]) if colors: geometry.colors = ColorCollection( colors.get_decoded(), face_point_indices[:, :, color_index]) for tex in texcoords: pc = PointCollection(tex.get_decoded(), face_point_indices[:, :, texcoord_index], tex.minimum, tex.maximum) geometry.texcoords.append(pc) texcoord_index += 1 return geometry
def decode_pos_mtx_indices(all_influences, weight_groups, vertices, pos_mtx_indices): """ Finds and applies the weight matrix to the corresponding vertices :param all_influences: map of influence ids to influences :param weight_groups: map of each beginning group face_point index to list of weights :param vertices: PointCollection :param pos_mtx_indices: np array of face_point indices corresponding to those in vertices :return: InfluenceCollection """ influences = {} # map vertex indices to influences used by this geometry vert_indices = vertices.face_indices points = vertices.points # Order the indices of each group so we can slice up the indices slicer = sorted(weight_groups.keys()) slicer.append(len(vert_indices)) # add the max onto the end for slicing remapper = {} new_points = [] new_face_indices = deepcopy(vert_indices) # Each weighting slice group for i in range(len(slicer) - 1): start = slicer[i] end = slicer[i + 1] weights = np.array(weight_groups[start]) vertex_slice = vert_indices[start:end] pos_mtx_slice = pos_mtx_indices[start:end] # map each vertex to an influence for i in range(len(vertex_slice)): for j in range(3): vert_id = vertex_slice[i, j] inf = all_influences[weights[pos_mtx_slice[i, j]]] weight_id = inf.influence_id remappings = remapper.get(vert_id) add_it = bool(remappings is None) if not remappings: remapper[vert_id] = remappings = [] if not add_it: add_it = True for index, influence in remappings: if influence.influence_id == weight_id: add_it = False new_face_indices[start + i, j] = index break if add_it: remappings.append((len(new_points), inf)) influences[len(new_points)] = inf new_face_indices[start + i, j] = len(new_points) new_points.append( inf.apply_to(points[vert_id], decode=True)) vertices.points = np.array(new_points) vertices.face_indices = new_face_indices assert len(influences) == len(new_points) return InfluenceCollection(influences)
def decode_pos_mtx_indices(all_influences, weight_groups, vertices, pos_mtx_indices): """ Finds and applies the weight matrix to the corresponding vertices :param all_influences: map of influence ids to influences :param weight_groups: map of each beginning group face_point index to list of weights :param vertices: PointCollection :param pos_mtx_indices: np array of face_point indices corresponding to those in vertices :return: InfluenceCollection """ influences = {} # map vertex indices to influences used by this geometry vert_indices = vertices.face_indices points = vertices.points # Order the indices of each group so we can slice up the indices slicer = sorted(weight_groups.keys()) slicer.append(len(vert_indices)) # add the max onto the end for slicing # Each weighting slice group for i in range(len(slicer) - 1): start = slicer[i] end = slicer[i + 1] weights = np.array(weight_groups[start]) vertex_slice = vert_indices[start:end].flatten() pos_mtx_slice = pos_mtx_indices[start:end].flatten() # get the ordered indices corresponding to vertices vertex_indices, indices = np.unique(vertex_slice, return_index=True) weight_indices = weights[pos_mtx_slice[ indices]] # get the matrix corresponding to vert index, resolve to weight_id # map each vertex id to an influence and apply it for i in range(len(vertex_indices)): vertex_index = vertex_indices[i] if vertex_index not in influences: influences[vertex_index] = influence = all_influences[ weight_indices[i]] points[vertex_index] = influence.apply_to(points[vertex_index], decode=True) elif influences[vertex_index].influence_id != weight_indices[i]: AutoFix.get().warn( f'vertex {vertex_index} has multiple different influences!' ) influences[vertex_index] = all_influences[weight_indices[i]] assert len(influences) == len(points) return InfluenceCollection(influences)
def decode_mdl0_influences(mdl0): influences = {} bones = mdl0.bones bonetable = mdl0.bone_table # Get bonetable influences for i in range(len(bonetable)): index = bonetable[i] if index >= 0: bone = bones[index] influences[i] = Influence( bone_weights={bone.name: Weight(bone, 1)}, influence_id=i) # Get mixed influences nodemix = mdl0.NodeMix if nodemix is not None: for inf in nodemix.mixed_weights: weight_id = inf.weight_id influences[weight_id] = influence = Influence( influence_id=weight_id) for x in inf: bone = bones[bonetable[x[0]]] influence[bone.name] = Weight(bone, x[1]) return InfluenceCollection(influences)
def decode_polygon(polygon, influences): """ Decodes an mdl0 polygon :returns geometry """ # build the decoder_string decoder pos_matrix_index = polygon.get_weight_index() tex_matrix_index = polygon.get_uv_matrix_index(0) vertex_index = polygon.get_vertex_index() vertices = polygon.get_vertex_group() normals = polygon.get_normal_group() normal_index = polygon.get_normal_index() colors = polygon.get_color_group() color_index = polygon.get_color0_index() texcoords = [] texcoord_index = polygon.get_uv_index(0) for i in range(polygon.count_uvs()): texcoords.append(polygon.get_uv_group(i)) face_point_indices, weights = decode_indices(polygon, polygon.encode_str) face_point_indices = np.array(face_point_indices, dtype=np.uint) face_point_indices[:, [0, 1]] = face_point_indices[:, [1, 0]] # decoded_verts = g_verts = PointCollection(decode_geometry_group(vertices), face_point_indices[:, :, vertex_index]) linked_bone = polygon.get_bone() if pos_matrix_index >= 0: # apply influences to vertices influence_collection = decode_pos_mtx_indices( influences, weights, g_verts, face_point_indices[:, :, pos_matrix_index] // 3) else: influence = influences[linked_bone.weight_id] rotation_matrix = get_rotation_matrix( np.array(linked_bone.get_inv_transform_matrix(), dtype=float)) decoded_verts = influence.apply_to_all(g_verts.points, decode=True) if not np.allclose(rotation_matrix, np.identity(3)): for i in range(len(decoded_verts)): decoded_verts[i] = np.dot(rotation_matrix, decoded_verts[i]) influence_collection = InfluenceCollection({0: influence}) if tex_matrix_index > 0: for x in polygon.has_tex_matrix: if x: indices = face_point_indices[:, :, tex_matrix_index] tex_matrix_index += 1 geometry = Geometry(polygon.name, polygon.get_material().name, g_verts, triangles=face_point_indices[:, :, vertex_index:], influences=influence_collection, linked_bone=linked_bone) # create the point collections if normals: geometry.normals = PointCollection( decode_geometry_group(normals), face_point_indices[:, :, normal_index]) if colors: geometry.colors = ColorCollection( ColorCollection.decode_data(colors), face_point_indices[:, :, color_index]) for tex in texcoords: x = decode_geometry_group(tex) pc = PointCollection(x, face_point_indices[:, :, texcoord_index], tex.minimum, tex.maximum) pc.flip_points() geometry.texcoords.append(pc) texcoord_index += 1 return geometry