def signed_tetrahedral_volume(p1, p2, p3):
    """
    Computes the signed tetrahedral volume

    Tetrahedron is formed by (p1, p2, p3, and origin)

    :param p1: (..., 3) array with positions of first point
    :param p2: (..., 3) array with positions of second point
    :param p3: (..., 3) array with positions of third point
    :return: (..., ) array with the volumes (negative if normal points towards the origin)
    """
    v321 = p3[..., 0] * p2[..., 1] * p1[..., 2]
    v231 = p2[..., 0] * p3[..., 1] * p1[..., 2]
    v312 = p3[..., 0] * p1[..., 1] * p2[..., 2]
    v132 = p1[..., 0] * p3[..., 1] * p2[..., 2]
    v213 = p2[..., 0] * p1[..., 1] * p3[..., 2]
    v123 = p1[..., 0] * p2[..., 1] * p3[..., 2]
    return (-v321 + v231 + v312 - v132 - v213 + v123) / 6.