示例#1
0
def get_node_transforms(nodes):
    node_transforms = [None]*len(nodes)

    # create a collection of absolute translations and rotations
    # to move and rotate each nodes collision model into place.
    for node_i in range(len(nodes)):
        node = nodes[node_i]
        trans = node.translation
        rot = node.rotation
        x, y, z = trans.x, trans.y, trans.z
        this_rot = quaternion_to_matrix(rot.i, rot.j, rot.k, rot.w)

        if node.parent_node >= 0:
            parent = node_transforms[node.parent_node]
            trans = Matrix((x, y, z))

            parent_rot = parent[4]
            this_rot = parent_rot * this_rot

            trans = parent_rot * trans
            x = trans[0][0] + parent[0]
            y = trans[1][0] + parent[1]
            z = trans[2][0] + parent[2]
        else:
            parent_rot = quaternion_to_matrix(0, 0, 0, 1)

        node_transforms[node_i] = [x, y, z, parent_rot, this_rot]

    return node_transforms
示例#2
0
    def calc_internal_data(self):
        '''
        For each node, this method recalculates the rotation matrix
        from the quaternion, and the translation to the root bone.
        '''
        HekTag.calc_internal_data(self)

        nodes = self.data.tagdata.nodes.STEPTREE
        for node in nodes:
            rotation = quaternion_to_matrix(*node.rotation)
            trans = Matrix([node.translation]) * -1
            parent = None

            # add the parents translation to this ones
            if node.parent_node > -1:
                trans += Matrix([nodes[node.parent_node].translation_to_root])

            # rotate the trans_to_root by this node's rotation
            trans *= rotation

            # combine this nodes rotation with its parents rotation
            if parent is not None:
                this_trans = node.translation
                node.distance_from_parent = sqrt(this_trans.x**2 +
                                                 this_trans.y**2 +
                                                 this_trans.z**2)

                parent_rot = Matrix(
                    [parent.rot_jj_kk, parent.rot_kk_ii, parent.rot_ii_jj])
                rotation *= parent_rot

            # apply the changes to the node
            node.translation_to_root[:] = trans[0][:]
            node.rot_jj_kk[:] = rotation[0]
            node.rot_kk_ii[:] = rotation[1]
            node.rot_ii_jj[:] = rotation[2]
def extract_physics(tagdata, tag_path="", **kw):
    do_write_jms = kw.get('write_jms', True)
    filepath = ""
    if do_write_jms:
        filepath = os.path.join(kw['out_dir'], os.path.dirname(tag_path),
                                "physics", "physics.jms")
        if not kw.get('overwrite', True) and os.path.isfile(filepath):
            return

    jms_model = JmsModel()
    child_node_ct = 1
    for mp in tagdata.mass_points.STEPTREE:
        child_node_ct = max(child_node_ct, mp.model_node + 1)
        fi, fj, fk = mp.forward
        ui, uj, uk = mp.up
        si, sj, sk = uj * fk - fj * uk, uk * fi - fk * ui, ui * fj - fi * uj

        matrix = Matrix(((fi, fj, fk), (si, sj, sk), (ui, uj, uk)))
        i, j, k, w = matrix_to_quaternion(matrix)
        # no idea why I have to invert these
        w = -w
        if w < 0:
            i, j, k, w = -i, -j, -k, -w

        jms_model.markers.append(
            JmsMarker(
                mp.name,
                "physics",
                -1,
                mp.model_node,
                i,
                j,
                k,
                w,
                mp.position.x * 100,
                mp.position.y * 100,
                mp.position.z * 100,
                mp.radius * 100,
            ))

    jms_model.nodes = generate_fake_nodes(child_node_ct)

    if do_write_jms:
        write_jms(filepath, jms_model)
    else:
        return jms_model
示例#4
0
def make_raw_verts_block(node_bsp, node_transforms, node_i):
    raw_verts = raw_block_def.build()

    # create the uncompressed vertices bytearray that
    # all the parts will reuse. This is wasteful, but
    # i dont care to convert the vertex indices, so w/e
    uncomp_verts = bytearray(68*len(node_bsp.vertices.STEPTREE))
    raw_verts.data = uncomp_verts

    transform = node_transforms[node_i]
    dx, dy, dz = transform[0], transform[1], transform[2]
    rotation = transform[4]
    pos = 0
    for vert in node_bsp.vertices.STEPTREE:
        # rotate the vertices to match the nodes orientation
        trans = rotation * Matrix(vert[:3])

        # also translate the vertices to match the nodes position
        pack_into('>14f2h2f', uncomp_verts, pos,
                  trans[0][0]+dx, trans[1][0]+dy, trans[2][0]+dz,
                  1,0,0,0,1,0,0,0,1,0,0,0,0,1,0)
        pos += 68

    return raw_verts
