def branchentry(self, branch): if not isinstance(branch, NifFormat.bhkConvexVerticesShape): # keep recursing return True else: self.toaster.msg("checking vertices and planes") for v4 in branch.vertices: v = NifFormat.Vector3() v.x = v4.x v.y = v4.y v.z = v4.z num_intersect = 0 for n4 in branch.normals: n = NifFormat.Vector3() n.x = n4.x n.y = n4.y n.z = n4.z d = n4.w if abs(v * n + d) < 0.01: num_intersect += 1 if num_intersect == 0: self.toaster.logger.error( "vertex %s does not intersect with any plane" % v) elif num_intersect == 1: self.toaster.logger.warn( "vertex %s only intersects with one plane" % v) elif num_intersect == 2: self.toaster.logger.warn( "vertex %s only intersects with two planes" % v) # stop recursing return False
def import_egm_morphs(self, egmdata, b_obj, v_map, n_verts): """Import all EGM morphs as shape keys for blender object.""" # XXX if there is an egm, the assumption is that there is only one # XXX mesh in the nif b_mesh = b_obj.data sym_morphs = [list(morph.get_relative_vertices()) for morph in egmdata.sym_morphs] asym_morphs = [list(morph.get_relative_vertices()) for morph in egmdata.asym_morphs] # insert base key at frame 1, using absolute keys sk_basis = b_obj.shape_key_add("Basis") b_mesh.shape_keys.use_relative = False morphs = ([(morph, "EGM SYM %i" % i) for i, morph in enumerate(sym_morphs)] + [(morph, "EGM ASYM %i" % i) for i, morph in enumerate(asym_morphs)]) for morphverts, keyname in morphs: #convert tuples into vector here so we can simply add in morph_mesh() morphvert_out = [] for u in morphverts: v = NifFormat.Vector3() v.x, v.y, v.z = u morphvert_out.append(v) self.morph_mesh(b_mesh, n_verts, morphvert_out, v_map) shape_key = b_obj.shape_key_add(keyname, from_mix=False)
def build_nif_matrix(cls): n_mat = NifFormat.Matrix44() translation = (2.0, 3.0, 4.0) scale = 2.0 n_rhs_rot_x = (1.0, 0.0, 0.0, 0.0, 0.866, 0.5, 0.0, -0.5, 0.866) n_rhs_rot_y = (0.5, 0.0, -0.866, 0.0, 1.0, 0.0, 0.866, 0.0, 0.5) n_rhs_rot_z = (0, 1, 0, -1, 0, 0, 0, 0, 1) n_rhs_rot_x = cls.create_matrix(n_rhs_rot_x) n_rhs_rot_y = cls.create_matrix(n_rhs_rot_y) n_rhs_rot_z = cls.create_matrix(n_rhs_rot_z) n_mat33 = n_rhs_rot_z * n_rhs_rot_y * n_rhs_rot_x n_vec3 = NifFormat.Vector3() n_vec3.x = translation[0] n_vec3.y = translation[1] n_vec3.z = translation[2] n_mat.set_scale_rotation_translation(scale, n_mat33, n_vec3) return n_mat
def build_nif_matrix(cls): n_mat = NifFormat.Matrix44() translation = (2.0, 3.0, 4.0) scale = 2.0 rhsrotx = (1.0, 0.0, 0.0, 0.0, 0.866, 0.5, 0.0, -0.5, 0.866) rhsroty = (0.5, 0.0, -0.866, 0.0, 1.0, 0.0, 0.866, 0.0, 0.5) rhsrotz = (0, 1, 0, -1, 0, 0, 0, 0, 1) rhsrotx = cls.create_matrix(rhsrotx) rhsroty = cls.create_matrix(rhsroty) rhsrotz = cls.create_matrix(rhsrotz) n_mat33 = rhsrotz * rhsroty * rhsrotx n_vec3 = NifFormat.Vector3() n_vec3.x = translation[0] n_vec3.y = translation[1] n_vec3.z = translation[2] n_mat.set_scale_rotation_translation(scale, n_mat33, n_vec3) return n_mat
def get_skin_deformation_from_partition(n_geom): """ Workaround because pyffi does not support this skinning method """ # todo [pyffi] integrate this into pyffi!!! # so that NiGeometry.get_skin_deformation() deals with this as intended # mostly a copy from pyffi... skin_inst = n_geom.skin_instance skin_data = skin_inst.data skin_partition = skin_inst.skin_partition skel_root = skin_inst.skeleton_root vertices = [ NifFormat.Vector3() for _ in range(n_geom.data.num_vertices) ] # ignore normals for now, not needed for import sum_weights = [0.0 for _ in range(n_geom.data.num_vertices)] skin_offset = skin_data.get_transform() # store one transform per bone bone_transforms = [] for i, bone_block in enumerate(skin_inst.bones): bone_data = skin_data.bone_list[i] bone_offset = bone_data.get_transform() bone_matrix = bone_block.get_transform(skel_root) transform = bone_offset * bone_matrix * skin_offset bone_transforms.append(transform) # now the actual unique bit for block in skin_partition.skin_partition_blocks: # create all vgroups for this block's bones block_bone_transforms = [bone_transforms[i] for i in block.bones] # go over each vert in this block for vert_index, vertex_weights, bone_indices in zip( block.vertex_map, block.vertex_weights, block.bone_indices): # skip verts that were already processed in an earlier block if sum_weights[vert_index] != 0: continue # go over all 4 weight / bone pairs and transform this vert for weight, b_i in zip(vertex_weights, bone_indices): if weight > 0: transform = block_bone_transforms[b_i] vertices[vert_index] += weight * ( n_geom.data.vertices[vert_index] * transform) sum_weights[vert_index] += weight for i, s in enumerate(sum_weights): if abs(s - 1.0) > 0.01: print( f"Vertex {i:d} has weights not summing to one: {sum_weights['i']:d}" ) return vertices
def branchentry(self, branch): if not isinstance(branch, NifFormat.NiGeometryData): # keep recursing return True else: report = {} self.toaster.msg("getting bounding sphere") center = NifFormat.Vector3() center.x = branch.center.x center.y = branch.center.y center.z = branch.center.z radius = branch.radius self.toaster.msg("checking that all vertices are inside") maxr = 0.0 maxv = None for vert in branch.vertices: dist = vert - center if dist * dist > maxr: maxr = dist * dist maxv = vert maxr = maxr ** 0.5 if maxr > 1.01 * radius + 0.01: #raise ValueError( self.toaster.logger.warn( "not all vertices inside bounding sphere (vertex %s, error %s)" % (maxv, abs(maxr - radius))) report["vertex_outside"] = maxv.as_tuple() self.toaster.msg("recalculating bounding sphere") branch.update_center_radius() self.toaster.msg("comparing old and new spheres") if center != branch.center: self.toaster.logger.warn( "center does not match; original %s, calculated %s" % (center, branch.center)) report["center"] = { "orig": center.as_tuple(), "calc": branch.center.as_tuple(), } if abs(radius - branch.radius) > NifFormat.EPSILON: self.toaster.logger.warn( "radius does not match; original %s, calculated %s" % (radius, branch.radius)) report["radius"] = { "orig": radius, "calc": branch.radius, } if report: self.append_report(report) # stop recursing return False
def branchentry(self, branch): if not isinstance(branch, NifFormat.bhkMoppBvTreeShape): # keep recursing return True else: mopp = [b for b in branch.mopp_data] o = NifFormat.Vector3() o.x = branch.origin.x o.y = branch.origin.y o.z = branch.origin.z scale = branch.scale self.toaster.msg("recalculating mopp origin and scale") branch.update_origin_scale() if branch.origin != o: self.toaster.logger.warn("origin mismatch") self.toaster.logger.warn("(was %s and is now %s)" % (o, branch.origin)) if abs(branch.scale - scale) > 0.5: self.toaster.logger.warn("scale mismatch") self.toaster.logger.warn("(was %s and is now %s)" % (scale, branch.scale)) self.toaster.msg("parsing mopp") # ids = indices of bytes processed, tris = triangle indices ids, tris = branch.parse_mopp(verbose=True) error = False # check triangles counts = [tris.count(i) for i in range(branch.shape.data.num_triangles)] missing = [i for i in range(branch.shape.data.num_triangles) if counts[i] != 1] if missing: self.toaster.logger.error( "some triangles never visited, or visited more than once") self.toaster.logger.debug( "triangles index, times visited") for i in missing: self.toaster.logger.debug(i, counts[i]) error = True wrong = [i for i in tris if i > branch.shape.data.num_triangles] if wrong: self.toaster.logger.error("invalid triangle indices") self.toaster.logger.debug(wrong) error = True # check bytes counts = [ids.count(i) for i in range(branch.mopp_data_size)] missing = [i for i in range(branch.mopp_data_size) if counts[i] != 1] if missing: self.toaster.logger.error( "some bytes never visited, or visited more than once") self.toaster.logger.debug( "byte index, times visited, value") for i in missing: self.toaster.logger.debug(i, counts[i], "0x%02X" % mopp[i]) self.toaster.logger.debug([mopp[k] for k in range(i, min(branch.mopp_data_size, i + 10))]) error = True #if error: # raise ValueError("mopp parsing failed") # stop recursing return False
def DrawOffset(v, off): w = NifFormat.Vector3() w.x = v.x + off.x w.y = v.y + off.y w.z = v.z + off.z DrawLine(v, w)