def compile_physics(phys_tag, jms_model_markers, updating=True):
    tagdata = phys_tag.data.tagdata
    mass_points = tagdata.mass_points.STEPTREE

    if not updating:
        # making fresh physics tag. use default values
        tagdata.radius = -1.0
        tagdata.moment_scale = 0.3
        tagdata.mass = 1.0
        tagdata.density = 1.0
        tagdata.gravity_scale = 1.0
        tagdata.ground_friction = 0.2
        tagdata.ground_depth = 0.2
        tagdata.ground_damp_fraction = 0.05
        tagdata.ground_normal_k1 = 0.7071068
        tagdata.ground_normal_k0 = 0.5
        tagdata.water_friction = 0.05
        tagdata.water_depth = 0.25
        tagdata.water_density = 1.0
        tagdata.air_friction = 0.001

    existing_mp_names = {}
    for i in range(len(mass_points)):
        existing_mp_names[mass_points[i].name.lower()] = i

    mass_points_to_update = {}
    for marker in jms_model_markers:
        name = marker.name.lower()
        if name in existing_mp_names:
            mass_points_to_update[name] = mass_points[existing_mp_names[name]]

    del mass_points[:]

    # update the mass points and/or make new ones
    for marker in jms_model_markers:
        rotation = quaternion_to_matrix(marker.rot_i, marker.rot_j,
                                        marker.rot_k, marker.rot_w)

        name = marker.name
        if name in existing_mp_names:
            mass_points.append(mass_points_to_update[name])
        else:
            mass_points.append()

        mp = mass_points[-1]
        if name not in existing_mp_names:
            # set default values
            mp.relative_mass = 1.0
            mp.relative_density = 1.0
            mp.friction_parallel_scale = 1.0
            mp.friction_perpendicular_scale = 1.0

        forward = rotation * Matrix(((1, ), (0, ), (0, )))
        up = rotation * Matrix(((0, ), (0, ), (1, )))
        mp.up[:] = up[0][0], up[1][0], up[2][0]
        mp.forward[:] = forward[0][0], forward[1][0], forward[2][0]
        mp.position[:] = marker.pos_x / 100, marker.pos_y / 100, marker.pos_z / 100
        mp.name = name
        mp.radius = marker.radius / 100
        mp.model_node = marker.parent

    phys_tag.calc_internal_data()
示例#6
0
文件: phys.py 项目: Sigmmma/reclaimer
    def calc_intertia_matrices(self):
        data = self.data.tagdata
        scale = data.moment_scale
        matrices = data.inertia_matrices.STEPTREE
        com = data.center_of_mass
        mass_points = data.mass_points.STEPTREE

        # make sure the matrix array is only 2 long
        matrices.extend(2 - len(matrices))
        del matrices[2:]

        reg = matrices.regular
        inv = matrices.inverse

        reg_yy_zz, reg_zz_xx, reg_xx_yy = reg.yy_zz, reg.zz_xx, reg.xx_yy
        xx = yy = zz = float('1e-30')  # prevent division by 0
        neg_zx = neg_xy = neg_yz = 0

        # calculate the moments for each mass point and add them up
        for mp in mass_points:
            pos = mp.position

            dist_xx = (com[1] - pos[1])**2 + (com[2] - pos[2])**2
            dist_yy = (com[0] - pos[0])**2 + (com[2] - pos[2])**2
            dist_zz = (com[0] - pos[0])**2 + (com[1] - pos[1])**2

            dist_zx = (com[0] - pos[0])*(com[2] - pos[2])
            dist_xy = (com[0] - pos[0])*(com[1] - pos[1])
            dist_yz = (com[1] - pos[1])*(com[2] - pos[2])

            if mp.radius > 0:
                radius_term = 4*pow(10, (2*log(mp.radius, 10) - 1))
            else:
                radius_term = 0

            xx += (dist_xx + radius_term) * mp.mass
            yy += (dist_yy + radius_term) * mp.mass
            zz += (dist_zz + radius_term) * mp.mass
            neg_zx -= dist_zx * mp.mass
            neg_xy -= dist_xy * mp.mass
            neg_yz -= dist_yz * mp.mass

        xx, yy, zz = xx*scale, yy*scale, zz*scale
        neg_zx, neg_xy, neg_yz = neg_zx*scale, neg_xy*scale, neg_yz*scale

        # place the calculated values into the matrix
        reg_yy_zz[:] = xx, neg_xy, neg_zx
        reg_zz_xx[:] = neg_xy, yy, neg_yz
        reg_xx_yy[:] = neg_zx, neg_yz, zz

        # calculate the inverse inertia matrix
        regular = Matrix((reg_yy_zz, reg_zz_xx, reg_xx_yy))
        try:
            inverse = regular.inverse
        except ZeroDivisionError:
            inverse = Matrix((1, 0, 0), (0, 1, 0), (0, 0, 1))
            print("Could not calculate inertia matrix inverse.")

        # place the inverse matrix into the tag
        inv.yy_zz[:] = inverse[0][:]
        inv.zz_xx[:] = inverse[1][:]
        inv.xx_yy[:] = inverse[2][:]

        # copy the xx, yy, and zz moments form the matrix into the tag body
        data.xx_moment = reg_yy_zz[0]
        data.yy_moment = reg_zz_xx[1]
        data.zz_moment = reg_xx_yy[2]